Jason Turley's Website

Firmware Analysis Notes

These are my notes for firmware analysis. I will update them overtime as I learn more.

Basic questions to ask

[!NOTE] The commands below assume a Linux host. Most tools (binwalk, binutils, jefferson, checksec) are pre-installed on Kali Linux. For other distros, install them via your package manager or from source.

Commands and Tools

Initial Identification

Before extracting anything, profile the firmware blob itself.

// identify file type and magic bytes
file firmware.bin

// print human-readable strings (minimum 8 chars to reduce noise)
strings -n 8 firmware.bin | less

// hex dump — inspect the first 512 bytes for headers
xxd firmware.bin | head -32

// alternatively with hexdump
hexdump -C firmware.bin | head -32

// check entropy (high entropy = compressed or encrypted regions)
binwalk -E firmware.bin

// find interesting strings: URLs, IPs, credentials, keys
strings -n 8 firmware.bin | grep -Ei "http|ftp|password|passwd|admin|root|ssh|key|token"
strings -n 8 firmware.bin | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'

Extraction

binwalk is the primary tool for scanning and carving firmware images.

// scan file for signatures
binwalk firmware.bin

// scan for common file signatures with terminal formatting
binwalk --signature --term firmware.bin

// extract all recognized formats
binwalk -e firmware.bin

// recursively extract nested archives
binwalk -Me firmware.bin

// extract a raw region manually with dd (use decimal offset from binwalk output)
dd if=firmware.bin of=squashfs.bin bs=1 skip=<DECIMAL_OFFSET> count=<SIZE>

// extract SquashFS manually if binwalk fails
unsquashfs squashfs.bin

// extract JFFS2 flash filesystem images
jefferson jffs2.bin -d output_dir

// decompress a gzip blob
gunzip -c compressed.gz > decompressed.bin

[!NOTE] SquashFS is the most common filesystem in consumer router firmware. If binwalk -e produces a _firmware.extracted directory containing a squashfs-root folder, that is your extracted filesystem root.

Filesystem Exploration

After extraction, treat the filesystem root like a live Linux system. The goal is situational awareness: what is running, who can log in, and what credentials are baked in.

[!WARNING] Never run extracted firmware binaries directly on your host machine. Use a VM or an emulator like QEMU.

Orientation

