コース目次 / 第3章

まとめ — 保護は、何を防いでいたか

同じ入力を、デフォルトの保護付きでビルドした場合と比較し、スタックカナリアがオーバーフローを検知してプロセスを強制終了することを確認します。pwnカテゴリの要点を畳み、次のカテゴリへ送り出します。

第3章 / 全4章目安 約8分この章のゴール: 保護機構が何を防いでいるかを理解し、pwnカテゴリの要点を畳む

第1章で、-fno-stack-protector -no-pieを付けてビルドしました。これを付けなかったら、どうなるでしょうか。

デフォルトのビルドで、同じ攻撃を試す

gcc -o vuln_protected vuln.c
python3 -c "
from pwn import *
p = process('./vuln_protected')
p.recvuntil(b': ')
p.sendline(b'A'*72 + p64(0x401196))
print(p.recvall(timeout=2).decode(errors='replace'))
"
こんにちは、AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...さん
*** stack smashing detected ***: terminated

flagは出ませんでした。*** stack smashing detected ***——スタックカナリアが、リターンアドレスの直前に置いた「番人の値」が書き換えられたことを検知し、リターンする前にプロセスを強制終了しました。第1章で外した-fno-stack-protectorが、まさにこの番人を無効化していたのです。

checksecで、保護の違いを見る

python3 -c "
from pwn import *
context.log_level = 'error'
print('--- vuln(保護を無効化) ---')
print(ELF('./vuln', checksec=False).checksec())
print('--- vuln_protected(デフォルト) ---')
print(ELF('./vuln_protected', checksec=False).checksec())
"
保護 vuln(無効化) vuln_protected(デフォルト) 防ぐもの
Stack Canary なし あり リターンアドレス書き換えの検知
NX 無効(実行可能スタック) 有効 スタック上のコード実行
PIE 無効(固定アドレス) 有効 アドレスの事前計算

現代のデフォルトビルドは、すでに何重にも保護されています。今回のret2winが成立したのは、脆弱な関数(gets)を使ったことに加えて、保護を意図的に3つとも外したからです。実際の脆弱性調査では、対象のバイナリがどの保護を有効にしているかをchecksecで最初に確認する——これが実務での第一歩です。

このコースで扱わなかったこと

NXが有効だと、スタック上に置いたコード(シェルコード)は実行できません。それを回避するROPチェーン(既存のコード断片をつなぎ合わせて任意の処理を組み立てる技術)は、より高度な武器化技術であり、このコースの範囲外です。今回学んだ「リターンアドレスは書き換えられる」という基礎は、その先に進むための土台です。

次の道

好きな順で、次のカテゴリに進んでください。forensics(残されたデータを掘る)、misc(檻を破る)——どちらも ctf-intro の後に置かれています。法と倫理の一線は、この先も同じです。

お疲れさまでした。「保護されているはず」という言葉も、確かめる目を持ちました。

こうなっていればOK

この章で卒業です。

この章はまだ完了していません。