exploiting-memory-corruption について
許可されたバイナリセキュリティ調査、CTF、ラボ向けのネイティブメモリ破壊攻略スキルです。バグの種類を利用プリミティブや手法に結び付け、緩和策とアロケーターの挙動に応じて方法を選びます。
主な機能
- 01バイナリの緩和策を列挙
- 02バグの種類を利用プリミティブに対応付け
- 03ROP とコード再利用チェーンの構築
- 04glibc のヒープ技法の適用
- 05pwntools による段階的なエクスプロイト開発
- 06許可されたラボ範囲でのテスト
活用シーン
- 01ELF または PE バイナリのクラッシュ評価
- 02CTF pwn チャレンジのエクスプロイト開発
- 03有効な緩和策に対する ROP のテスト
- 04glibc 上のヒープ破壊の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trilwu/ secskills --skill exploiting-memory-corruptionインストール後、Claude Code で/exploiting-memory-corruptionを入力して読み込まれたか確認します。
詳細
メモリ破壊の悪用
リバースエンジニアリングによって、バイナリにバグがあることがわかります。エクスプロイトは、そのバグを制御可能なプリミティブに変え、さらにコード実行へとつなげる、別個の技術です。対象に実際に組み込まれている緩和策に対処しながら進めます。この作業は、バグからプリミティブへ、プリミティブから情報漏えいへ、情報漏えいから制御へと変換を重ねるものであり、それぞれの段階では型どおりに進めるのではなく、バイナリの保護機能で可能なことに応じて手法を選びます。
使用する場面
- ELF/PE にクラッシュまたは既知のバグクラスがあり、エクスプロイト可能か評価して、動作するエクスプロイトを作成する必要がある場合
- ROP/JOP チェーン、ret2libc、またはヒープ配置を調整する手順を構築する場合
- ラボまたは CTF のターゲットで、特定の緩和策(ASLR、NX/DEP、カナリア、PIE、RELRO)を回避する場合
- 許可されたバイナリ悪用タスク、または CTF の pwn チャレンジに取り組む場合
使用しない場面
- バイナリの動作を解明する場合 — 逆アセンブル、逆コンパイル、アルゴリズムの復元は
analyzing-binariesの対象です。バグをまだ理解できていない場合は、まずそちらを使ってください。 - コードを確認できるようになる前に、保護されたバイナリをアンパックまたは仮想化解除する場合 —
unpacking-protected-binariesを使ってください。 - Web、デシリアライズ、またはインジェクションのバグ — これらはそれぞれ独自のスキル(
testing-web-applications、exploiting-deserialization)の対象です。このスキルが扱うのはネイティブのメモリ破壊のみです。 - カーネル/ドライバーのエクスプロイト — プリミティブが大きく異なるため(libc がなく、SMEP/SMAP/KASLR、システムコールのコンテキストが関わる)、ここでは対象外です。ユーザーランドでの手法は参考になります。
- バグを見つけるためのファジング — これは発見段階の作業です。このスキルはクラッシュが発生した時点から始まります。
まず緩和策を列挙する
構築できるエクスプロイトは、有効になっている保護機能によって決まります。計画を立てる前に確認してください(checksec、または pwntools の checksec/ELF)。
| 緩和策 | 防ぐもの | 通常の対処法 |
|---|---|---|
| NX / DEP | スタック/ヒープ上のシェルコードの実行 | ROP / ret2libc — 既存の実行可能コードを再利用する |
| ASLR | アドレスのハードコード | 情報漏えいを利用してベースアドレスを特定し、オフセットを計算する |
| スタックカナリア | 単純なスタック上のリターンアドレスの上書き | カナリアを漏えいさせる、別のものを上書きする、またはフォークするサーバーでブルートフォースを行う |
| PIE | バイナリ自身のアドレスのハードコード | バイナリのアドレスを漏えいさせる。それまでは相対的/部分的な上書きのみ |
| Partial RELRO | ほとんど何も防がない — GOT は引き続き書き込み可能 | GOT 上書きが選択肢になる |
| Full RELRO | GOT 上書き | __malloc_hook/__free_hook(2.34 より前)を狙うか、ROP のみの経路を使う |
作業の順序を決める重要な問いは 2 つです。情報漏えいを利用できるか(ASLR/PIE)、そして どこに書き込めるか(RELRO)。それ以外は、この 2 つを踏まえて決まります。
バグクラスからプリミティブへ
手法を選ぶ前に、手元にあるものを特定してください。
- スタックバッファーオーバーフロー → 保存されたリターンアドレスを直接制御できます。カナリアが許せば、ROP チェーンへの最も明快な経路です。
- ヒープオーバーフロー/オフバイワン → 隣接するチャンクのメタデータや、隣接オブジェクトのポインターを破壊します。利用できるプリミティブは、調整可能なヒープ配置によって異なります。
- 解放後使用(Use-after-free) → 解放済みのスロットに攻撃者のデータを再割り当てし、古いポインターが制御下のデータを参照するようにします。偽の vtable/オブジェクトを使う古典的な手法です。
- 型の取り違え → ある型のフィールドを別の型として扱い、多くの場合、読み取り/書き込み、または直接制御可能な呼び出しを実現します。
- フォーマット文字列 →
%nで狙った位置に書き込み、%p/%sで情報を漏えいさせます。1 つのバグで情報漏えいと書き込みの両方が可能なこともよくあります。 - 整数オーバーフロー/範囲外アクセス → 通常は上記のいずれかを引き起こす手段です(サイズの計算結果が短くなり、ヒープオーバーフローが起きるなど)。
この段階の目標は、次の 3 つのプリミティブのいずれかを得ることです。制御フローの乗っ取り、任意読み取り、または 任意書き込み。まずプリミティブを獲得し、その後で構築に進みます。
ROP とコード再利用
NX が有効な状態では、プログラム自身のバイト列を、選んだ順序で実行します。
- ガジェットを探すには ROPgadget または ropper を使います。呼び出しの準備に使う、
pop rdi; retのようなレジスター制御を探します。 - ret2libc — libc のベースアドレスが分かったら、
system("/bin/sh")に戻ります。libc を利用でき、アドレスが漏えいしている場合に最も直接的なチェーンです。 - ret2csu — 適切なガジェットがない場合、2.34 より前のバイナリーでは
__libc_csu_initの末尾を使ってrdx/rsiを制御します。 - SROP(sigreturn-oriented)— ガジェットが少なくても、偽のシグナルフレームを用意して
sigreturnに到達できる場合に使います。 - ret2dlresolve — 動的リンカーに関数を解決させて呼び出します。アドレスの漏えいがなく、RELRO が部分的な場合に有効です。
- one_gadget — シェルを実行する単一の libc アドレスを見つけます。条件が満たされれば、最終段階をまとめられます。
オフセットを正しくするため、漏えいした libc に libc-database を使って一致するビルドを特定します。別の libc を前提に組んだチェーンは、何も表示せずに失敗します。
ヒープエクスプロイト(glibc ptmalloc)
ヒープ攻撃はメモリー配置を扱う作業です。破壊が有用な対象に届くよう、アロケーションを配置します。アロケーターのチェックは段階的に強化されてきたため、手法は glibc のバージョンによって異なります。
- tcache poisoning(2.26 以降)— 現代的な手法の中で最も効果の高いプリミティブです。解放済みの tcache チャンクの
nextを破壊すると、次のmallocで任意のポインターを返させられます。2.32 以降ではポインターが safe-linking によって難読化されるため(格納先アドレスを右に 12 ビットシフトした値との XOR)、偽造にはヒープアドレスの漏えいが必要です。また、2.34 ではチェーンの終端に使われていた__free_hook/__malloc_hookのターゲットが削除されています。 - fastbin dup — fastbin に二重解放して同じチャンクを 2 回返させます。現代的な glibc では tcache が先に使われる動作に注意してください。
- unsorted-bin leak — unsorted bin 内の解放済みチャンクには
main_arenaポインターが含まれます。これを読み取ると libc アドレスが漏えいし、ASLR を回避できます。 - House of * 系の手法(Force、Orange、Einherjar など)— それぞれ特定のアロケーター不変条件を悪用し、単純なプリミティブが使えない場合に任意の書き込みを実現します。レイアウト上必要な場合にのみ使います。
これらの作業には pwndbg または GEF を使います。heap、bins、tcache コマンドで状態を確認し、頭の中のモデルではなく実際の状態に合わせてヒープを整えます。
繰り返しの進め方
pwntools でエクスプロイトを少しずつ組み立て、次の要素を追加する前に、それぞれの段階を検証します。クラッシュを発生させ、命令ポインターを制御できていることを証明し、アドレスの漏えいを実現して計算したベースアドレスを確認し、次に書き込み、最後にシェルを取得します。ある段階で問題が起きたら、チェーン全体を眺めるのではなく、まさにその時点で gdb.attach() を使ってアタッチします。ローカルでは動作するのにリモートで失敗する場合、ほとんどの場合は環境の差が原因です。たとえば libc のバージョン、スタックのアライメント(movaps のための余分な ret)、環境に依存するアドレス漏えいなどです。
適用範囲と許可
エクスプロイトの開発対象は、自分が所有するバイナリー、CTF のターゲット、ラボ VM、または明示的にテストを依頼されたソフトウェアです。ここでは lab_only のエグレスモードがデフォルトです。動作するエクスプロイトを本番環境に対して実行することは、研究ではなく侵入にあたるためです。特に注意すべき点が 2 つあります。
- サードパーティーソフトウェアの 0-day は、公開ではなく協調的な情報開示の対象です。概念実証を作成し、ベンダーの窓口を通じて報告してください。修正される前に、武器化したエクスプロイトを公開してはいけません。
- 「動作するか確かめる」ために、自分が管理していないシステムに対してエクスプロイトを試してはいけません。メモリー破壊のエクスプロイトは、成功しない場合にサービスをクラッシュさせます。これは他者のシステムに対する可用性への影響です。
却下すべき合理化
- 「EIP/RIP でクラッシュするから、悪用可能だ。」 命令ポインターの制御は出発点であり、ゴールではありません。最新の緩和策があるため、リークなしではクラッシュが行き詰まりになることがあります。悪用可能だと主張する前に、プリミティブに到達できるかを評価してください。
- 「ローカルで動くから、そのまま出荷しよう。」 リモート環境の libc、ASLR のエントロピー、スタックのアラインメントは異なります。対象の libc に合わせ、動作すると報告する前に実際の環境でテストしてください。
- 「スタックにシェルコードをばらまけばいい。」 NX は 10 年以上前からデフォルトで有効です。スタックにシェルコードを書き込んでジャンプする場合は、時間を費やす前に NX が実際に無効になっていることを確認してください。
- 「最後の手順は one_gadget に任せればいい。」 one_gadget の制約(特定のレジスターが null であること、特定のスタック状態など)は満たされないことがよくあります。確認したうえで、代替手段として ret2libc を用意してください。
- 「解説記事のヒープ手法ならそのまま動く。」 アロケーターのチェックはバージョン固有です。tcache キー、カウントチェック、safe-linking などが該当します。対象の glibc のバージョンと、その手法が現在も適用できることを確認してください。
ATT&CK のカバレッジ
secskills-core/ttp-index.json から生成されます。このファイルを編集してから、
python3 scripts/sync_attack.py --write を実行してください。レポートで引用する前に、
ID を現行の ATT&CK リリースと照合して再確認してください。
実行(TA0002)
- T1203 クライアント実行のための悪用 —
performing-social-engineering、analyzing-malwareも参照
権限昇格(TA0004)
- T1068 権限昇格のための悪用 —
escalating-linux-privileges、escalating-windows-privilegesも参照
ラテラルムーブメント(TA0008)
- T1210 リモートサービスの悪用 —
enumerating-network-servicesも参照
これらの検知コンテンツ:engineering-detections。プロアクティブな検索:hunting-threats。侵害後の対応:responding-to-incidents。
参考資料
analyzing-binaries— まずコードを復元し、バグを理解するunpacking-protected-binaries— バイナリのアンパック/デバーチャル化が必要な場合reviewing-cryptography— 対象がメモリーではなく暗号プリミティブである場合maintaining-engagement-state— エグレスモードと、ここでのラボ専用のデフォルト設定