| name | firmware-acquisition |
| description | Systematic firmware extraction from IoT and embedded targets — vendor portals, OTA interception, SPI flash dumping with flashrom/CH341A, eMMC chip-off, and UART/JTAG console dumps. Covers the full acquisition chain from zero hardware access to a raw binary ready for static analysis. |
| allowed-tools | Bash Read Write |
| metadata | {"subdomain":"iot","when_to_use":"firmware dump, SPI flash, eMMC chip-off, UART dump, JTAG dump, OTA capture, flashrom, CH341A, vendor firmware portal, firmware extraction, flash read","tags":"iot, firmware, spi, emmc, uart, jtag, flashrom, ch341a, ota, acquisition, embedded","mitre_attack":"T1542, T1601, T1592.002"} |
Firmware Acquisition
Acquire a binary image of the target's firmware before any static analysis.
Work through the acquisition tiers in order — cheapest and least invasive first.
Each tier degrades hardware less and preserves the device's operational state.
Prerequisites
- Device PCB photographed (top + bottom). Mark: SoC part number, flash chip marking,
debug pad pattern (UART = 4-pin row; JTAG = TAP header or test points).
- Identify flash type from silkscreen or datasheet: SPI NOR (SOIC-8/WSON), SPI NAND,
eMMC (BGA-153/169), parallel NOR/NAND.
- Bench tools staged: CH341A programmer + SOIC-8 clip, BusPirate / J-Link / SEGGER
J-Trace, USB-UART adapter (CP2102 / FT232), multimeter for UART baud sniffing.
Tier 0 — Vendor Portal / OTA Proxy (no hardware needed)
0a. Vendor download portal
curl -sI "https://firmware.vendor.com/latest/<model>.bin"
curl -sI "https://downloads.vendor.com/firmware/<model>/<version>.tar.gz"
wget -r -l1 -nd -A "*.bin,*.tar.gz,*.zip,*.img" \
"https://www.vendor.com/support/firmware/<model>"
sha256sum <fw.bin>
0b. OTA interception (MITM the device's update check)
sudo arpspoof -i eth0 -t <device_ip> <gateway_ip> &
sudo arpspoof -i eth0 -t <gateway_ip> <device_ip> &
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8080
mitmproxy --mode transparent --set ssl_insecure=true -w /tmp/ota_capture.mitm
mitmdump -r /tmp/ota_capture.mitm -w /tmp/ota_fw.bin \
--set flow_detail=3 '~t application/octet-stream or ~t application/x-gzip'
openssl enc -d -aes-128-cbc -K <hex_key> -iv <hex_iv> -in /tmp/ota_fw.bin -out /tmp/fw_plain.bin
0c. Companion-app embedded firmware
apktool d companion.apk -o companion_decompiled/
find companion_decompiled/ -name "*.bin" -o -name "*.fw" -o -name "*.img" | xargs file
grep -r "firmware\|update\|download\|cdn" companion_decompiled/assets/ --include="*.js"
Tier 1 — UART Console Dump
UART is the fastest hardware path: non-destructive, works while device is powered.
1a. Identify UART pins
Typical 4-pin UART header: VCC | GND | TX | RX
Probe each with multimeter (DC, 3.3 V idle = TX candidate).
Baud detect: minicom -D /dev/ttyUSB0 -b 115200 (try 9600, 57600, 115200, 460800).
python3 baudrate.py /dev/ttyUSB0
for baud in 9600 19200 38400 57600 115200 230400 460800 921600; do
echo "Testing $baud..."; screen /dev/ttyUSB0 $baud; done
1b. Interrupt boot and dump from U-Boot
screen /dev/ttyUSB0 115200
=> printenv
=> mtdparts
=> loady 0x80000000
=> md.b 0x80000000 0x200000
python3 -c "
import sys, re
data = open('uart_hexdump.txt').read()
chunks = re.findall(r':\s+((?:[0-9a-fA-F]{8} ){1,4})', data)
raw = bytes.fromhex(''.join(''.join(c.split()) for c in chunks))
open('fw_from_uart.bin','wb').write(raw)"
1c. Full flash dump via UART + tftp
=> setenv ipaddr 192.168.1.100
=> setenv serverip 192.168.1.10
=> sf probe; sf read 0x80000000 0x0 0x1000000
=> tftp 0x80000000 flash_full.bin
Tier 2 — JTAG / SWD Debug Interface
2a. OpenOCD + J-Link SWD dump (ARM Cortex-M)
openocd -f interface/jlink.cfg -f target/stm32f4x.cfg \
-c "init; halt; dump_image /tmp/flash.bin 0x08000000 0x100000; shutdown"
2b. JTAG boundary-scan enumeration (MIPS/ARM application processors)
jtag> cable jtagkey
jtag> detect
jtag> print chain
gdb-multiarch vmlinux
(gdb) target remote :3333
(gdb) monitor halt
(gdb) dump binary memory /tmp/mem.bin 0x80000000 0x90000000
2c. JTAG boundary-scan via eBBoot / Segger
JFlash -openprj target.jflash -readchip /tmp/flash_full.bin -exit
Tier 3 — SPI NOR Flash Dump (CH341A + flashrom)
Most cost-effective hardware method for 8-pin SPI NOR chips.
3a. In-circuit dump (device powered off, clip attached)
sudo flashrom -p ch341a_spi --verbose 2>&1 | grep -E "Found|Matched|chip"
sudo flashrom -p ch341a_spi -c "MX25L12835F" -r /tmp/flash_dump.bin
sudo flashrom -p ch341a_spi -c "MX25L12835F" -r /tmp/flash_dump2.bin
sha256sum /tmp/flash_dump.bin /tmp/flash_dump2.bin
cmp /tmp/flash_dump.bin /tmp/flash_dump2.bin && echo "MATCH" || echo "MISMATCH — re-seat clip"
3b. Troubleshooting in-circuit reads
Symptom: flashrom sees 0x00 or 0xFF → chip held in reset by SoC pull-downs.
Fix: power-cycle with clip attached BEFORE the SoC powers up (race the SoC).
Or: locate HOLD# / WP# pins, tie to VCC; CS# must go low only from CH341A.
If SoC fights the bus: desolder for Tier 4.
3c. SPI NAND / eMMC alternative: python-flashrom / serprog
sudo flashrom -p serprog:dev=/dev/ttyUSB0:4000000 -c "W25N01GV" -r /tmp/nand.bin
binwalk -e /tmp/nand.bin
Tier 4 — eMMC Chip-Off
Last resort: BGA desoldering, direct eMMC reader. Destructive to PCB.
4a. Chip-off procedure
1. Hot-air rework (350 °C, 60 L/min): heat BGA from below; lift with vacuum.
2. Clean pads with flux + wick.
3. Reflow eMMC onto BGA breakout board (eMMC adapter):
- SD-to-eMMC: Allwinner eMMC reader, Emuelec adapter, or custom PCB.
4. Insert into card reader that supports eMMC protocol.
4b. Dump with dd / usbimager
dmesg | tail -20 | grep sd
lsblk -d /dev/sdb
sudo dd if=/dev/sdb of=/tmp/emmc_full.img bs=512 status=progress conv=noerror,sync
sha256sum /tmp/emmc_full.img > /tmp/emmc_full.img.sha256
fdisk -l /tmp/emmc_full.img
file /tmp/emmc_full.img
sudo mount -o loop,offset=$((512*2048)) /tmp/emmc_full.img /mnt/emmc_p1
Evidence
Store all artifacts under /workspace/evidence/iot/<target>/firmware/:
mkdir -p /workspace/evidence/iot/<target>/firmware
cp /tmp/flash_dump.bin /workspace/evidence/iot/<target>/firmware/flash_full.bin
sha256sum /workspace/evidence/iot/<target>/firmware/flash_full.bin \
> /workspace/evidence/iot/<target>/firmware/flash_full.bin.sha256
echo "Acquired via: CH341A + SOIC-8 clip; flashrom 1.4.0; chip: MX25L12835F" \
> /workspace/evidence/iot/<target>/firmware/acquisition.log
OPSEC Notes
- In-circuit clips can corrupt firmware if contact is intermittent — always compare
two reads before treating the image as canonical.
- OTA MITM is logged server-side; only perform on isolated test-lab networks unless
RoE explicitly permits production intercept.
- JTAG debug may trigger internal tamper fuses on hardened targets (e.g., Qualcomm
secure boot with JTAG-disable eFuse). Read the SoC TRM before probing.
- eMMC RPMB partition requires authentication key to read — skip on initial triage;
flag for key extraction if bootloader secrets are needed.
References
- flashrom supported hardware:
https://flashrom.org/Supported_hardware
- CH341A pinout + SOIC clip wiring:
references/ch341a-soic-wiring.md
- U-Boot command reference:
https://u-boot.readthedocs.io/en/latest/usage/index.html
- OpenOCD target configs:
/usr/share/openocd/scripts/target/