MS08-065 : Exploitable for remote code execution?

Today, we released MS08-065 to fix an issue in MSMQ.  You’ll notice that the bulletin was rated “Important” and indicates that remote code execution is possible.  However, we would like to show you that in practice the severity of the fixed issue is limited only to information disclosure.

If the MSMQ service were installed by default on any affected Windows configuration, we would have rated this one Critical.  The “off-by-default” mitigation drops the rating one notch from Critical to Important.  We would like to help you understand the information disclosure threat by revealing some details about the vulnerability. Quick stepping through the pseudo-code representing this issue will give you a sense of whether or not this issue will be exploited in the real-world.

SomeRpcFunction (int ptr)

WCHAR *buf = ((blah *) ptr)->SomeString;
DWORD size = sizeof(WCHAR) * (wcslen(buf) + 1)
… do some sanity checking …
WCHAR *buf2 = allocatememory(size);
wcscpy(buf2, buf);

return buf2;

The attacker can pass in any address he wants for “ptr” and the function will happily try to dereference it. If the attacker does this correctly, there will be some information leakage through the string returned by the function. For code execution, the attacker has a much tougher job. It will have to be a timing attack. The attacker will need to modify memory (using a separate thread) during the window of time between the string length calculation and the wscpy(). The memory modification would have to make the length of the string bigger than it was when the length of the string was calculated several lines of code earlier. In real world scenarios, we expect that exploiting this race condition in a reliable manner would be very difficult. We can also look at it from an assembly perspective to see the window of attack, measured in assembly instructions:

6b96ac16 8b780c          mov     edi,dword ptr [eax+0Ch]

6b96ac19 897de4          mov     dword ptr [ebp-1Ch],edi

6b96ac1c 57              push    edi

“edi” is a pointer to a string

6b96ac1d ff15c0f4996b    call    dword ptr [mqqm!_imp__wcslen (6b99f4c0)]

We pass it to wsclen(). The calculated string length will be in “eax”)

6b96ac23 59              pop     ecx

6b96ac24 8d440002        lea     eax,[eax+eax+2]

Note the compiler optimization on “eax”;this instruction is the same as eax = 2*(eax+1).  “eax” now represents how many bytes we need to store the string)

6b96ac28 8945e0          mov     dword ptr [ebp-20h],eax

6b96ac2b 3d00000400      cmp     eax,40000h

6b96ac30 7615            jbe     mqqm!QMGetRemoteQueueName+0x73 (6b96ac47)

do some error checking

6b96ac32 a1dc1b9b6b      mov     eax,dword ptr [mqqm!s_FN (6b9b1bdc)]

6b96ac37 8945cc          mov     dword ptr [ebp-34h],eax

6b96ac3a 6899000000      push    99h

6b96ac3f 50              push    eax

6b96ac40 be06000ec0      mov     esi,0C00E0006h

6b96ac45 eb52            jmp     mqqm!QMGetRemoteQueueName+0xc5 (6b96ac99)

6b96ac47 50              push    eax

“eax” is how many bytes we needed (see 0x6b96ac24)

6b96ac48 e88879ffff      call    mqqm!MIDL_user_allocate (6b9625d5)

We allocate a buffer of size “eax”

6b96ac4d 8bf0            mov     esi,eax

Save the ptr in “esi”

6b96ac4f 8975dc          mov     dword ptr [ebp-24h],esi

6b96ac52 57              push    edi

“edi” is the pointer to the string we had before. If the attacker managed to change memory content at this pointer, then the length can be greater than what we calculated before…

6b96ac53 56              push    esi

“esi” is our newly allocated buffer

6b96ac54 ff15c8f4996b    call    dword ptr [mqqm!_imp__wcscpy (6b99f4c8)]

we do wscpy() on it.  If the length of string at “edi” changed, then we have a buffer overflow


– SVRD Bloggers

*Postings are provided “AS IS” with no warranties, and confers no rights.*