// determine Linux kernel version from kernel modules
find . -name "*.ko" | head -5
strings ./lib/modules/*/*.ko 2>/dev/null | grep "vermagic"

// identify the init system
cat etc/inittab
ls etc/init.d/
ls etc/rc.d/ 2>/dev/null

// find the busybox binary (common in embedded Linux)
find . -name "busybox" 2>/dev/null
file ./bin/busybox

// list all installed binaries
ls -la bin/ sbin/ usr/bin/ usr/sbin/

Credentials

// user accounts and password hashes
cat etc/passwd
cat etc/shadow

// search for hardcoded passwords in config files
grep -irl "password" . --include="*.conf" --include="*.cfg" --include="*.xml" --include="*.json"
grep -ir "passwd\|password\|pass=" . --include="*.sh" 2>/dev/null

// search for private keys
grep -irl "BEGIN RSA PRIVATE KEY" .
grep -irl "BEGIN EC PRIVATE KEY" .
grep -irl "BEGIN OPENSSH PRIVATE KEY" .
find . -name "*.pem" -o -name "*.key" -o -name "*.crt" 2>/dev/null

// find .htpasswd files (web basic auth credentials)
find . -name ".htpasswd" 2>/dev/null

Network and Services

// web server config
ls -la etc/nginx/ etc/apache2/ etc/lighttpd/ etc/httpd/ 2>/dev/null

// web root
ls -la var/www/ srv/www/ 2>/dev/null

// look for CGI scripts (common attack surface in embedded web UIs)
find . -name "*.cgi" 2>/dev/null

// check for listening services configured via inetd/xinetd
cat etc/inetd.conf 2>/dev/null
cat etc/xinetd.conf 2>/dev/null
ls etc/xinetd.d/ 2>/dev/null

// SSH server configuration
cat etc/ssh/sshd_config 2>/dev/null

// find hardcoded IPs and URLs
grep -Ero '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' . 2>/dev/null | sort -u
grep -Erio 'https?://[a-zA-Z0-9./?=_%:-]+' . 2>/dev/null | sort -u

Startup and Persistence

// startup scripts
cat etc/inittab
ls -la etc/init.d/
cat etc/rc.local 2>/dev/null

// cron jobs
cat etc/crontab 2>/dev/null
ls etc/cron.d/ etc/cron.daily/ 2>/dev/null

// users and home directories
ls -latr home/
cat etc/group

// scripts in common locations
ls -l usr/local/bin
ls -l bin

Binary Analysis

Once you have the extracted filesystem, analyze individual binaries for security weaknesses.

File identification

// identify architecture and ELF type
file bin/busybox
file usr/sbin/httpd

// read ELF header (shows CPU architecture, endianness, entry point)
readelf -h usr/sbin/httpd

// display all sections
readelf -S usr/sbin/httpd

// list dynamic dependencies and imported symbols
readelf -d usr/sbin/httpd
readelf --syms usr/sbin/httpd

Security mitigations

// check for NX, RELRO, stack canaries, PIE
checksec --file=usr/sbin/httpd

// audit all ELF binaries at once
find . -type f -exec file {} \; 2>/dev/null | grep ELF | cut -d: -f1 | xargs -I{} checksec --file={}

// rabin2 equivalent (radare2 toolkit)
rabin2 -I usr/sbin/httpd

// check for RPATH issues (potential library hijacking)
rabin2 -l usr/sbin/httpd

Strings and disassembly

// dump all strings from a binary
strings -n 8 usr/sbin/httpd

// rabin2 strings with section context
rabin2 -z usr/sbin/httpd
rabin2 -zzz usr/sbin/httpd

// disassemble with objdump
objdump -d usr/sbin/httpd | less
objdump -D -M intel usr/sbin/httpd | less   // x86 only

// list symbol table
objdump -tT usr/sbin/httpd
nm -D usr/sbin/httpd 2>/dev/null

Dangerous function hunting

// scan all ELF binaries for dangerous C functions
find . -type f | xargs file 2>/dev/null | grep ELF | cut -d: -f1 | while read bin; do
    result=$(nm -D "$bin" 2>/dev/null | grep -E "strcpy|strcat|sprintf|gets|system|popen|exec")
    [ -n "$result" ] && echo "=== $bin ===" && echo "$result"
done

Tool Summary

ToolPurposeCommon flags
fileIdentify file type and architecture
stringsExtract readable strings from a binary-n 8 (min length)
xxd / hexdumpHex inspectionxxd -l 256 for first 256 bytes
binwalkSignature scan, entropy analysis, extraction-Me recursive extract, -E entropy
ddRaw binary carving by offsetbs=1 skip=<offset> count=<size>
unsquashfsExtract SquashFS images
jeffersonExtract JFFS2 images-d <output_dir>
readelfELF header, section, and symbol analysis-h, -S, -d, --syms
objdumpDisassembly and symbol tables-d, -D, -tT
checksecSecurity mitigation audit--file=<binary>
rabin2Multi-purpose binary info (radare2)-I, -z, -l, -i
nmSymbol listing-D for dynamic symbols
grepPattern search across filesystem-irl recursive, case-insensitive

Worked Example: Netgear WNAP320

Below is an example of extracting vmlinux.bin from the Netgear WNAP320 firmware.

$ binwalk vmlinux.gz.uImage

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x8B048C59, created: 2011-06-23 10:45:30, image size: 983040 bytes, Data Address: 0x80020000, Entry Point: 0x801F2000, data CRC: 0xC0C376EF, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: gzip, image name: "Linux Kernel"
64            0x40            gzip compressed data, has original file name: "vmlinux.bin", from Unix, last modified: 2011-06-23 10:45:30

The uImage header states that the firmware is Linux MIPS. If we want to get the exact version of the Linux Kernel, we will need to extract the gzip compressed vmlinux.bin data.

It is stored at offset 64, so use dd to extract it:

// save output to vmlinux.bin.gz
$ dd if=vmlinux.gz.uImage of=vmlinux.bin.gz bs=1 skip=64

$ gunzip vmlinux.bin.gz

Find the Linux Kernel version and GCC version

$ strings vmlinux.bin | grep "Linux version"
Linux version 2.6.23-WNAP320_V2.0.3 (root@build) (gcc version 4.2.4) #1 Thu Jun 23 16:06:18 IST 2011

Despite this Netgear Wireless Access Point being released in November 2015, it is using very old versions of the Linux kernel and gcc compiler. Linux kernel version 2.6.23 released in October 2007 and gcc 4.2.4 released in May 2008!

Further Resources

#cheatsheets #reversing #firmware