# Observe The Wired | Field | Value | |-------|-------| | Category | IoT | | Difficulty | Medium-Hard | | Points | 499 | | 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/: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:///.well-known/core ``` Returns a comma-separated list of resource links (RFC 6690 format): ``` ,,, ;obs,, ``` ![.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:///status ``` Response includes: `fragment_a: WIRED` ### Step 3 — Get fragment B ```bash coap-client -m get coap:///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:///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:///archive/firmware ``` The response is a text payload with base64 between markers: ``` FIRMWARE_B64_BEGIN 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:///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}`