PR 本記事には広告(Amazonアソシエイト・もしもアフィリエイト・A8.net等)が含まれます。掲載情報の正確性には努めていますが、商品の詳細は必ずリンク先で最新情報をご確認ください。

【スタックBoF基礎編】ret書き換えとret2winで初Pwn成功する|CTF思考フレームワーク #59

【スタックBoF基礎編】ret書き換えとret2winで初Pwn成功する|CTF思考フレームワーク #59 アイキャッチ画像
安全に生きたい編集部

広告・PRを含みます。この記事にはアフィリエイトリンクが含まれます。掲載内容は編集方針に基づいて作成していますが、価格・在庫・キャンペーン内容はリンク先で最新情報を確認してください。

スタックBoF(バッファオーバーフロー)って、聞いたことある!🛑

Pwnの古典中の古典。スタックに置かれた配列に長すぎる文字列を書き込み、返り値(return address)を上書きする攻撃。「ret書き換え」と「ret2win」のシナリオで、最初のPwn成功体験ができます。

スタックバッファオーバーフロー(Stack BoF)は、1988年のMorris Worm以来35年以上、現役の脆弱性。C/C++の char buf[64]; gets(buf); のような無防備な実装に長文字列を入れると、return address を書き換えて任意のコード実行へつなげられます。今もIoTファームウェアで多数発見されています。

35年も続いてる古典的バグなんだ…

この記事は、CTF思考フレームワーク第59回。スタックBoFの仕組みと、ret書き換え・ret2win の典型シナリオ、GDB/pwntools を使った実践、Canary・PIE などの保護機構の影響を整理します。

📖 この記事はシリーズの一部です
CTF思考フレームワーク#59 / 全86記事 → シリーズ一覧を見る →

💥 Pwnの登竜門、Stack Buffer Overflow。スタック上の配列を超えて書き込み、戻り番地を奪う。Hello Worldの次に世界中の入門者が触る「制御フロー乗っ取り」の最古典です。

スタックBOFの肝は「バッファとリターンアドレスの距離」「カナリア有無」「NX有効か」。Canaryありなら漏洩から、NXありならROPへ。最初の一発は「ret2win」で十分です。

難易度:★★☆(中級)

ret書き換えとret2winで初Pwnを成功させます🎯

スタックBoFは「buffer長を無視して書き込む→retアドレス改ざん」がコア🎯

この記事で出てくる言葉

先に意味を押さえておくと読みやすい用語です。

  • CTF: セキュリティの練習問題を解く競技。必ず許可された環境だけで試します。
  • Pwn: バイナリの不備を突いてプログラムの制御を奪うCTF分野です。
  • ROP: 既存コードの断片をつなぎ、攻撃用の処理を作る高度な手法です。
  • スタック: 関数呼び出しや一時データを積み上げて管理するメモリ領域です。

👀 観察フェーズ:まず何を見る?

checksecCanaryなしNX有効PIEなしのバイナリは絶好の練習台🔍

バイナリの保護を確認、続いてstringsobjdumpで目的関数(win/secret/admin等)を探します。脆弱関数(gets/strcpy/scanf)の存在も要確認。

  • checksec:Canary / NX / PIE / RELRO
  • 脆弱関数:gets, strcpy, scanf %s
  • 目的関数(win, secret, get_flag等)の存在
  • バッファサイズと return 位置の距離
  • cyclic パターンでオフセット推定
  • libc使用の有無(ret2libcの伏線)

gets / read / strcpyの使用箇所をGhidraで確認。バッファサイズと読込長の差がBoFサイズです👀

cyclicでret到達オフセットを測るのが最初の儀式だね💡

🤔 仮説フェーズ:攻撃者は何を考える?

スタックBoF基本攻略の4ステップ。

🕶️ 攻撃者は「Canaryなし+目的関数あり=ret2win一直線」「Canaryあり=漏洩経路(FormatStringやprintf)が必要」「NXあり=ROP」「PIEあり=アドレス漏洩が前提」と素早く分類します。

📏 仮説①:オフセット特定

cyclicパターン→クラッシュ→RSP/RIP値からcyclic_findで逆引き。これでretまでの距離が判明。

🎯 仮説②:ret2win

勝利関数win()のアドレスにretでジャンプ。最も基本的な制御奪取。

🐚 仮説③:ret2libc

libcのsystem("/bin/sh")を呼び出す古典。アーキにより引数渡しが違う(x64ならrdi)。

⚙️ 仮説④:シェルコード実行

NX無効ならスタックにシェルコードを置いてretでジャンプ。NXがあると不可。

スタックBoFは「Pwn入門の通過儀礼」。これができたら世界が広がる💡

🔬 検証フェーズ:どうやって確かめる?

pwntoolsでp64()を使ってスタック構築→ローカル先デバッグ→リモート展開の手順🧪

pwntoolsのcyclicでオフセットを取り、retポイントを確実に書き換えられるか確認。漏洩→アドレス計算→2回目の入力で本攻撃、というパターンも頻出。

