# 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 ` 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 L0–L3 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.