finding-brokers
practicalL2 — Finding Exposed Brokers
Internet-exposed MQTT brokers number in the tens of thousands. Shodan has indexed them continuously since port 1883 became a reliable attack surface. This lesson covers the tooling to find them and identify their configurations before connecting.
Shodan
Shodan crawls the internet continuously, connecting to open ports and recording banners. For MQTT on port 1883, it performs an actual MQTT CONNECT and records the broker's response including version strings.
Working Queries
port:1883 MQTT
This is the baseline. Returns every host Shodan has indexed on port 1883 that responded with MQTT-formatted data. As of writing, typically 50,000–90,000 results.
port:1883 "mosquitto"
Narrows to Mosquitto brokers — the version string appears in the banner. The result count is lower but the targets are more likely to be default-configured (and therefore unauthenticated).
port:1883 country:FR
Geographic filter. Useful for scoping to a jurisdiction for legal testing. Combine with organization filters for CTF-style reconnaissance.
port:1883 org:"Amazon"
Finds AWS-hosted brokers. These are less likely to be misconfigured but the result set is useful for identifying AWS IoT Core endpoints exposed on non-standard configurations.
port:1883 "Connection Refused"
Inverted query — finds brokers that rejected the Shodan crawler's connection. Still useful for mapping topology even if auth is required.
Reading a Shodan MQTT Result
A typical Shodan result for an open Mosquitto broker:
Port: 1883
Banner:
MQTT
Version: 3.1.1
Server: mosquitto version 1.6.9
The version number is actionable. Cross-reference with:
- Mosquitto CVE list
- Mosquitto 1.x before 1.6.12 — CVE-2021-28166 (memory leak via malformed SUBSCRIBE)
- Mosquitto before 2.0.12 — CVE-2021-34432 (crash via invalid retained message)
- Any Mosquitto 1.4.x — extremely outdated, EOL, no patches since 2018
Version enumeration from Shodan alone can tell you whether a broker is unpatched before you connect to it.
Nmap
Nmap has an MQTT-specific script in its default script library. Use it when you have a specific target rather than broad discovery.
Version Detection
nmap -sV -p 1883,8883 <target>
This attempts service fingerprinting. On port 1883, Nmap will identify the service as MQTT and often extract the broker name and version. Output example:
1883/tcp open mqtt Mosquitto mqttd 2.0.14
8883/tcp open ssl/mqtt Mosquitto mqttd 2.0.14
MQTT Subscribe Script
nmap -p 1883 --script mqtt-subscribe <target>
The mqtt-subscribe script connects to the broker, subscribes to #, and records any messages received during a short window. The output includes topic names and payloads — all from a single Nmap command. Example output:
PORT STATE SERVICE
1883/tcp open mqtt
| mqtt-subscribe:
| Topic: home/living_room/temperature
| 22.4
| Topic: home/alarm/armed
| false
| Topic: device/shelly1/status
|_ {"wifi_sta":{"connected":true},"cloud":{"enabled":false}}
This is reconnaissance gold. You haven't written anything to the broker — this is passive listening.
# Increase timeout to catch more messages
nmap -p 1883 --script mqtt-subscribe --script-args mqtt-subscribe.timeout=15 <target>
Default Ports and What They Tell You
| Port | Meaning | Action |
|---|---|---|
| 1883 open | Plaintext MQTT | Try anonymous connect immediately |
| 8883 open | TLS MQTT | Check cert validity; TLS doesn't mean auth |
| 9001 open | WebSocket MQTT | Browser-accessible; look for web dashboards |
| 1883 + 9001 open | Dual exposure | WebSocket often has separate, weaker ACL |
Port 9001 (WebSocket transport) deserves special attention. Many Mosquitto deployments enable WebSocket for browser-based dashboards but configure it with looser ACLs, or forget to require auth on the WebSocket listener while requiring it on the raw MQTT listener.
Mosquitto config that creates this split:
# TCP listener — auth required
listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd
# WebSocket listener — auth forgotten
listener 9001
protocol websockets
allow_anonymous true
This exact misconfiguration appears in the wild regularly.
mqttx CLI
mqttx is a modern, cross-platform MQTT client from EMQX. It handles MQTT 3.1, 3.1.1, and 5.0, supports TLS, WebSocket, and has clean error output — which makes it better than mosquitto_sub for scripted testing where you need to distinguish auth failure from network error.
Installation
# npm
npm install -g mqttx-cli
# or download binary from https://mqttx.app/cli
Testing Connectivity
# Attempt anonymous connection, immediately disconnect
mqttx conn -h <broker> -p 1883
# With explicit MQTT version
mqttx conn -h <broker> -p 1883 --mqtt-version 3.1.1
Successful connection output:
✔ Connected
Auth failure output:
✖ Connection failed: Connection refused: Not authorized
Network failure output:
✖ Connection failed: connect ECONNREFUSED <ip>:1883
The distinction matters. "Not authorized" means the broker is running and rejecting unauthenticated connections — worth brute-forcing credentials. "ECONNREFUSED" means firewall or the port isn't open — skip it.
Subscribe Test
# Subscribe to all topics, print first 10 messages
mqttx sub -h <broker> -p 1883 -t "#" --output-mode clean
Banner Analysis Workflow
When you find a broker, this is the sequence:
- Record the version from Shodan or
nmap -sV - Check CVEs for that version
- Attempt anonymous connect —
mqttx conn -h <target> -p 1883 - If connected, subscribe to
#—mosquitto_sub -h <target> -t "#" -v - Check port 9001 —
mqttx conn -h <target> -p 9001 --protocol ws - Check port 8883 — note: TLS doesn't imply auth
The version string also tells you the deployment era. Mosquitto 1.4.x was released around 2015. A broker running 1.4.x hasn't been updated in nearly a decade — its configuration is almost certainly the default from whatever tutorial installed it.
Scope and Legal Notes
Shodan returns public data only — it shows what is internet-accessible. The discovery phase (Shodan queries) is passive and legal. Connecting to a broker you don't own crosses into active testing territory. For this course, all active testing is performed against:
- Your own lab infrastructure
- Explicitly provided challenge containers
- Systems you have written authorization to test
Shodan reconnaissance against real targets is for the discovery skill, not for unauthorized access.
Key Takeaways
port:1883 "mosquitto"on Shodan surfaces thousands of targets- Version strings from banners map directly to CVE databases
nmap --script mqtt-subscribeperforms passive recon in one command- Port 9001 (WebSocket) often has weaker auth than port 1883
- Distinguish "not authorized" from "connection refused" — they require different next steps