mcpField
B
binary-protection-bypass

binary-protection-bypass

github.com/yaklangセキュリティ2.6k3.7k 回インストール6 週間前に更新
リポジトリ

binary-protection-bypass について

バイナリ分析や脆弱性調査向けに、各種防御機構の識別方法と回避手法、必要なプリミティブをまとめたセキュリティスキルです。一般的なコンパイル時の防御からハードウェア機能まで扱います。

主な機能

  1. 01ASLR、PIE、NX、RELRO、Canary の識別
  2. 02防御機構と回避手法の対応付け
  3. 03手法に必要な条件とプリミティブの提示
  4. 04FORTIFY_SOURCE、CET、ARM MTE の解説

活用シーン

  1. 01checksec の防御設定を確認
  2. 02有効な防御に沿って攻撃手順を検討
  3. 03回避手法と必要条件を比較

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yaklang/hack-skills --skill binary-protection-bypass

インストール後、Claude Code で/binary-protection-bypassを入力して読み込まれたか確認します。

同梱ファイルPROTECTION_BYPASS_MATRIX.md

詳細

スキル:バイナリ保護の回避 — エキスパート向け攻撃プレイブック

AI LOAD INSTRUCTION:バイナリ保護の特定と回避に関するエキスパート向け手法です。ASLR、PIE、NX、RELRO、canary、FORTIFY_SOURCE、stack clash、CET shadow stack、ARM MTE を扱います。各保護について、回避方法と必要なプリミティブを組み合わせて説明します。ctf-wiki の緩和策に関するセクションと、実環境でのエクスプロイトをもとに要点をまとめています。ベースモデルは、どの保護がどの攻撃を阻止するのかを混同しやすく、複数の保護が組み合わさった場合の効果を見落としがちです。

0. 関連するルーティング

高度なリファレンス

保護 × 回避方法 × プリミティブの包括的なマトリックスについては、PROTECTION_BYPASS_MATRIX.md を読み込んでください。


1. 保護の特定

$ checksec ./binary
[*] '/path/to/binary'
    Arch:     amd64-64-little
    RELRO:    Full RELRO          ← GOT read-only
    Stack:    Canary found        ← stack canary enabled
    NX:       NX enabled          ← stack not executable
    PIE:      PIE enabled         ← position-independent code
    FORTIFY:  Enabled             ← fortified libc functions
簡易特定表
保護確認コマンドバイナリの指標
ASLRcat /proc/sys/kernel/randomize_va_spaceOS レベル(0=無効、1=部分的、2=完全)
PIEchecksec または readelf -h(Type: DYN)-pie を指定してコンパイルされたバイナリ
NXchecksec または readelf -l(RWE セグメントなし)gcc -z noexecstack(デフォルトで有効)
Canarychecksec または __stack_chk_fail@plt を確認gcc -fstack-protector-all
Partial RELROreadelf -l(GNU_RELRO セグメント、.got.plt は書き込み可能)gcc -Wl,-z,relro
Full RELROreadelf -l と .got セクションが読み取り専用であることを確認gcc -Wl,-z,relro,-z,now
FORTIFY__printf_chk、__memcpy_chk などが存在することgcc -D_FORTIFY_SOURCE=2

2. ASLR の回避

ASLR は実行のたびに、スタック、ヒープ、libc、mmap 領域のベースアドレスをランダム化します。

回避方法必要なプリミティブ備考
情報リーク任意の読み取りプリミティブ(フォーマット文字列、範囲外読み取り、UAF)libc/スタック/ヒープのアドレスをリーク → ベースアドレスを計算
部分上書き書き込みプリミティブ(長さに制限あり)末尾の 1~2 バイトを上書き(ページオフセットは固定)
ブルートフォース(32 ビット)再接続/再試行できること約 256~4096 回の試行(エントロピー 8~12 ビット)
Return-to-PLTスタックオーバーフローPLT アドレスはバイナリのベースアドレスから固定オフセットにある(PIE なしの場合)
ret2dlresolveスタックオーバーフロー+書き込みプリミティブlibc のベースアドレスを知らずに任意の関数を解決
フォーマット文字列によるリークフォーマット文字列の脆弱性%N$p でスタック/libc/ヒープのアドレスを取得
スタック読み取り1 バイトずつ(fork サーバー)クラッシュオラクルを使ってスタックを 1 バイトずつ読み取る
ASLR のエントロピー(x86-64 Linux)
領域エントロピー(ビット)位置数
スタック22約 4M
mmap/libc28約 256M
ヒープ(brk)13約 8K
PIE バイナリ28約 256M

3. PIE の回避

PIE(位置独立実行ファイル)は、バイナリ自体のコード/データのベースアドレスをランダム化します。

