Important
Solved with Google Antigravity この問題は Google の AI コーディングアシスタント Antigravity を活用して解決されました。
Daily AlpacaHack "func-array" writeup and solution.
- 問題名: func-array
- ジャンル: Pwn (Binary Exploitation)
- 難易度: Easy
- リンク: Daily AlpacaHack
- pwntools: Pythonベース of CTF向けフレームワーク。
- checksec: バイナリのセキュリティ保護機能を調べるツール。
- objdump: バイナリを逆アセンブルして構造を確認するツール。
プログラム内では、関数ポインタの配列 alpaca_functions がスタック上に配置されています。ユーザーが入力したインデックス choice を使ってこの配列から関数を呼び出しますが、インデックスが 0〜2 の範囲内であるかどうかのチェックがありません。
alpaca_functions[choice]() は、スタック上の特定のアドレスにある値を読み取り、それをアドレスとしてジャンプ(呼び出し)します。スタック上には、関数ポインタだけでなく、戻りアドレスやベースポインタなどの重要な情報も存在します。
graph TD
subgraph Stack
direction BT
choice["choice (rbp-0x24)"]
func0["alpaca_functions[0] (rbp-0x20)"]
func1["alpaca_functions[1] (rbp-0x18)"]
func2["alpaca_functions[2] (rbp-0x10)"]
canary["Stack Canary (rbp-0x08)"]
rbp["Saved RBP (rbp)"]
ret["Return Address (rbp+0x08)"]
end
choice_input -- "5" --> index
index -- "Index 5 points to Return Address" --> ret
ret -- "Points to main code calling win()" --> win_call
checksecでバイナリを確認したところ、PIE (Position Independent Executable) が無効であることが分かりました。これにより、関数のアドレスが固定されます。objdumpでvuln関数のスタック構成を確認。alpaca_functions[0]はrbp - 0x20にあり、vuln関数の戻りアドレスはrbp + 0x08にあります。- インデックスを計算すると、
(0x08 - (-0x20)) / 8 = 5となります。インデックス5を指定すると、alpaca_functions[5]はスタック上の戻りアドレスを関数ポインタとして読み込みます。 main関数では、vulnの呼び出し直後にwin関数の呼び出しがスケジュールされています。そのため、戻りアドレスはwinを呼び出す直前のコードを指しており、これを利用してwinを実行させることができます。
- Pwn (Pwnable): プログラムの脆弱性を突き、意図しない動作(シェルの起動など)をさせる攻撃。
- 関数ポインタ (Function Pointer): 関数のアドレスを保持する変数。この変数を「呼び出す」ことでその関数を実行できる。
- スタック (Stack): 関数のローカル変数や戻りアドレスを一時的に保存するメモリ領域。
- 戻りアドレス (Return Address): 関数が終了した後に戻るべき、呼び出し元の次の命令のアドレス。
- PIE (Position Independent Executable): 実行のたびにアドレスをランダム化する機能。今回は無効だったため、アドレスが固定でした。