|
| 1 | +# Extra tools |
| 2 | + |
| 3 | +The `extra/` directory ships standalone helpers built around `kasld`: capture and |
| 4 | +replay, soundness validation, security-posture comparison, symbol resolution, and |
| 5 | +test setup. Each is a self-contained script with a `--help` / header comment — this |
| 6 | +page indexes them and shows how they combine into workflows. (`kasld` itself is in |
| 7 | +[usage.md](../docs/usage.md).) |
| 8 | + |
| 9 | +## Table of Contents |
| 10 | + |
| 11 | +- [The tools at a glance](#the-tools-at-a-glance) |
| 12 | +- [Workflows](#workflows) |
| 13 | + - [Measure what hardening buys](#measure-what-hardening-buys) |
| 14 | + - [Capture here, verify anywhere](#capture-here-verify-anywhere) |
| 15 | + - [Validate a live run against ground truth](#validate-a-live-run-against-ground-truth) |
| 16 | + - [Watch a fleet, gate CI](#watch-a-fleet-gate-ci) |
| 17 | + - [Turn a recovered base into an exploit](#turn-a-recovered-base-into-an-exploit) |
| 18 | +- [Standalone helpers](#standalone-helpers) |
| 19 | + |
| 20 | +## The tools at a glance |
| 21 | + |
| 22 | +| Tool | Purpose | Root? | Deeper reference | |
| 23 | +|------|---------|-------|------------------| |
| 24 | +| [`collect`](collect) | Capture a portable, self-identifying bundle of this host's KASLD-relevant state (meta, `kasld -v`, dmesg, a path-preserving `sysroot/` mirror) | no ¹ | [reproducibility.md](../docs/reproducibility.md#1-on-the-local-kernel) | |
| 25 | +| [`validate-bundle`](validate-bundle) | Offline soundness check over a `collect` bundle — asserts the resolved ranges contain the captured truth | no | [reproducibility.md](../docs/reproducibility.md#1-on-the-local-kernel) | |
| 26 | +| [`check-results`](check-results) | Live per-leak validator — compares a `kasld` run against `/proc/kallsyms` · `/proc/iomem` · `/proc/kcore` ground truth | **yes** | [testing.md](../docs/testing.md#validating-captured-bundles) | |
| 27 | +| [`posture-diff`](posture-diff) | Compare two `kasld -j` snapshots; exit non-zero if the KASLR **posture** regressed | no | [usage.md](../docs/usage.md#regression-gate-extraposture-diff) | |
| 28 | +| [`posture-summary`](posture-summary) | Roll up many `kasld -j` snapshots into one table (text / markdown / csv / json), one row per host | no | [usage.md](../docs/usage.md#fleet-summary-extraposture-summary) | |
| 29 | +| [`ksymoff`](ksymoff) | Apply the KASLR slide to kernel symbols; translate physical ↔ virtual and physical → `struct page` | no | [exploitation.md](../docs/exploitation.md#from-a-base-to-runtime-addresses) | |
| 30 | +| [`weaken-kernel-hardening`](weaken-kernel-hardening) | Temporarily relax the hardening sysctls for testing; restores the originals on exit | **yes** | below | |
| 31 | +| [`sudo-proc-kallsyms`](sudo-proc-kallsyms) | Briefly lower `kptr_restrict`, read the base symbols from `/proc/kallsyms`, restore | sudo | below | |
| 32 | +| [`check-hardware-vulnerabilities`](check-hardware-vulnerabilities) | Report the CPU hardware vulnerabilities (Meltdown / MDS / …) that can disclose kernel memory to an unprivileged process | no | [bypass-techniques.md](../docs/bypass-techniques.md#side-channels) | |
| 33 | +| [`anonymize-fdt`](anonymize-fdt) | Strip board serial / MAC from a captured device tree before sharing it as a replay fixture | no ² | [testing.md](../docs/testing.md) | |
| 34 | + |
| 35 | +¹ `collect --kallsyms` records ground truth only where `kptr_restrict` is readable |
| 36 | +(root, or `kptr_restrict=0`); without it the bundle carries no truth. |
| 37 | +² Maintainer / dev-host tool; needs `dtc`. |
| 38 | + |
| 39 | +## Workflows |
| 40 | + |
| 41 | +### Measure what hardening buys |
| 42 | + |
| 43 | +`kasld` recovers less on a hardened host and more on a relaxed one; `posture-diff` |
| 44 | +puts a number on the gap. Capture the posture in each state, then diff them. |
| 45 | + |
| 46 | +```sh |
| 47 | +# 1. Baseline: the host as it boots (whatever hardening is in effect). |
| 48 | +./build/*/kasld -j > hardened.json |
| 49 | + |
| 50 | +# 2. Relax the hardening sysctls. weaken-kernel-hardening holds until Ctrl+C and |
| 51 | +# restores the originals on exit; run kasld from a second terminal meanwhile. |
| 52 | +sudo extra/weaken-kernel-hardening # terminal A — leave it running |
| 53 | +./build/*/kasld -j > weakened.json # terminal B |
| 54 | +# ... then Ctrl+C in terminal A to restore the original sysctls. |
| 55 | + |
| 56 | +# 3. What did the hardening hide? Diff hardened (baseline) -> weakened (current): |
| 57 | +extra/posture-diff hardened.json weakened.json |
| 58 | +# REGRESSION: posture is weaker than baseline |
| 59 | +# - guaranteed entropy dropped: 9 -> 0 bits (virtual) |
| 60 | +# - defense turned off: kptr_restrict |
| 61 | +# - defense turned off: perf_event_paranoid |
| 62 | +``` |
| 63 | + |
| 64 | +The regression findings are exactly what the hardening was buying: the residual |
| 65 | +entropy it preserved and the defenses it kept on. `posture-diff` is **directional** |
| 66 | +(baseline first) — flip the arguments (`posture-diff weakened.json hardened.json`) |
| 67 | +and the same change reads as an improvement (`OK: no posture regression`). |
| 68 | + |
| 69 | +`weaken-kernel-hardening` relaxes `kptr_restrict`, `dmesg_restrict`, |
| 70 | +`perf_event_paranoid`, and `unprivileged_bpf_disabled` — a **testing** convenience, |
| 71 | +never for production. It restores the saved values on `Ctrl+C`, `SIGTERM`, or normal |
| 72 | +exit, so the weakened state never outlives the process. |
| 73 | + |
| 74 | +`posture-diff` compares only the **boot-stable** posture — guaranteed entropy |
| 75 | +(virtual and physical), KASLR state, unpatched CVE-class leaks, and disabled |
| 76 | +defenses. It never reads the per-boot base address or slide, which re-randomize |
| 77 | +every boot, so the same command doubles as a reboot-safe config-drift gate. |
| 78 | + |
| 79 | +### Capture here, verify anywhere |
| 80 | + |
| 81 | +`collect` freezes a host's KASLD-relevant state into a portable bundle that |
| 82 | +replays offline on another machine — useful for a bug report, an air-gapped |
| 83 | +target, or an architecture the analysis host can only emulate. |
| 84 | + |
| 85 | +```sh |
| 86 | +# On the target: capture (add --kallsyms to record ground truth for validation). |
| 87 | +extra/collect --kallsyms # -> kasld-bundle-<host>-<date>/ |
| 88 | + |
| 89 | +# Anywhere: replay the exact same facts through kasld, no target needed. |
| 90 | +KASLD_SYSROOT=kasld-bundle-*/sysroot ./build/*/kasld -v |
| 91 | + |
| 92 | +# And check the engine stayed sound over that capture (truth ∈ every range): |
| 93 | +extra/validate-bundle kasld-bundle-* |
| 94 | +``` |
| 95 | + |
| 96 | +`validate-bundle` needs no root — the truth comes from the bundle's captured files, |
| 97 | +not the host's `/proc`. It exits `0` (every quantity PASS or N/A), `1` (a soundness |
| 98 | +violation — the resolved window excluded the truth, a bug), or `2` (malformed |
| 99 | +bundle). See [reproducibility.md](../docs/reproducibility.md#1-on-the-local-kernel). |
| 100 | + |
| 101 | +### Validate a live run against ground truth |
| 102 | + |
| 103 | +On a system where you have root, `check-results` compares a live `kasld` run |
| 104 | +against the kernel's real addresses (`/proc/kallsyms`, `/proc/iomem`, …): |
| 105 | + |
| 106 | +```sh |
| 107 | +sudo extra/check-results # runs kasld itself |
| 108 | +./build/*/kasld -v 2>&1 | sudo extra/check-results # or validate a piped run |
| 109 | +sudo extra/check-results results.txt # or a saved report |
| 110 | +``` |
| 111 | + |
| 112 | +It reports PASS / FAIL / SKIP per result and asserts the resolved window contains |
| 113 | +the truth. A `sudo-proc-kallsyms` one-liner is the minimal version — it just |
| 114 | +lowers `kptr_restrict`, prints the base symbols from `/proc/kallsyms`, and restores. |
| 115 | + |
| 116 | +### Watch a fleet, gate CI |
| 117 | + |
| 118 | +The two `posture-*` tools scale the single-host view to an estate and to CI. They |
| 119 | +do no collection or transport themselves — your own fan-out supplies the snapshots |
| 120 | +(the file's basename is the host label, since `kasld -j` carries no hostname): |
| 121 | + |
| 122 | +```sh |
| 123 | +# One kasld -j per host, then summarise the whole fleet at a glance. |
| 124 | +for h in $(cat hosts); do ssh "$h" 'kasld -j' > "snap/$h.json"; done |
| 125 | +extra/posture-summary --markdown snap/*.json |
| 126 | + |
| 127 | +# In CI: fail the build if a target's posture regressed against a saved baseline. |
| 128 | +kasld -j > current.json |
| 129 | +extra/posture-diff baseline.json current.json || echo "KASLR posture regressed" |
| 130 | +``` |
| 131 | + |
| 132 | +Both read `kasld -j` snapshots (live, or replayed from a `collect` bundle via |
| 133 | +`KASLD_SYSROOT`). Full detail — the entropy-threshold and CVE-leak gates they pair |
| 134 | +with — is in [usage.md → Continuous integration](../docs/usage.md#continuous-integration). |
| 135 | + |
| 136 | +### Turn a recovered base into an exploit |
| 137 | + |
| 138 | +`ksymoff` consumes `kasld`'s output to resolve runtime symbol addresses (forward |
| 139 | +`base → symbols`, inverse `known symbol → base`) and to translate physical |
| 140 | +addresses for data-only pivots (`--phys2virt` / `--virt2phys` / `--phys2page`): |
| 141 | + |
| 142 | +```sh |
| 143 | +./build/*/kasld -1 2>/dev/null | extra/ksymoff -s System.map commit_creds |
| 144 | +``` |
| 145 | + |
| 146 | +The full exploit workflow — control-flow reuse vs data-only, the pwntools |
| 147 | +template, and every `ksymoff` mode — is in |
| 148 | +[exploitation.md](../docs/exploitation.md#from-a-base-to-runtime-addresses). |
| 149 | + |
| 150 | +## Standalone helpers |
| 151 | + |
| 152 | +These two stand alone rather than chaining into a workflow above: |
| 153 | + |
| 154 | +- **[`check-hardware-vulnerabilities`](check-hardware-vulnerabilities)** *(target |
| 155 | + reconnaissance)* — reports which memory-disclosure CPU bugs (Meltdown, MDS, …) |
| 156 | + the running kernel still exposes, i.e. whether a hardware leak of kernel data |
| 157 | + (and with it a pointer that defeats KASLR) is applicable here at all. These |
| 158 | + differ in power: Meltdown reads arbitrary kernel addresses, while MDS/L1TF-class |
| 159 | + flaws leak only opportunistic in-flight or cache-resident data. Background in |
| 160 | + [bypass-techniques.md](../docs/bypass-techniques.md#side-channels). |
| 161 | +- **[`anonymize-fdt`](anonymize-fdt)** *(maintainer / fixtures)* — a dev-host tool: strips |
| 162 | + board-identifying serial / MAC properties from a captured flattened device tree |
| 163 | + (`sysroot/sys/firmware/fdt`) before it is committed as a shared replay fixture. It |
| 164 | + deliberately keeps `chosen/kaslr-seed` (KASLD reads it to infer the KASLR state). |
| 165 | + Needs `dtc`; edits in place with a `.orig` backup. |
0 commit comments