# Observe The Wired

| Field | Value |
|-------|-------|
| Category | IoT |
| Difficulty | Medium-Hard |
| Points | — |
| Author | Eun0us |
| CTF | Espilon 2026 |

---

## 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

```bash
coap-client -m get coap://<HOST>/.well-known/core
```

Returns a comma-separated list of resource links (RFC 6690 format):

```
</status>,</telemetry/heart>,</telemetry/temp>,
</wired/stream>;obs,</archive/firmware>,
</maintenance/unlock>
```

![.well-known/core response listing all CoAP resources](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/coap_wellknown.png)

### 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"}
```

![observable stream notification containing fragment_c value](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/coap_observe.png)

### Step 5 — Build the XOR key

Concatenate fragments in order A + B + C:

```
WIRED + LAIN + 23 = WIREDLAIN23
```

### Step 6 — Download and decode the firmware blob

```bash
coap-client -m get coap://<HOST>/archive/firmware
```

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
```

![Python script printing the maintenance key from the decoded firmware blob](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/coap_firmware_key.png)

### 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.

![CoAP POST response returning the flag](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/coap_flag.png)

---

## Flag

`ESPILON{c0ap_0bs3rv3_th3_w1r3d}`
