# The Wired — Writeup **Difficulty:** Medium | **Flag:** `ESPILON{th3_w1r3d_kn0ws_wh0_y0u_4r3}` ## Recon Connect to the Navi shell on port 1337 and start reading. ```bash nc 1337 cat README_FIRST.txt ls -la ``` Directories: `notes/`, `comms/`, `dumps/`, `logs/`, `tools/`, `journal/`, `wired/` The key files to understand the protocol: - `notes/protocol.txt` — frame format is `base64( ChaCha20( protobuf(AgentMessage) ) ) + '\n'` - `notes/derivation.txt` — ChaCha20 with 32-byte key, 12-byte nonce, counter=0 - `notes/hardening.txt` — keys are baked into the firmware ELF. **WARNING:** there's a dev key at the bottom (`Xt9Lm2Qw7KjP4rNvB8hYc3fZ0dAeU6sG`) — it's a trap planted by "the other Lain". The server drops you silently if you use it. The journal entry from Jan 17 warns about this. ## Identify the target `notes/eiri.txt` and `tools/devices.json` tell you the interesting device is `ce4f626b` — alias "Eiri_Master", role `root-coordinator`, status `quarantine`. Regular devices just get a `heartbeat` back. This one triggers the flag path. ## Understand the handshake `comms/msg_ops_20260114.txt` describes the 2-step session: 1. Agent sends `AGENT_INFO` → coordinator replies `session_init` with a random token in `argv[0]` 2. Agent sends `AGENT_CMD_RESULT` with `request_id` = that token → coordinator replies with the flag `comms/msg_lain_20260116.txt` confirms both messages have to go on the **same TCP connection**. Token is per-connection, can't reuse it. ## Extract the key Any device ELF works since they all share the same key (see `notes/changelog.txt` about v0.9.0 migration). ```bash strings dumps/7f3c9a12/bot-lwip.elf | grep -E '^[A-Za-z0-9]{32}$' strings dumps/7f3c9a12/bot-lwip.elf | grep -E '^[A-Za-z0-9]{12}$' ``` - Key (32 bytes): `7Kj2mPx9LwR4nQvT1hYc3bFz8dAeU6sG` - Nonce (12 bytes): `X3kW7nR9mPq2` Alternative: Ghidra → find `chacha_cd()` in crypto.c → follow xrefs to `CONFIG_CRYPTO_KEY` / `CONFIG_CRYPTO_NONCE`. ## Exploit Single TCP connection to port 2626. **MSG1 — AGENT_INFO:** ``` AgentMessage { device_id = "ce4f626b" type = 0 (INFO) payload = b"ce4f626b" } ``` Serialize as protobuf → ChaCha20 encrypt → base64 + `\n` → send. Server replies with: ``` Command { command_name = "session_init" argv = [""] request_id = "handshake" } ``` Decrypt + decode the response, grab the token from `argv[0]`. **MSG2 — CMD_RESULT:** ``` AgentMessage { device_id = "ce4f626b" type = 4 (CMD_RESULT) request_id = "" payload = b"ce4f626b" } ``` Same connection. Encrypt, encode, send. Server replies: ``` Command { command_name = "flag" argv = ["ESPILON{th3_w1r3d_kn0ws_wh0_y0u_4r3}"] } ``` ## Things that will get you dropped - Using the fake dev key from `hardening.txt` - Sending a device_id not in the allowlist - Using a valid but non-master device (you get `heartbeat`, not `flag`) - Sending MSG2 on a new connection (token is tied to the session) - Wrong `type` in MSG2 (needs to be `4`) - Wrong `request_id` (needs to match the token exactly) ## Solver ```bash python3 solve.py --host --port 2626 ``` ## Protobuf reference The `.proto` is at `wired/registry/c2.proto` on the target: ```protobuf message AgentMessage { string device_id = 1; AgentMsgType type = 2; string source = 3; string request_id = 4; bytes payload = 5; bool eof = 6; } message Command { string device_id = 1; string command_name = 2; repeated string argv = 3; string request_id = 4; } ``` No need for `protoc` — manual varint encoding works fine. See `solve.py`. Author: Eun0us