回避方法必要なプリミティブ備考
情報リークスタックからリターンアドレスを読み取るPIE のベースアドレス = リークしたアドレス - 既知のオフセット
部分上書き1 バイトまたは 2 バイトの書き込みページオフセットの下位 12 ビットは固定
フォーマット文字列によるリークフォーマット文字列の脆弱性N が .text のリターンアドレスを指す場合の %N$p
相対アドレス指定バイナリのレイアウトに関する知識相対オフセットが分かっていれば、リークは 1 つだけでよい
部分上書きの詳細
PIE binary loaded at: 0x555555554000 (example)
Function at offset 0x1234: 0x555555555234

Overwrite return address last 2 bytes: 0x?234 → 0x?XXX
Unknown: bits 12-15 (one nibble = 4 bits = 16 possibilities)
Success rate: 1/16 per attempt

4. NX/DEP のバイパス

NX(No-eXecute)/DEP(Data Execution Prevention)は、スタック/ヒープ上のコード実行を防止します。

バイパス方法詳細
ROP(Return-Oriented Programming)ret で終わる既存のコードガジェットを連結します
ret2libclibc 関数(system、execve)を直接呼び出します
ret2csu__libc_csu_init ガジェットを使って、制御された関数呼び出しを行います
ret2dlresolve動的リンカー構造を偽造し、任意の関数を解決させます
SROPsigreturn を使い、偽のシグナルフレームからすべてのレジスターを設定します
mprotect ROPmprotect(addr, size, PROT_RWX) を連結 → ページを実行可能にする → シェルコードにジャンプします
JIT スプレーJIT 環境(V8 など)で、JIT コンパイラーを通じて実行可能コードを作成します
mprotect チェーン
# Make stack executable, then jump to shellcode
rop = b'A' * offset
rop += p64(pop_rdi) + p64(stack_page)     # page-aligned address
rop += p64(pop_rsi) + p64(0x1000)         # size
rop += p64(pop_rdx) + p64(7)              # PROT_READ|PROT_WRITE|PROT_EXEC
rop += p64(mprotect_addr)
rop += p64(shellcode_addr)                 # jump to shellcode on now-executable stack

5. RELRO のバイパス

RELRO レベルGOT の状態バイパス方法
No RELROGOT は完全に書き込み可能GOT を直接上書きします
Partial RELRO.got.plt は書き込み可能(遅延バインディング)GOT の上書きが引き続き可能です
Full RELROすべての GOT エントリーがロード時に解決され、GOT は読み取り専用GOT には書き込めないため、他の構造を標的にします
Full RELRO の代替ターゲット
ターゲット条件方法
__malloc_hookglibc < 2.34one_gadget で上書きします
__free_hookglibc < 2.34system で上書きし、free("/bin/sh") を実行します
_IO_FILE vtableすべての glibcFSOP/vtable ハイジャック
__exit_funcsすべての glibc終了ハンドラーリストを上書きします
TLS_dtor_listglibc ≥ 2.34スレッドローカルデストラクターリスト(ポインターガードが必要)
.fini_array書き込み可能な場合デストラクター関数ポインターを上書きします
スタックのリターンアドレススタックへの直接書き込みリターンアドレスを上書きして ROP を実行します

包括的なターゲット一覧については、arbitrary-write-to-rce を参照してください。


6. CANARY のバイパス

方法条件詳細
フォーマット文字列リークprintf(user_input)%N$p を使ってスタックから canary を読み取ります
ブルートフォースfork() サーバー(canary は子プロセスでも維持されます)1 バイトずつ試行します:256 × (canary_size-1) 回の試行
スタック読み取り部分上書き/情報リークcanary のヌルバイトを上書きし、出力からリークさせます
スレッド canary の上書きオーバーフローが TLS に到達するcanary は fs:[0x28] にあります。バッファーを越えて TLS までオーバーフローさせ、canary を既知の値で上書きします
canary 相対上書きcanary の後、リターンアドレスの前でオーバーフローするcanary を避け、リターンアドレスのみを上書きします(まれなレイアウト)
ヒープベース脆弱性がスタックではなくヒープ上にあるcanary が保護するのはスタックのみです
__stack_chk_fail GOT の上書きPartial RELRO__stack_chk_fail@GOT を無害な関数に向けて上書きし、canary チェックを通過させます
Canary の形式
x86:    0x00XXXXXX (4 bytes, leading null byte)
x86-64: 0x00XXXXXXXXXXXXXX (8 bytes, leading null byte)

先頭の \x00 によって、文字列操作で誤って canary が読み取られるのを防ぎます。


7. FORTIFY_SOURCE のバイパス

_FORTIFY_SOURCE=2 はバッファーサイズチェックを追加し、フォーマット文字列操作を制限します。

