write-up: IoT/Observe_The_Wired/README.md
This commit is contained in:
parent
30bd8dfd02
commit
9844d09683
@ -1,52 +1,154 @@
|
||||
# Observe The Wired -- Solution
|
||||
# Observe The Wired
|
||||
|
||||
## Overview
|
||||
CoAP node with observable stream. Recover fragments, decode the firmware blob, then POST the maintenance key.
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Category | IoT |
|
||||
| Difficulty | Medium-Hard |
|
||||
| Points | — |
|
||||
| Author | Eun0us |
|
||||
| CTF | Espilon 2026 |
|
||||
|
||||
## Steps
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
An IoT module from Clinique Sainte-Mika (Room 013) communicates via **CoAP** on the
|
||||
WIRED-MED network. The stream seems stable... but the observation layer hides a key fragment.
|
||||
|
||||
*In The Wired, only observers hear the truth.*
|
||||
|
||||
Explore the CoAP resources, observe the stream, reconstruct the key, decode the firmware
|
||||
blob, and open the maintenance channel.
|
||||
|
||||
- CoAP: `udp/<host>:5683`
|
||||
|
||||
Format: **ESPILON{flag}**
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
Discover CoAP resources with a `.well-known/core` GET. Collect fragments A, B, C from
|
||||
`/status`, `/telemetry/heart`, and the observable `/wired/stream`. Concatenate to build
|
||||
XOR key `WIREDLAIN23`. Download and decode the firmware blob from `/archive/firmware`.
|
||||
POST the maintenance key `0BS3RV3-L41N-23` to unlock and get the flag.
|
||||
|
||||
---
|
||||
|
||||
## Tools
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `coap-client` (libcoap) | CoAP GET, observe, POST |
|
||||
| Python 3 | XOR decode, base64 |
|
||||
|
||||
---
|
||||
|
||||
## Solution
|
||||
|
||||
### Step 1 — Discover resources
|
||||
|
||||
1. Discover resources
|
||||
```bash
|
||||
coap-client -m get coap://HOST/.well-known/core
|
||||
coap-client -m get coap://<HOST>/.well-known/core
|
||||
```
|
||||
|
||||
2. Get fragments A and B
|
||||
```bash
|
||||
coap-client -m get coap://HOST/status
|
||||
coap-client -m get coap://HOST/telemetry/heart
|
||||
Returns a comma-separated list of resource links (RFC 6690 format):
|
||||
|
||||
```
|
||||
</status>,</telemetry/heart>,</telemetry/temp>,
|
||||
</wired/stream>;obs,</archive/firmware>,
|
||||
</maintenance/unlock>
|
||||
```
|
||||
|
||||
3. Observe the stream for fragment C
|
||||
```bash
|
||||
coap-client -m get -s 30 -o coap://HOST/wired/stream
|
||||
```
|
||||
Capture the JSON notification that includes `fragment_c`.
|
||||
> 📸 `[screenshot: .well-known/core response listing all CoAP resources]`
|
||||
|
||||
### Step 2 — Get fragment A
|
||||
|
||||
```bash
|
||||
coap-client -m get coap://<HOST>/status
|
||||
```
|
||||
|
||||
Response includes: `fragment_a: WIRED`
|
||||
|
||||
### Step 3 — Get fragment B
|
||||
|
||||
```bash
|
||||
coap-client -m get coap://<HOST>/telemetry/heart
|
||||
```
|
||||
|
||||
Response includes: `fragment_b: LAIN`
|
||||
|
||||
### Step 4 — Observe the stream for fragment C
|
||||
|
||||
Subscribe to the observable resource for 30 seconds:
|
||||
|
||||
```bash
|
||||
coap-client -m get -s 30 -o observe_out.txt coap://<HOST>/wired/stream
|
||||
```
|
||||
|
||||
Among the periodic notifications, one JSON payload contains:
|
||||
|
||||
```json
|
||||
{"fragment_c": "23", "node": "013"}
|
||||
```
|
||||
|
||||
> 📸 `[screenshot: observable stream notification containing fragment_c value]`
|
||||
|
||||
### Step 5 — Build the XOR key
|
||||
|
||||
4. Build XOR key
|
||||
Concatenate fragments in order A + B + C:
|
||||
|
||||
```
|
||||
WIRED + LAIN + 23 = WIREDLAIN23
|
||||
```
|
||||
|
||||
5. Download firmware blob
|
||||
```bash
|
||||
coap-client -m get coap://HOST/archive/firmware
|
||||
```
|
||||
Save the base64 data between `FIRMWARE_B64_BEGIN` and `FIRMWARE_B64_END` into `firmware.b64`.
|
||||
### Step 6 — Download and decode the firmware blob
|
||||
|
||||
6. Decode the blob
|
||||
```bash
|
||||
python3 decode.py firmware.b64
|
||||
coap-client -m get coap://<HOST>/archive/firmware
|
||||
```
|
||||
The JSON includes `maintenance_key`.
|
||||
|
||||
7. Unlock and get the flag
|
||||
```bash
|
||||
coap-client -m post -e '0BS3RV3-L41N-23' coap://HOST/maintenance/unlock
|
||||
The response is a text payload with base64 between markers:
|
||||
|
||||
```
|
||||
FIRMWARE_B64_BEGIN
|
||||
<base64 data>
|
||||
FIRMWARE_B64_END
|
||||
```
|
||||
|
||||
Save and decode:
|
||||
|
||||
```python
|
||||
import base64, json
|
||||
|
||||
with open("firmware.b64") as f:
|
||||
b64_data = f.read().strip()
|
||||
|
||||
raw = base64.b64decode(b64_data)
|
||||
|
||||
# XOR with key WIREDLAIN23
|
||||
key = b"WIREDLAIN23"
|
||||
decoded = bytes(b ^ key[i % len(key)] for i, b in enumerate(raw))
|
||||
|
||||
config = json.loads(decoded.decode())
|
||||
print(config["maintenance_key"])
|
||||
# 0BS3RV3-L41N-23
|
||||
```
|
||||
|
||||
> 📸 `[screenshot: Python script printing the maintenance key from the decoded firmware blob]`
|
||||
|
||||
### Step 7 — Unlock and get the flag
|
||||
|
||||
```bash
|
||||
coap-client -m post -e "0BS3RV3-L41N-23" coap://<HOST>/maintenance/unlock
|
||||
```
|
||||
|
||||
The response contains the flag.
|
||||
|
||||
> 📸 `[screenshot: CoAP POST response returning the flag]`
|
||||
|
||||
---
|
||||
|
||||
## Flag
|
||||
`ESPILON{c0ap_0bs3rv3_th3_w1r3d}`
|
||||
|
||||
## Author
|
||||
Eun0us
|
||||
`ESPILON{c0ap_0bs3rv3_th3_w1r3d}`
|
||||
|
||||
Loading…
Reference in New Issue
Block a user