Skip to main content

firmware-acquisition

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.

설치로 이동

소스 정보

저장소
BitterSecurity/Decepticon
최근 소스 활동
2026년 5월 30일 11:59
감지된 SKILL.md 언어
영어
스타
5,565
포크
1,053

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
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 ```bash # Check common firmware CDN patterns curl -sI "https://firmware.vendor.com/latest/<model>.bin" curl -sI "https://downloads.vendor.com/firmware/<model>/<version>.tar.gz" # Scrape firmware release page for direct links wget -r -l1 -nd -A "*.bin,*.tar.gz,*.zip,*.img" \ "https://www.vendor.com/support/firmware/<model>" # Checksum-verify before unpacking sha256sum <fw.bin> ``` ### 0b. OTA interception (MITM the device's update check) ```bash # 1. ARP-spoof the device to route its traffic through your machine sudo arpspoof -i eth0 -t <device_ip> <gateway_ip> & sudo arpspoof -i eth0 -t <gateway_ip> <device_ip> & # 2. Forward all traffic except OTA traffic; intercept OTA with mitmproxy 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 # 3. Trigger an OTA check from the device (power cycle or companion app) # 4. Inspect intercepted traffic; export firmware binary mitmdump -r /tmp/ota_capture.mitm -w /tmp/ota_fw.bin \ --set flow_detail=3 '~t application/octet-stream or ~t application/x-gzip' # 5. Decrypt if AES-encrypted OTA (key often in companion app resources) 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 ```bash # APK often bundles the firmware binary or partial images 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). ``` ```bash # Baud-rate autoprobe with sigrok / baudrate.py python3 baudrate.py /dev/ttyUSB0 # https://github.com/devttys0/baudrate # Or with screen – step through common rates 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 ```bash # Connect: GND → GND, RX(USB) → TX(device), TX(USB) → RX(device) screen /dev/ttyUSB0 115200 # Power on device; press any key within 1-3s to break into U-Boot # At U-Boot prompt: locate kernel + rootfs partition offsets => printenv => mtdparts # shows flash map (e.g. 0x00000000 kernel 0x200000, rootfs 0x600000) # Dump via XMODEM to host => loady 0x80000000 # load address in RAM => md.b 0x80000000 0x200000 # memory-display: prints hex to terminal # Capture terminal output → convert hex dump → binary: 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 ```bash # If U-Boot has tftp + nand/sf commands: => setenv ipaddr 192.168.1.100 => setenv serverip 192.168.1.10 => sf probe; sf read 0x80000000 0x0 0x1000000 # read 16MB SPI NOR into RAM => tftp 0x80000000 flash_full.bin # upload to your tftp server # On your host: python3 -m py3tftp -p 69 --ip 0.0.0.0 ``` --- ## Tier 2 — JTAG / SWD Debug Interface ### 2a. OpenOCD + J-Link SWD dump (ARM Cortex-M) ```bash openocd -f interface/jlink.cfg -f target/stm32f4x.cfg \ -c "init; halt; dump_image /tmp/flash.bin 0x08000000 0x100000; shutdown" # Adjust start address and size per datasheet (STM32F4: 1 MB @ 0x08000000) ``` ### 2b. JTAG boundary-scan enumeration (MIPS/ARM application processors) ```bash # UrJTAG or JTAGulator to identify IR length + IDCODE jtag> cable jtagkey jtag> detect jtag> print chain # Identify MIPS/ARM AP; attach GDB via OpenOCD gdb-multiarch vmlinux (gdb) target remote :3333 (gdb) monitor halt (gdb) dump binary memory /tmp/mem.bin 0x80000000 0x90000000 # DRAM range ``` ### 2c. JTAG boundary-scan via eBBoot / Segger ```bash # Segger J-Flash CLI for known targets: 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) ```bash # Connect SOIC-8 clip to CH341A programmer # Identify chip: run flashrom probe first sudo flashrom -p ch341a_spi --verbose 2>&1 | grep -E "Found|Matched|chip" # Dump (use the exact chip name from probe output) sudo flashrom -p ch341a_spi -c "MX25L12835F" -r /tmp/flash_dump.bin sudo flashrom -p ch341a_spi -c "MX25L12835F" -r /tmp/flash_dump2.bin # Verify both reads match (disk corruption / clip contact issue otherwise) 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 ```bash # For SPI NAND (Winbond W25Nxxxx), use nandwrite flow: # 1. Use flashrom with serprog (Raspberry Pi as SPI master): sudo flashrom -p serprog:dev=/dev/ttyUSB0:4000000 -c "W25N01GV" -r /tmp/nand.bin # 2. Extract with nanddump equivalent for raw bin: binwalk -e /tmp/nand.bin # handles OOB stripping for most NAND dumps ``` --- ## 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 ```bash # Identify device node (dmesg after plugging in) dmesg | tail -20 | grep sd lsblk -d /dev/sdb # confirm size matches eMMC spec # Full raw dump 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 # Partition inspection fdisk -l /tmp/emmc_full.img file /tmp/emmc_full.img # Mount individual partition (offset in sectors from fdisk output) sudo mount -o loop,offset=$((512*2048)) /tmp/emmc_full.img /mnt/emmc_p1 ``` --- ## Evidence Store all artifacts under `/workspace/evidence/iot/<target>/firmware/`: ```bash 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 # Log acquisition method and hardware used 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/`
GitHub에서 보기