External Tools Integration¶
Crucible's built-in triage handles the common case, but dedicated crash analysis tools provide additional capabilities: automated clustering, crash minimization, and root cause deduction. This guide covers integrating these tools into your workflow.
CASR — Crash Analysis and Severity Rating¶
CASR (v2.13.0+) provides automated crash clustering, deduplication, and severity estimation for sanitizer-detected crashes.
Installation¶
# Install from crates.io (requires Rust toolchain)
cargo install casr --locked
# Verify
casr-libfuzzer --version
Triaging libFuzzer Crashes¶
Use casr-libfuzzer to process a crash directory against a harness binary:
casr-libfuzzer \
-i ./crashes/deep \
-o ./casr-out/deep \
-- ./harness/libfuzzer/crucible-libfuzzer-deep
This replays each crash file, captures the sanitizer output, and writes a .casrep JSON report per crash.
Clustering¶
Use casr-cluster to deduplicate and group crashes by stack similarity:
# Deduplicate
casr-cluster -d ./casr-out/deep
# Cluster into groups
casr-cluster -c ./casr-out/deep ./casr-clusters/deep
The cluster output directory contains one subdirectory per unique crash, with the representative .casrep and all duplicate crash files grouped together.
Interpreting Results¶
CASR reports include:
- Crash severity — Exploitable, Probably Exploitable, Medium, Not Exploitable
- Crash class — ASAN-specific crash type (e.g.,
heap-buffer-overflow) - Stack trace — Full sanitizer stack trace
- Registers — CPU register state at crash point (when available)
CASR vs. Crucible Triage
CASR and Crucible triage are complementary. Crucible's crucible-triage focuses on CWE mapping, CVSS scoring, and SARIF export for CVE reporting. CASR excels at large-scale crash clustering when you have thousands of crash files to sort. Use CASR first to cluster, then feed unique representatives into crucible-triage for report generation.
Batch Processing Multiple Campaigns¶
# Process all campaign directories
for campaign in deep model rpc-commands rpc-race whisper-audio; do
casr-libfuzzer \
-i "./crashes/${campaign}" \
-o "./casr-out/${campaign}" \
-- "./harness/libfuzzer/crucible-libfuzzer-${campaign}"
casr-cluster -c "./casr-out/${campaign}" "./casr-clusters/${campaign}"
done
# Summary of unique crashes per campaign
for d in ./casr-clusters/*/; do
echo "$(basename "$d"): $(ls -d "$d"/*/ 2>/dev/null | wc -l) unique"
done
halfempty — Crash Minimization¶
halfempty uses bisection strategies to minimize crash reproducers. Smaller reproducers make root cause analysis easier and produce cleaner CVE reports.
Installation¶
# Build from source (requires glib2 development headers)
# Fedora/RHEL:
sudo dnf install glib2-devel
# Ubuntu/Debian:
sudo apt install libglib2.0-dev
git clone https://github.com/googleprojectzero/halfempty.git
cd halfempty
make
sudo cp halfempty /usr/local/bin/
Minimizing a Crash¶
halfempty requires a script that exits 0 for "interesting" (still crashes) and non-zero for "not interesting":
#!/bin/bash
# Exit 0 if the input still triggers the crash
timeout 10 ./harness/libfuzzer/crucible-libfuzzer-deep "$1" 2>&1 | \
grep -q "heap-buffer-overflow" && exit 0
exit 1
halfempty will produce a minimized file that still triggers the same crash.
Strategies¶
| Strategy | Description | Best For |
|---|---|---|
bisect | Binary search removal of byte ranges | General purpose, fastest |
zero | Replace byte ranges with zeros | Preserving file structure |
delete | Remove individual bytes | Fine-grained minimization |
Integration with Crucible Triage¶
Minimize crashes before triaging for cleaner reports:
Built-in minimization
crucible-triage --minimize natively recurses into crash subdirectories and preserves directory structure, reducing the need for external minimization tools in many workflows. Use halfempty when you need fine-grained control over the minimization strategy (bisect vs. zero vs. delete).
# Minimize all unique crashes in a cluster
for crash in ./casr-clusters/deep/*/crash-*; do
halfempty --strategy bisect ./minimize.sh "$crash"
done
# Then triage the minimized set
crucible-triage --crashes ./minimized --output ./reports
Workflow: Full Pipeline¶
A complete triage pipeline combining all tools:
flowchart TD
A[Fuzzing Campaign] --> B[Raw Crashes]
B --> C[CASR: Cluster & Dedup]
C --> D[Unique Representatives]
D --> E[halfempty: Minimize]
E --> F[Minimized Reproducers]
F --> G[crucible-triage: Reports + SARIF]
G --> H[Markdown Reports]
G --> I[SARIF for CI] # 1. Cluster with CASR
casr-libfuzzer -i ./crashes/deep -o ./casr-out -- ./harness/libfuzzer/crucible-libfuzzer-deep
casr-cluster -c ./casr-out ./casr-clusters
# 2. Minimize each unique crash
for cluster in ./casr-clusters/*/; do
crash=$(ls "$cluster"/crash-* 2>/dev/null | head -1)
[ -n "$crash" ] && halfempty --strategy bisect ./minimize.sh "$crash"
done
# 3. Generate reports and SARIF
crucible-triage \
--crashes ./minimized \
--output ./reports \
--sarif ./results.sarif