# pwntoolsでcyclicテスト
from pwn import *
p = process('./chall')
p.sendline(cyclic(200))
p.wait()
core = p.corefile
offset = cyclic_find(core.read(core.rsp, 8))
print(offset)  # 例:72

スタックアラインメントでmovapsクラッシュした時はretガジェット1個追加するんだね💡

⚔️ 攻撃フェーズ:実際の手口

基本BoF攻撃3パターン。

基本exploit:①パディングでバッファ埋める、②カナリア(あれば)をリーク値で再現、③saved rbpを適当に、④戻り番地に win 関数のアドレス。x64ではアラインに注意(要 ret gadget 1個)。

# ret2win(最シンプル)
from pwn import *
elf = ELF('./chall')
p = process('./chall')
win = elf.symbols['win']
payload = b'A' * 72 + p64(0xdeadbeef) + p64(win)
p.sendline(payload)
p.interactive()

# x64のmovaps対策で ret gadget を1個挟む
payload = b'A' * 72 + p64(0) + p64(ret_gadget) + p64(win)

x64でsystem呼び出しが落ちる原因の多くは movaps アライメント。retガジェット1個挟むだけで解決します🪄

① ret2win

バイナリ内の勝利関数を呼ぶ。PIEなしなら静的アドレスでそのまま指定可能。

② ret2libc

pop rdi; retガジェットで引数を準備して system()呼び出し。x64の最頻出パターン。

③ Stage型 (read→exec)

一度のBoFでreadを呼び出して大きなペイロードを書き込み、その後実行。長いROPを段階的に。

🛡️ 防御フェーズ:どう守る?

BoF対策の鉄則3つ。

スタックBOF防御は層状。Canary・NX・PIE・FORTIFY_SOURCE・shadow stack。コンパイラの推奨設定を全部ONにすれば、純粋な古典BOFはほぼ通らなくなります。

  • -fstack-protector-strong または -fstack-protector-all
  • -D_FORTIFY_SOURCE=2
  • NX (-z noexecstack)
  • -fpie -pie(PIE有効)
  • -fcf-protection=full(CET)
  • gets/strcpy/scanf %s の使用禁止(lint・SAST)
🛡️ Stack Canary

リターンアドレスの直前に乱数ガードを置き、関数戻り時に検証。BoFを即検知。

🚫 NX/DEP

スタックを実行不可にしてシェルコードを死語化。

🎲 ASLR + PIE

アドレスをランダム化してret2libc難易度を激増。

これら3つの標準保護を全部有効にすればスタックBoFは大半が死ぬ💪

🧪 pwn検証用のLinuxラボ

Pwnやエクスプロイトの練習は、必ず自分の検証環境で。💻 ConoHa VPSならLinuxをワンクリックで立てて、gdb-pedaやpwntoolsを仕込んでそのままトレーニングできます。

PR / 広告

ConoHa VPS

※ 上記は他社サービスへのリンクです。購入は各自でご判断ください。

⚠️ よくある落とし穴

  1. cyclicでオフセットを取らず手計算してズレる
  2. x64でmovaps落ちを忘れret gadgetを挟まない
  3. PIE有効を無視して絶対アドレスを使う
  4. Canary検知を「Canary値ランダムだから無理」で諦め、漏洩経路を探さない
  5. sendとsendlineの末尾改行を間違える
  6. process()とremote()の挙動差を意識しない

🧰 ツール早見表

ツール用途備考
pwntoolsexploit骨格cyclic/ELF/process
gdb + pwndbgデバッグcore dump解析も
checksec保護機構確認初手の儀式
ROPgadgetgadget抽出汎用
one_gadgetlibc内のexecve(“/bin/sh”)leak後の決め技

🎓 本気で学びたい人へ

ローレベルやOSレベルの許可を、仕事として深く学びたい方へ。🎓 ササエルはインフラとセキュリティの両方を学べるスクールです。

PR / 広告

ササエル

📚 もっと深く学びたい人へ

実際に手を動かして攻撃手法を体で覚えたいなら『7日間でハッキングをはじめる本 TryHackMe』がおすすめ📚

📚 次に読みたい

✍️ 学んだことを発信する

検証ノートをブログで公開したい方は、高速で安価なConoHa WINGが使いやすいです。

PR / 広告

ConoHa WING

⚖️ 大事なお約束

必ず守ってね

この記事の手法は、必ず自分の環境か、許可されたCTF・脆弱性報奨金プログラム(HackerOne、Bugcrowd等)で試してください。他人のサービスに無断で攻撃を仕掛けるのは不正アクセス禁止法違反、立派な犯罪です。学んだ知識は守る側で活かしましょう🤝

この記事は合法な学習・防御目的での解説です。許可のないシステムへの攻撃は犯罪になります(不正アクセス禁止法ほか)。検証は必ず自分が管理する環境・CTF・公式ハンズオンで行ってください🙏

記事URLをコピーしました