
The unglamorous truth of IoT security is that you rarely need an exploit. Honeypot telemetry published by Nozomi Networks shows the majority of recorded attack attempts against connected devices still rely on default or brute-forced credentials, the same I1 weakness the OWASP IoT Top 10 has listed for years. A smart lock with telnet open and the password admin/admin does not need a memory-corruption bug to fall over.
That said, the deep findings come from physically taking the device apart. This guide follows the five stages of a real IoT engagement: recon, firmware extraction and cracking, hardware access over serial and SPI, radio and protocol abuse, and reporting that maps everything back to the OWASP IoT Top 10. Each stage shows the actual tool output you would capture and the line that tells you the device is compromised.
An IoT penetration test assesses the device as a complete system: its network services, web and mobile management interfaces, cloud APIs, firmware, hardware debug interfaces, and wireless radios. The interesting bugs sit where two layers meet, for example a cloud API that trusts a device identity you can clone out of dumped firmware. Because the firmware and silicon are physically in your hands, IoT work is unusually white-box compared with other types of penetration testing.
It pulls in several disciplines at once: web and API testing against the management plane, mobile testing against the companion app (close to our mobile app penetration testing work), plus hardware and RF analysis that has no software equivalent. The methodology below moves outside-in, from what an internet attacker sees to what someone with the board on a bench can extract.
The OWASP IoT Top 10 is the reference baseline that frames scope and lets a client compare against the industry. It opens with I1 weak, guessable, or hardcoded passwords, which remain the single most exploited issue, followed by I2 insecure network services and I3 insecure web, backend, and mobile interfaces. The list runs through I4 lack of secure update, I5 outdated components, and down to I10 lack of physical hardening, which is exactly what serial and SPI access exploit.
Mapping each finding to an item does real work in the report: it tells the client whether a problem is a one-off or a systemic gap, and it connects the hardware-level issues most teams ignore to a named, defensible category. The three that carry most engagements:
Firmware analysis starts before you touch the device: pull the image from the vendor's update server or support download, then carve it open with binwalk. The -e flag identifies and extracts embedded filesystems (usually SquashFS or JFFS2) and bootloaders in one pass:
$ binwalk -e firmware.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------
0 0x0 uImage header, kernel 3.10.14
1490944 0x16C800 Squashfs filesystem, little endian, 4.0 <- root fs starts here
$ cd _firmware.bin.extracted/squashfs-rootInside the filesystem you hunt the same secrets as any code review: credentials, private keys, API endpoints, backdoor accounts, and outdated binaries with known CVEs. The highest-impact move is grepping the password hash out of /etc/shadow and feeding it to hashcat, because the recovered password is almost always reused fleet-wide:
$ grep root etc/shadow
root:$1$xyz$Hk9c0/9q8mZ3yQ2pL.:18000:0:99999:7::: <- MD5-crypt ($1$) hash
$ hashcat -m 500 root.hash rockyou.txt
$1$xyz$Hk9c0/9q8mZ3yQ2pL.:Admin@123 <- cracked in seconds
Session..........: Recovered
Status...........: CrackedThe $1$ prefix is MD5-crypt, weak enough that hashcat recovers it almost instantly. The lesson clients hate: that one password logs into every device they ever shipped. Automated firmware scanners like EMBA will flag the weak hash and outdated busybox, but the chained insight (this hash is the SSH login for the whole fleet) is human work, the kind of judgment we discuss in our automated versus manual penetration testing comparison.
UART is the fastest path to a shell on a device whose firmware you cannot download. It is a serial console, usually a 4-pin header or test pads exposing VCC, GND, TX, and RX. Identify the pins with a multimeter, wire only TX, RX, and GND to a 3.3V USB-to-TTL adapter (never VCC), and attach a terminal at the common baud rate:
$ screen /dev/ttyUSB0 115200
U-Boot 2016.05 (Jan 02 2020)
Hit any key to stop autoboot: 0 <- press a key here to interrupt
=> setenv bootargs ${bootargs} init=/bin/sh <- skip init, drop straight to a shell
=> boot
...
/ # id
uid=0(root) gid=0(root) <- root, no password prompt at allThe decisive moment is interrupting autoboot at the U-Boot prompt and appending init=/bin/sh to the kernel arguments. The kernel boots straight to a root shell and never runs the login process, so the password you cracked earlier is not even needed. If the console drops you into a Linux login instead, that cracked /etc/shadow password is your way in. JTAGulator helps locate unlabeled JTAG pads when UART is disabled, and JTAG gives you raw CPU debug access to read and write memory directly.
When UART and JTAG are disabled, you read the storage chip directly. Most IoT devices keep firmware on an external SPI flash (commonly a Winbond 25-series in an SOIC-8 package), and flashrom driving a cheap programmer reads the whole image even when the vendor never published one. Attach an SOIC-8 test clip so you avoid desoldering, wire it to a CH341A or Bus Pirate, and read the chip twice so you can prove a clean capture:
$ flashrom -p ch341a_spi -r dump1.bin
Found Winbond flash chip "W25Q64.V" (8192 kB, SPI).
Reading flash... done.
$ flashrom -p ch341a_spi -r dump2.bin
$ sha256sum dump1.bin dump2.bin
9f2a... dump1.bin
9f2a... dump2.bin <- hashes match, dump is clean
$ binwalk -e dump1.bin # back into the firmware workflow aboveIdentical SHA-256 hashes confirm the read was clean. This matters because if the board still powers the chip during the read, the main CPU contends for the bus and you get a non-deterministic, garbage dump. Holding the CPU in reset, or desoldering the chip onto an adapter, isolates it. Once dumped, the image flows straight back into the binwalk and hashcat workflow above.
Wireless testing covers Wi-Fi, BLE, Zigbee, and sub-GHz bands like 433 MHz, and the classic finding is an unauthenticated replay: capture the signal a remote sends, retransmit it, and trigger the action with no rolling code. A cheap RTL-SDR plus rtl_433 decodes most sub-GHz sensors and remotes, while Universal Radio Hacker handles analysis and replay. At the application layer, MQTT is the protocol I find exposed most often, and an anonymous wildcard subscribe frequently dumps every device's telemetry and commands at once:
$ mosquitto_sub -h 192.168.1.10 -t '#' -v
home/lock/livingroom/state locked <- every device, no auth required
home/lock/livingroom/battery 84
home/cam/garage/stream rtsp://192.168.1.42:554/h264
fleet/device/AC32F1/token eyJhbGciOiJIUzI1... <- session tokens on the wire
$ mosquitto_pub -h 192.168.1.10 -t 'home/lock/livingroom/cmd' -m 'unlock' # writes open tooThe wildcard # subscribing with no credentials and returning live state for every device is the finding: the broker has no authentication and no topic ACLs. If publish is also open, you command devices directly. The fix is config-level: set allow_anonymous false in mosquitto.conf, require per-device credentials, and enforce topic ACLs so a compromised device cannot read the whole fleet's traffic.
Report each finding against the layer it lives on, the OWASP IoT Top 10 item it maps to, and the access level it requires, because access level drives real-world risk. A root shell over UART matters less on a device sealed in a locked enclosure than a remotely reachable, unauthenticated MQTT broker does. State that distinction explicitly so the client prioritizes correctly.
Rate by blast radius. A hardcoded TLS key, a reused root password, or an open broker affects every shipped unit, not one device, which is what makes these the critical findings. Where the same bug recurs across firmware versions, the durable fix is process-level: a signed, authenticated secure-update pipeline (closing I4) so fixes can actually ship, plus per-device unique credentials and keys provisioned at manufacture. For organizations running large fleets, this folds into continuous validation rather than a one-time test, the model we cover in our DAST versus pentesting versus agentic pentesting guide.