write-up: IoT/Anesthesia_Gateway/README.md
This commit is contained in:
parent
a45c1af0e1
commit
81798e6dbd
@ -1,72 +1,142 @@
|
||||
# Anesthesia Gateway -- Solution
|
||||
# Anesthesia Gateway
|
||||
|
||||
## Overview
|
||||
MQTT broker simulating an anesthesia monitoring gateway. A debug topic leaks
|
||||
an encoded firmware blob. Reverse the encoding to extract a maintenance key
|
||||
and publish it to unlock the flag.
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Category | IoT |
|
||||
| Difficulty | Medium-Hard |
|
||||
| Points | 500 |
|
||||
| Author | Eun0us |
|
||||
| CTF | Espilon 2026 |
|
||||
|
||||
## Steps
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
The anesthesia monitoring gateway in Operating Room 13 at Clinique Sainte-Mika is
|
||||
broadcasting live data over MQTT.
|
||||
|
||||
Something unusual is being transmitted on the network. The contractor left a debug
|
||||
channel open.
|
||||
|
||||
Connect to the MQTT broker and investigate.
|
||||
|
||||
- MQTT Broker: `tcp/<host>:1883`
|
||||
|
||||
Format: **ESPILON{flag}**
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
Subscribe to the MQTT wildcard topic `sainte-mika/#`. Find the debug firmware topic
|
||||
publishing a base64-encoded blob every 45 seconds. Reverse the encoding chain
|
||||
(base64 → XOR with key `WIRED` → zlib decompress → JSON) to extract the maintenance key
|
||||
`N4V1-C4R3-0R13-L41N`. Publish it to the unlock topic to receive the flag.
|
||||
|
||||
---
|
||||
|
||||
## Tools
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `mosquitto_sub` / `mosquitto_pub` | MQTT client |
|
||||
| Python 3 | Decode base64, XOR, zlib, JSON |
|
||||
|
||||
---
|
||||
|
||||
## Solution
|
||||
|
||||
### Step 1 — Connect and discover topics
|
||||
|
||||
### 1. Connect and discover topics
|
||||
```bash
|
||||
mosquitto_sub -h HOST -t "sainte-mika/#" -v
|
||||
mosquitto_sub -h <HOST> -t "sainte-mika/#" -v
|
||||
```
|
||||
|
||||
> 📸 `[screenshot: mosquitto_sub output listing all discovered topics and their messages]`
|
||||
|
||||
Topics discovered:
|
||||
- `sainte-mika/or13/vitals` -- patient vital signs (JSON)
|
||||
- `sainte-mika/or13/sevoflurane` -- anesthetic gas data
|
||||
- `sainte-mika/or13/propofol` -- infusion pump data
|
||||
- `sainte-mika/or13/ventilator` -- mechanical ventilator data
|
||||
- `sainte-mika/or13/alarms` -- alarm status (note: `"network": "WIRED-MED"`)
|
||||
- `sainte-mika/or13/debug/firmware` -- **base64-encoded blob (every 45s)**
|
||||
|
||||
### 2. Capture firmware blob
|
||||
Grab the base64 string from `debug/firmware`.
|
||||
| Topic | Content |
|
||||
|-------|---------|
|
||||
| `sainte-mika/or13/vitals` | Patient vital signs (JSON) |
|
||||
| `sainte-mika/or13/sevoflurane` | Anesthetic gas data |
|
||||
| `sainte-mika/or13/propofol` | Infusion pump data |
|
||||
| `sainte-mika/or13/ventilator` | Ventilator data |
|
||||
| `sainte-mika/or13/alarms` | Alarm status — note `"network": "WIRED-MED"` |
|
||||
| `sainte-mika/or13/debug/firmware` | **Base64 blob, published every 45s** |
|
||||
|
||||
### 3. Decode the blob
|
||||
The encoding chain is: JSON -> zlib -> XOR("WIRED") -> base64
|
||||
### Step 2 — Capture the firmware blob
|
||||
|
||||
Wait for a message on `debug/firmware` (up to 45 seconds). Save the base64 string.
|
||||
|
||||
Note the `"network": "WIRED-MED"` in the alarms topic — this is the XOR key hint.
|
||||
|
||||
> 📸 `[screenshot: debug/firmware topic publishing the base64-encoded blob]`
|
||||
|
||||
### Step 3 — Reverse the encoding chain
|
||||
|
||||
The chain is: `base64 → XOR("WIRED") → zlib → JSON`
|
||||
|
||||
To reverse:
|
||||
```python
|
||||
import base64, zlib
|
||||
import base64, zlib, json
|
||||
|
||||
blob = "<base64 string from MQTT>"
|
||||
blob = "<base64 string from debug/firmware>"
|
||||
|
||||
# Step 1: base64 decode
|
||||
raw = base64.b64decode(blob)
|
||||
|
||||
# XOR with key "WIRED" (hint: WIRED-MED appears in alarm data)
|
||||
# Step 2: XOR with key "WIRED"
|
||||
key = b"WIRED"
|
||||
xored = bytes(b ^ key[i % len(key)] for i, b in enumerate(raw))
|
||||
|
||||
# After XOR, bytes start with 78 9C (zlib magic)
|
||||
config = zlib.decompress(xored)
|
||||
print(config.decode())
|
||||
# Verify: first two bytes after XOR should be 0x78 0x9C (zlib magic)
|
||||
assert xored[:2] == b'\x78\x9C', "Key is wrong — magic bytes don't match"
|
||||
|
||||
# Step 3: zlib decompress
|
||||
decompressed = zlib.decompress(xored)
|
||||
|
||||
# Step 4: parse JSON
|
||||
config = json.loads(decompressed.decode())
|
||||
print(config)
|
||||
```
|
||||
|
||||
### 4. Extract maintenance key
|
||||
> 📸 `[screenshot: Python script printing the decoded JSON configuration]`
|
||||
|
||||
### Step 4 — Extract the maintenance key
|
||||
|
||||
The decoded JSON contains:
|
||||
|
||||
```json
|
||||
{
|
||||
"maintenance_key": "N4V1-C4R3-0R13-L41N"
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Publish key and get flag
|
||||
The key is a leetspeak encoding of "Navi Care OR13 Lain".
|
||||
|
||||
### Step 5 — Publish the key and get the flag
|
||||
|
||||
```bash
|
||||
mosquitto_pub -h HOST -t "sainte-mika/or13/maintenance/unlock" -m "N4V1-C4R3-0R13-L41N"
|
||||
mosquitto_pub -h <HOST> -t "sainte-mika/or13/maintenance/unlock" -m "N4V1-C4R3-0R13-L41N"
|
||||
```
|
||||
|
||||
Subscribe to the flag topic:
|
||||
|
||||
```bash
|
||||
mosquitto_sub -h HOST -t "sainte-mika/or13/maintenance/flag"
|
||||
mosquitto_sub -h <HOST> -t "sainte-mika/or13/maintenance/flag"
|
||||
```
|
||||
|
||||
> 📸 `[screenshot: flag topic publishing the ESPILON flag after unlock]`
|
||||
|
||||
### Key insights
|
||||
- The XOR key "WIRED" is discoverable from the alarm topic which includes `"network": "WIRED-MED"`
|
||||
- After XOR decryption, the zlib magic bytes `78 9C` confirm the correct key
|
||||
- The maintenance key "N4V1-C4R3-0R13-L41N" = "Navi Care OR13 Lain" in leetspeak
|
||||
|
||||
- The XOR key `WIRED` is derivable from the alarms topic which includes `"network": "WIRED-MED"`
|
||||
- After XOR decryption, the zlib magic bytes `0x78 0x9C` confirm the correct key
|
||||
- MQTT wildcard subscription `#` enumerates all topics in one command
|
||||
- An open MQTT broker with no authentication is a real-world IoT misconfiguration
|
||||
|
||||
---
|
||||
|
||||
## Flag
|
||||
`ESPILON{mQtt_g4tw4y_4n3sth3s14}`
|
||||
|
||||
## Author
|
||||
Eun0us
|
||||
`ESPILON{mQtt_g4tw4y_4n3sth3s14}`
|
||||
|
||||
Loading…
Reference in New Issue
Block a user