re-crash-triage について
re-crash-triageは、ファジング結果やクラッシュ報告を扱うセキュリティ研究者向けの、クラッシュ分析と脆弱性特定のスキルです。再現、入力の最小化、デバッグ、PoC作成を一連の手順で扱い、非決定的なクラッシュにも対応します。
主な機能
- 01クラッシュの再現と分類
- 02ASANによるメモリエラー分析
- 03クラッシュ入力の最小化
- 04gdbまたはrrによる原因特定
- 05PoCと脆弱性レポートの作成
活用シーン
- 01ファジングで見つかったクラッシュの分析
- 02クラッシュが到達可能な脆弱性か評価
- 03非決定的なマルチスレッドクラッシュの再現
- 04最小化したクラッシュPoCの作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dslsdzc/ rev-skills --skill re-crash-triageインストール後、Claude Code で/re-crash-triageを入力して読み込まれたか確認します。
詳細
クラッシュ分析と脆弱性の特定(crash triage)
いつ使用するか/いつ使用しないか
- 使用する:fuzz によってクラッシュ入力が生成された場合、プログラムがセグメンテーション違反/abort した場合、クラッシュが実際の脆弱性か(到達可能性)を判断して最小の PoC を作成する必要がある場合、マルチスレッド/非決定的なクラッシュを再現する必要がある場合
- 使用しない:まだクラッシュしておらず、能動的に bug を探したい場合(→ [[re-fuzzing]]);クラッシュの位置は特定済みで、関数のロジックをさらに詳しく調べたい場合(→ [[re-binary-core]] 基盤)
- 使用しない:シンボルスタックだけを確認したい場合(直接 [[re-gdb]] を使ってもかまいませんが、このスキルには「再現→最小化→特定→PoC」の完全な手順が含まれています)
ツールの準備
すべてのツールは、使用前に検証してください。クラッシュの再現は動的実行であるため、デフォルトでサンドボックス内で実行します([[re-analyze/platform-tips]] の最優先原則を参照。[[re-sandbox]])。
ASAN / UBSAN —— メモリと未定義動作の検出(clang/gcc に内蔵)
- clang:
sudo apt install clang/sudo dnf install clang/sudo pacman -S clang/ macOS の Xcode に付属 - gcc:Debian/Ubuntu では
sudo apt install gcc(ASAN は gcc に内蔵されており、独立したパッケージはありません);Fedora ではsudo dnf install gcc;Arch ではsudo pacman -S gcc - コンパイル:
gcc -fsanitize=address,undefined -g -fno-omit-frame-pointer -o target_asan target.c(clang でも同じパラメーターを使用) - 検証:配列の範囲外アクセスを起こす小さなプログラムを書いてコンパイル、実行し、出力に
AddressSanitizerという文字列が含まれることを確認します
gdb —— バックトレースと core 分析
- Debian/Ubuntu:
sudo apt install gdb - Fedora/RHEL:
sudo dnf install gdb - Arch:
sudo pacman -S gdb - macOS:
brew install gdb(codesign の認証が必要);Xcode に付属の lldb も使用できます([[re-lldb]] を参照) - Windows:WSL 内では Linux 版を使用;Windows ネイティブでは WinDbg を使用([[re-windbg]])
- 検証:
gdb --version
rr —— 記録/再生(非決定的なクラッシュ)
- Debian/Ubuntu:
sudo apt install rr(universe リポジトリ) - Fedora/RHEL:
sudo dnf install rr - Arch:
paru -S rr(AUR パッケージ;公式リポジトリに rr はありません) - macOS:サポートなし(rr は Linux のみをサポートします。公式の言葉では「Apple hardware is fine, Apple software is not」);Apple Silicon ユーザーは Asahi Linux または Linux 仮想マシンを使用します(PMU パススルーが必要)
- Windows:WSL2 内では Linux 版を使用
- ソースからのコンパイル:
git clone https://github.com/rr-debugger/rr && mkdir rr/obj && cd rr/obj cmake -DCMAKE_BUILD_TYPE=Release ../rr && make -j$(nproc) && sudo make install - 前提条件:Linux カーネル 3.11+(4.7+ を推奨);
perf_event_paranoidが 1 より大きい場合は極端に遅くなるため、先に制限を解除します:sudo sysctl kernel.perf_event_paranoid=1 - 仮想マシン内では PMU パススルーが必要です(VMware/KVM は可、VirtualBox は不可)
- コンテナ/制限された環境では、まず自己診断してください:
rr checkで PMU/perf_eventの利用可否と既知の制限を確認し、問題がなければ使用します。ネストされた仮想化環境や、PMU がパススルーされていないコンテナでは rr を使って記録できません - PMU が利用できない場合の代替手段(rr にこだわらないでください):同じ入力で複数回再実行し、ログ/条件付きブレークポイントを使って競合状態が起きる範囲を絞り込みます。データ競合の問題は
valgrind --tool=helgrindまたは-fsanitize=threadを使ったビルドで特定します。ASLR の揺らぎだけが原因の場合は、まずset disable-randomization onで無効化して切り分けます - 検証:
rr --version
afl-tmin / afl-cmin —— 入力の最小化と重複排除(AFL++ とともにインストール)
- インストール方法は [[re-fuzzing]] の AFL++ セクションを参照(
afl-tmin/afl-cminはパッケージとともにインストールされます) - 前提条件(特に
afl-cminでは重要):afl-cminでは、対象を AFL で観測できる必要があります。通常、AFL インストルメンテーション付きでビルドされている必要があります(afl-clang-fast/afl-gcc)。そうでない場合、「インストルメンテーションなし/not instrumented」というエラーが出て失敗します。afl-tminの制約ははるかに緩く、純粋なクラッシュ判定で動作できるため、インストルメンテーションなしの対象でも通常は実行できます - よくある落とし穴:対象が独立した ASAN ビルド(
gcc -fsanitize=address -g)で、かつafl-clang-fastを使っていない場合、afl-cminが動作する保証はありません。まずビルド方法を確認してください。AFL コンパイラーでビルドされていない場合は、afl-tminを使って個別に最小化するか、[[re-fuzzing]] に戻ってインストルメンテーション付きバージョンを再ビルドします - 検証:
afl-tmin -h/afl-cmin -h
操作手順
順番に実行します。クラッシュ入力と PoC は、まず sha256 を記録して証拠として保全します([[re-triage]] の方法を参照)。
- 決定的な再現:
sha256sum crash_input > crash_input.sha256 ./target < crash_input # stdin 输入 ./target crash_input # 文件输入 ./target -f crash_input # 按目标实际参数形态- 3 回連続でクラッシュする場合は決定的なクラッシュです。手順 2 に進みます。クラッシュしたりしなかったりする場合は非決定的です(マルチスレッド/未初期化/ASLR)。手順 4 に進み、rr を使用します
- core dump を有効にします(クラッシュ後に分析用の core を残します):
ulimit -c unlimited;cat /proc/sys/kernel/core_patternが systemd-coredump/apport を指している場合、core はシステムに回収されます(落とし穴 4 を参照)
- ASAN レポートの読み解き(対象は
-fsanitize=address -g -fno-omit-frame-pointerを指定してビルドする必要があります。ツールの準備を参照):heap-buffer-overflow/stack-buffer-overflow/global-buffer-overflow:範囲外読み書きです。レポートには範囲外アクセスの方向(READ of size N/WRITE of size N)と範囲外のオフセットが含まれますheap-use-after-free:UAF です。freed byとallocated byの 2 つのスタックを見て、解放箇所と再使用箇所を特定しますattempting double-free:二重解放ですSEGV:ヌルポインター/不正なポインターへのアクセスです。詳細は gdb で補足する必要があります(手順 4)- 重要:
#0フレームがクラッシュ箇所です。行番号だけを見ないでください。データフローと照らし合わせて、どの入力バイトが原因かを判断します
- 入力の最小化:
afl-tmin -i crash_input -o crash.min -- ./target @@ # 多个崩溃输入先按路径去重(需 AFL 插桩,见工具准备): afl-cmin -i crashes_dir -o minimized -- ./target @@@@は「ファイル引数」を取る対象にのみ使えます(AFL は@@を入力ファイルのパスに置き換えます)。対象が stdin から入力を読み込む場合は@@を使わず、「ファイル → stdin」の手順をコマンドラインに追加します。たとえば次のようにします:
または、対象にafl-tmin -i crash_input -o crash.min -- sh -c './target < "$1"' _ @@-f <file>などのファイル引数がある場合は、それを使って@@を置き換えます。手順 1 で確認した実際の入力形式に合う書き方を選んでください- afl-tmin は、クラッシュを維持する最短の入力を生成します。さらに手作業で先頭/末尾のバイトを削除して検証することもできます(二分探索で最小境界を探します)
- 最小化後の入力が PoC の草案になります。クラッシュの種類が変わらないことが、同じ bug であると判断する根拠です
- gdb によるバックトレースと特定:
gdb -q ./target (gdb) set disable-randomization on # 关 ASLR 便于地址对照 (gdb) run crash.min (gdb) bt # 完整回溯 (gdb) info registers # 崩溃点寄存器 (gdb) x/16i $pc # 崩溃点反汇编- core ファイルを分析するには:
gdb -q ./target /path/to/core btがすべて??(シンボルなし)になる場合:モジュールのベースアドレスとオフセットを記録し、[[re-ghidra]] / [[re-ida]] で逆コンパイルしてフレームを補います(落とし穴 5 を参照)- 非決定的なクラッシュの場合 → rr で記録して再生します:
rr record ./target crash_input rr replay # gdb セッションを開く (rr) continue # クラッシュ箇所まで実行 (rr) bt (rr) reverse-continue # クラッシュ前に逆向きに実行して根本原因を探す
- core ファイルを分析するには:
- PoC/レポート:
- PoC:
crash.min+ sha256 + 再現コマンド(環境:ASAN のビルドパラメーター、実行パラメーター、入力経路) - レポートの要点:クラッシュの種類(ASAN の分類)、クラッシュ箇所の関数/行/オフセット、データフロー(どの入力バイト → 範囲外のインデックス)、根本原因(長さチェックの欠如/インデックスの未検証/解放後使用)、到達可能性(落とし穴 3 を参照:クラッシュ経路に実際に到達可能で、入力を制御できること)、影響評価(範囲外読み取り → 情報漏えい、範囲外書き込み → RCE、クラッシュのみ → DoS)、修正の推奨事項
- 成果物:PoC のハッシュとクラッシュの特徴は [[re-ioc]] に登録できます
- PoC:
跨域联合
- [[re-vuln]]:本网关工作流第 3 步固定调用本技能(崩溃分析是漏洞挖掘链路的核心环节)
- [[re-fuzzing]]:其崩溃产出(
out/crashes/)交本技能分析(本技能也反向使用其 afl-tmin/cmin 工具链) - [[re-binary-core]]:定位后补符号/读函数逻辑走底座([[re-ghidra]] / [[re-ida]] / [[re-radare2]]);[[re-triage]] 提供存证方法
- [[re-memdump]]:进程已死 / 已有 core 文件需更多上下文时转储分析(崩溃 core → memdump)
- [[re-sandbox]] / [[re-analyze/platform-tips]]:复现是动态执行,默认沙箱内跑
常见坑与陷阱
- 非确定性崩溃(多线程):现象——同一输入 10 次里崩 3 次,gdb 重跑复现不了;原因——线程竞态 / 未初始化内存 / ASLR 地址差异;对策——rr 录制(
rr record ./target input)在崩溃点自动停止,rr replay+reverse-continue反向定位根因;先set disable-randomization on排除 ASLR 因素 - ASAN 与优化差异:现象——ASAN(-O0/-O1)崩溃但 release(-O2)不崩,或反过来 release 才崩;原因——优化改变内存布局/时序,掩盖或暴露未定义行为;对策——两种构建都试;补
-fsanitize=undefined抓 UB;影响与可达性判断以真实 release 行为为准(ASAN 报出的是潜在漏洞,需确认) - 崩溃≠漏洞(可达性):现象——ASAN 报越界但在死代码/不可达分支,或崩溃由 harness 引入;原因——fuzzer 触发的输入未必对应真实攻击面;对策——gdb 回溯 + 反编译确认崩溃路径可触达、输入可控;区分 harness bug 与目标 bug([[re-vuln]] 工作流第 4 步兜底确认)
- core 被系统收走:现象——
ulimit -c unlimited后崩溃仍无 core 文件;原因——core_pattern指向 systemd-coredump(管道方式)/apport 拦截;对策——先cat /proc/sys/kernel/core_pattern确认落点,再按落点取回:core_pattern形如|/usr/lib/systemd/systemd-coredump ...:core 已被 systemd 接管,不要急着改全局设置,直接取用即可——coredumpctl list找条目(按可执行名/时间),coredumpctl info <PID|可执行名>看元数据,coredumpctl dump <PID> -o core导出,或coredumpctl gdb <PID>直接进 gdb 调试。这比改core_pattern更完整,也不影响系统上其它程序的 core 行为- apport 接管(Ubuntu):core 落在
/var/crash/,用apport-unpack展开 - 确实需要原始 core 文件时再临时改:
sudo sysctl kernel.core_pattern=core(core 落到进程工作目录,注意只对之后启动的进程生效) - 兜底:
gdb --args ./target crash.min直接跑,不依赖 core 文件
- 符号缺失:现象——
bt全??、地址对不上;原因——strip / 静态链接 / 二进制与 core 版本不一致;对策——core 与二进制必须同版本(对比 sha256);记录崩溃模块基址与偏移,在 [[re-ghidra]] / [[re-ida]] 按偏移定位函数,换算回 gdb 地址
コメント
Markdown 対応