Files
CellGuard/common/docs/anti-forensics-hardening.md
sssnake 9a3e3a0501 CellGuard: LTE/5G-NR lock + IMSI-catcher detection KSU module
- cgcap.ko: cpif CP-frame capture via kprobe/kallsyms, stock-GKI build
- ratlock.sh: hold modem to LTE+NR(5G), block 2G/3G downgrade
- cgdetect.sh: always-on behavioral cell-site-simulator detection
- cgctl.sh + WebUI: block/detect toggles, status + alerts
- build-stock-gki.sh: reproducible stock-GKI module build pipeline
2026-07-12 09:21:54 -07:00

194 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Rango Anti-Forensics Hardening — Case Write-Up
**Scope:** Owner-authorized security hardening and research on a personally-owned
device. Goal: raise the cost of physical forensic extraction (Cellebrite UFED,
GrayKey, XRY, Oxygen) and make the shell / low-level flash interfaces
inaccessible without owner authorization.
> This document is a defensive engineering plan for the device owner's own
> hardware. The research track (§8) is authorized vulnerability research on
> that same device; its purpose is to understand and mitigate the attack
> surface, not to produce a distributable exploit.
---
## 1. Objective
- Resist forensic extraction by a physical-access adversary.
- Deny an attacker useful access to adb, fastboot, fastbootd, recovery, and the
USB data surface — gated behind owner authentication.
- Keep the device usable (and rooted, for the CellGuard modem work) without
giving that up as the price of hardening.
## 2. Device baseline (as-found)
| Item | Value |
|---|---|
| Device | Pixel 10 Pro Fold (`rango`), Tensor G5, Shannon 5400 modem |
| Kernel | stock GKI `6.6.102-android15-8-g6eb5b2a8c46b-ab14739656-4k` |
| Kernel hardening | RANDSTRUCT_NONE, CFI_CLANG (strict), MODVERSIONS, LTO_NONE, MODULE_SIG_PROTECT, MODULE_SIG_FORCE **off** |
| Root | KernelSU **LKM** |
| Bootloader | **unlocked** (props spoofed to locked/green to pass Play Integrity) |
| adb | USB + wireless both enabled; `ro.adb.secure=1`; 1 authorized host key |
## 3. Threat model
- **Adversary:** forensic extraction appliance with physical possession.
- **Primary vectors:**
1. **USB attack surface** — adb, fastboot (ABL), fastbootd (userspace), the
USB gadget/MTP stack. The port is the appliance's front door.
2. **Lockscreen brute force** — throttled by Titan M2, but exploits + time
erode a short PIN.
3. **AFU key residency** — After First Unlock, disk-encryption keys are in RAM
and the secure element has seen the credential → extraction is far easier
than the Before-First-Unlock (BFU) state.
4. **Unlocked bootloader** — while unlocked, `fastboot boot <img>` runs an
attacker image *instead of* the owner OS, bypassing any in-OS defense.
## 4. Boot chain & trust anchors — what the owner can and cannot control
```
bootrom (fused OEM key) → bl1 → bl2 → bl31 (EL3) → pbl → ABL (fastboot)
→ boot / init_boot (kernel + ramdisk) → Android userspace
```
| Stage | Owner-controllable? | How |
|---|---|---|
| bootrom, bl1/bl2/bl31, pbl, **ABL/fastboot** | ❌ | bootrom-anchored to the OEM key; cannot be re-signed |
| **boot / init_boot / vendor_boot / recovery / vbmeta** | ✅ | **custom AVB key** (`avb_custom_key`) makes the owner the root of trust for these |
| Android userspace (adb, settings) | ✅ | root / WRITE_SECURE_SETTINGS |
**Key consequence:** you can become the verified-boot root of trust for
everything from `boot` upward, but **not** for the bootloader itself. So a
legitimately-signed, password-patched `fastboot` is impossible — the only way to
run modified ABL code is an exploit (see §5, §8).
## 5. Cryptographic reality (for the record)
- RSA-2048/4096 and ECDSA P-256 are **not broken** by any known classical
attack. Bootloader signing keys are in this range → **not forgeable.**
- What *is* real: factored **weak** RSA (≤829-bit, academic), **ECDSA nonce
reuse / bad RNG** (PS3, Bitcoin — implementation, not algorithm), **side-channel
/ fault-injection** bypasses of the *verification path*, and **future quantum**
(Shor's — no cryptographically-relevant quantum computer exists yet; NIST PQC
migration is pre-emptive).
- **Therefore:** defeating verified boot means attacking the *check*
(glitch / memory-corruption bug in the verifier or command parser), **not**
breaking the *key*. This is the premise of the research track (§8).
## 6. Defensive architecture — achievable, layered
Ordered so each layer builds on the one below it.
- **L0 — Foundation: custom AVB root of trust + re-lock.**
Generate an owner AVB key; build a **KSU-integrated** GKI `boot` image (baked
in, not LKM, so root survives lock); build a custom recovery; sign
boot/init_boot/vendor_boot/recovery/vbmeta with the owner key;
`fastboot flash avb_custom_key`; flash; **prove it boots**; then
`fastboot flashing lock`. *Delivers:* locked verified boot **with** root; ABL
fastboot becomes crypto-inert (refuses flash/boot/erase/unlock); recovery
cannot be swapped. **This is the linchpin — every other layer depends on it.**
- **L1 — Password-gated recovery.** Compile a secret gate into the signed
recovery ramdisk for the pre-decryption actions: **fastbootd**, ADB sideload,
factory reset. (fastbootd *is* "fastboot from inside recovery" — the piece the
owner actually controls.)
- **L2 — USB-when-locked cutoff + adb hard-off.** Deny USB data/enumeration
(charge-only) whenever the screen is locked — the single most Cellebrite-
relevant control (GrapheneOS's headline feature). Implement as a kernel module
(reuses the CellGuard build pipeline) or a root daemon on keyguard state.
adb defaults **off**; enabling is biometric/PIN-gated with an auto-off timeout.
- **L3 — Auto-reboot to BFU.** Root/KSU daemon reboots after N minutes locked,
evicting in-RAM keys → forces the hard BFU state, defeating AFU extraction.
- **L4 — Duress / honeypot.** Only meaningful once L0 is locked (else the
attacker boots their own image and skips it). Options:
- **Non-destructive decoy** — a duress credential boots a sterile decoy user
while the real user's keys stay underived.
- **Destructive** — duress credential (or repeated failures) evicts/wipes the
real keys.
- **Boot-context branch** — `init` inspects `androidboot.bootreason`/mode and
presents the decoy on abnormal boot.
- *Limit:* true deniability is weak on Android — FBE metadata reveals that
multiple users/volumes exist. Destructive duress is more reliable than a
deniable-hidden-volume approach.
- **L5 — Strong passphrase** (owner action). Converts lockscreen brute force
from "time + exploit" into a non-starter.
## 7. Honest limits (what will NOT work, and why)
- **Patching/signing ABL** — bootrom-anchored to the OEM key; a modified
bootloader can't be signed and won't boot. Only an *exploit* runs it (§8).
- **Hiding/redirecting the ABL fastboot key-combo** — the key combo is read by
the signed bootloader *before* any OS/recovery code; recovery can't intercept
it. The "TWRP forces you through recovery" trick (e.g., on the S20) relies on
a more malleable bootloader and the fact that Samsung has **no fastboot**
(Download/Odin + Knox instead). Not reproducible on Tensor.
- **Deniable hidden volumes** — FBE leaks the existence of multiple data sets.
- **Current unlocked bootloader** — negates most in-OS defenses until L0 re-lock,
because an attacker can just boot their own image.
## 8. Research track — ABL vulnerability research (authorized, own device)
Parallel to the defensive build. Premise (§5): attack the verification, not the
key. Assets already on hand: the **`rango` factory image** in
`~/PixelFlasher/dist/` (contains `bootloader-rango-*.img`) and existing **Ghidra**
projects under `seteclabs/rango-wifi-monitor`.
1. **Unpack** `bootloader-rango-*.img` → split the pack into stages
(bl1/bl2/bl31/pbl/ABL; Tensor uses a Samsung-style chain).
2. **Load ABL into Ghidra**; locate the fastboot dispatch (strings: `getvar`,
`download:`, `flash:`, `boot`, `oem `, `reboot-bootloader`).
3. **Audit the parser** for classic wins: unchecked lengths in
`download`/sparse-image handling, `oem` vendor commands (least-audited
surface), integer overflows in partition sizing.
4. **Firmware diffing** across bootloader versions — patched bugs point at the
interesting code and sometimes yield n-days.
5. **Hardware surface** (if pursued): identify UART/JTAG test points; assess the
voltage/EM **glitch** surface on the signature-check path (ChipWhisperer-class).
*Strategic note:* an ABL exploit is the attacker's own primitive and is fragile
(breaks/needs rework each firmware update). It should **not gate** the defensive
build — ship L0L3 for protection now, run the RE track in parallel.
## 9. Safety rig / escape hatch (mandatory before anything irreversible)
- Keep the **factory image `flash-all`** ready (`~/PixelFlasher/dist/`).
- Keep the bootloader **unlocked** and **OEM-unlocking enabled** until the signed
chain is proven to boot cleanly.
- **Dry-run the full sign → flash → boot cycle unlocked first**; confirm
`avbtool verify` passes against the owner key **before** ever typing
`fastboot flashing lock`.
- `flashing lock` is the **last** step; disable OEM-unlocking only after the
locked chain is proven stable.
- Prefer proving the sign/lock/escape-hatch loop on a **spare** device before the
daily driver.
## 10. Risk register
| Risk | Mitigation |
|---|---|
| Re-lock with a non-verifying image → hard brick | dry-run unlocked; `avbtool verify`; keep OEM-unlock until proven |
| OTA breaks the owner-signed chain | re-sign after each update; hold OTAs until pipeline is scripted |
| KSU integration regressions under lock | validate root + boot on unlocked build first |
| Duress deniability weaker than hoped | prefer destructive duress; document the limit |
| Losing the working session over wireless adb when disabling adb | attach USB fallback before testing the "off" path |
## 11. Roadmap / next actions
- **Phase 0:** prove the escape hatch (spare device and/or verified factory flash).
- **Phase 1 (reversible):** L0 foundation — AVB key + KSU-integrated signed boot;
flash and boot **unlocked** to validate; do **not** lock yet.
- **Phase 2:** L1 recovery gate + L2 USB-when-locked / adb hard-off.
- **Phase 3:** L3 auto-reboot-to-BFU + L4 duress/honeypot; then L0 `flashing lock`.
- **Parallel:** §8 ABL RE track (unpack `bootloader-rango-*.img` → Ghidra).
---
## Appendix A — current-state levers (verified this session)
```
settings get global adb_enabled -> 1 (USB debugging)
settings get global adb_wifi_enabled -> 1 (wireless debugging; current link)
getprop ro.adb.secure -> 1 (RSA host-key auth enforced)
/data/misc/adb/adb_keys -> 1 authorized host key
```
adb kill switch: `settings put global adb_enabled 0; settings put global
adb_wifi_enabled 0; setprop ctl.stop adbd`.
## Appendix B — related work in this project
- `common/kmod/cellguard.c` — kernel module; demonstrates the GKI build + load
path (protected-symbol resolution via kallsyms) reused by L2.
- `common/kmod/build-stock-gki.sh` — stock-GKI module build pipeline; the basis
for building the L0 KSU-integrated signed boot image.