強化された関数制限バイパス方法
__printf_chk位置指定引数を伴う %n(%N$n)は禁止されています位置指定なしの %n または %hn チェーンを使います
__memcpy_chk宛先バッファーのサイズがチェックされますスタックの代わりにヒープオーバーフローを使います
__strcpy_chk同上
__read_chk読み取りサイズがバッファーに対してチェックされます
FORTIFY_SOURCE を使ったフォーマット文字列
# %1$n is blocked by __printf_chk
# But sequential (non-positional) %n may still work:
# Print exact byte count, then %hn — must be very precise
# Or: find unfortified printf in binary/libc via ROP

8. CET(Control-flow Enforcement Technology)

Intel CET は、2 つのメカニズムを追加します。

シャドウスタック
  • ハードウェアで管理されるリターンアドレスのコピー
  • ret の実行時に、CPU はシャドウスタックが実際のスタックと一致するかをチェックします
  • 不一致の場合 → #CP フォールト(制御保護例外)
影響詳細
ROP はブロックされるret の実行時にリターンアドレスの上書きが検出されます
JOP は可能jmp [reg] はシャドウスタックでチェックされません
COP は可能call [reg] はシャドウスタックにプッシュされますが、ターゲットは IBT で検証されます
間接分岐トラッキング(IBT)
  • 間接 jmp/call は ENDBR64 命令に着地する必要があります
  • ENDBR 以外の場所に着地すると、#CP フォールトが発生します

バイパス:

  • データのみを狙う攻撃(制御フローは変更しません)
  • 有用な操作につながる、有効な ENDBR ガジェットを見つけます
  • ENDBR で始まるガジェットを使った JOP
  • CFI の対象範囲外にある構造を標的にします(modprobe_path、関数ポインター配列)

9. MTE(メモリータグ付け拡張、ARM)

ARM MTE は、メモリーポインターとメモリー割り当てに 4 ビットのタグを割り当てます。タグが一致しない場合、フォールトが発生します。

項目詳細
タグのビット数ポインター内の 4 ビット(ビット 56~59)=16 個のタグが使用可能
グラニュール16 バイト(各 16 バイトのグラニュールに 1 つのタグがあります)
チェックロード/ストア時に、ポインターのタグがメモリータグと一致する必要があります
確率タグはランダムであり、攻撃者が正しく推測できる確率は 1/16 です
バイパス手法
手法成功率
ブルートフォース試行ごとに 1/16(6.25%)
タグオラクルサイドチャネルを使ってタグを判定します(タイミング、エラーメッセージ)
範囲内でのエクスプロイト同じタグ付き領域内にとどまります(相対オフセットを使用します)
タグバイパスガジェットアクセス可能な場合は LDGM/STGM 命令を使用します
投機的実行Spectre 型のタグチェックバイパス

10. 意思決定ツリー

Binary analysis: checksec output
├── NX disabled?
│   └── Shellcode on stack/heap (simplest path)
│
├── NX enabled (standard modern binary)?
│   ├── Need code execution → ROP/ret2libc
│   │
│   ├── Canary enabled?
│   │   ├── fork server? → byte-by-byte brute-force
│   │   ├── Format string? → leak canary via %p
│   │   ├── Heap vuln? → canary doesn't protect heap
│   │   └── Partial RELRO? → overwrite __stack_chk_fail@GOT
│   │
│   ├── PIE enabled?
│   │   ├── Format string? → leak .text address → PIE base
│   │   ├── Partial overwrite → last 12 bits fixed (1/16 brute-force)
│   │   └── OOB read? → leak code pointer
│   │
│   ├── ASLR enabled?
│   │   ├── Info leak available → leak libc base
│   │   ├── No leak → ret2dlresolve or SROP
│   │   ├── 32-bit? → brute-force feasible (~4096 attempts)
│   │   └── Return-to-PLT (no libc base needed for PLT calls)
│   │
│   ├── RELRO level?
│   │   ├── None/Partial → GOT overwrite
│   │   └── Full → alternative targets:
│   │       ├── glibc < 2.34 → __malloc_hook / __free_hook
│   │       ├── glibc ≥ 2.34 → _IO_FILE / exit_funcs / TLS_dtor_list
│   │       ├── .fini_array (if writable)
│   │       └── Stack return address
│   │
│   └── FORTIFY_SOURCE?
│       ├── Blocks positional %n → use sequential %n or heap exploit
│       └── Blocks buffer overflows in fortified functions → use unfortified paths
│
├── CET (shadow stack)?
│   ├── ROP blocked → data-only attack or JOP
│   └── ENDBR-gadget chaining
│
└── MTE (ARM)?
    ├── 1/16 brute-force
    └── Stay in-bounds for relative corruption

コメント