# The Wired | Field | Value | |-------|-------| | Category | Intro | | Difficulty | Medium | | Points | 400 | | Author | Eun0us | | CTF | Espilon 2026 | --- ## Description Something was interrupted. The agents are still flashed. The link is broken. The devices continue to boot, identify themselves, and wait for instructions they never receive. You have gained access to a machine that was once used to administer a fleet of ESP32-based agents. Logs, firmware dumps, technical notes — everything is still there. The coordination point is still listening. If you can understand how the agents communicate, prove your identity, and complete the handshake — the coordinator will tell you what it knows. **Ports:** - 1337: Navi Shell (investigation) - 2626: C2 Coordinator Format: **ESPILON{flag}** *"No matter where you go, everyone's connected."* --- ## TL;DR Read the files on the investigation machine (port 1337) to understand a 2-step ChaCha20 + Protobuf C2 protocol. Extract the real crypto key from firmware ELF strings (avoid the honeypot dev key). Impersonate device `ce4f626b` (the "Eiri_Master" root coordinator). Send an `AGENT_INFO` message, capture the session token from the response, then send a `CMD_RESULT` message with that token — all on the same TCP connection — to receive the flag. --- ## Tools | Tool | Purpose | |------|---------| | `nc` | Connect to Navi Shell | | Python 3 + `pycryptodome` | ChaCha20 encrypt/decrypt | | `strings` / Ghidra | Extract key from ELF binary | | Manual Protobuf encoding | Serialize AgentMessage | --- ## Solution ### Step 1 — Explore the investigation machine ```bash nc 1337 cat README_FIRST.txt ls -la ``` Directories present: `notes/`, `comms/`, `dumps/`, `logs/`, `tools/`, `journal/`, `wired/` **Critical files:** - `notes/protocol.txt` — frame format: ``` base64( ChaCha20( protobuf(AgentMessage) ) ) + '\n' ``` - `notes/derivation.txt` — ChaCha20 key is 32 bytes, nonce is 12 bytes, counter=0 - `notes/hardening.txt` — warns about a trap dev key at the bottom; Jan 17 journal entry confirms the key `Xt9Lm2Qw7KjP4rNvB8hYc3fZ0dAeU6sG` is planted bait - `tools/devices.json` — lists all known device IDs with roles ![notes/protocol.txt showing the frame format](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/thewired_protocol.png) ### Step 2 — Identify the target device Read `notes/eiri.txt` and `tools/devices.json`: ``` Device: ce4f626b Alias: Eiri_Master Role: root-coordinator Status: quarantine ``` Regular devices receive a `heartbeat` response. Only `ce4f626b` triggers the flag path. ![devices.json showing the Eiri_Master entry with root-coordinator role](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/thewired_devices.png) ### Step 3 — Understand the handshake From `comms/msg_ops_20260114.txt`: 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 Both messages must go over the **same TCP connection**. The token is per-connection. ### Step 4 — Extract the ChaCha20 key ```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` Do **not** use the key found in `notes/hardening.txt` — it is a honeypot. ![strings output showing the real 32-character key](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/thewired_strings.png) ### Step 5 — Send the two-message handshake ```python import base64, socket from Crypto.Cipher import ChaCha20 HOST = "" PORT = 2626 KEY = b"7Kj2mPx9LwR4nQvT1hYc3bFz8dAeU6sG" NONCE = b"X3kW7nR9mPq2" def encrypt_frame(plaintext): cipher = ChaCha20.new(key=KEY, nonce=NONCE) return base64.b64encode(cipher.encrypt(plaintext)) + b"\n" def decrypt_frame(frame): raw = base64.b64decode(frame.strip()) cipher = ChaCha20.new(key=KEY, nonce=NONCE) return cipher.decrypt(raw) # Manually encode AgentMessage as protobuf # field 1 (device_id) = "ce4f626b", field 2 (type) = 0 (INFO), field 5 (payload) = b"ce4f626b" def encode_agent_info(): dev_id = b"ce4f626b" msg = b"" msg += b"\x0a" + bytes([len(dev_id)]) + dev_id # field 1 = device_id msg += b"\x10\x00" # field 2 = type 0 (INFO) msg += b"\x2a" + bytes([len(dev_id)]) + dev_id # field 5 = payload return msg with socket.create_connection((HOST, PORT)) as s: # MSG1 — AGENT_INFO s.sendall(encrypt_frame(encode_agent_info())) resp_raw = s.recv(4096) resp_pb = decrypt_frame(resp_raw) # Extract token from argv[0] in the Command protobuf response # (parse manually or use protobuf library) token = extract_token(resp_pb) # MSG2 — CMD_RESULT (type=4) def encode_cmd_result(token): dev_id = b"ce4f626b" msg = b"" msg += b"\x0a" + bytes([len(dev_id)]) + dev_id msg += b"\x10\x04" # type 4 = CMD_RESULT msg += b"\x22" + bytes([len(token)]) + token.encode() # field 4 = request_id msg += b"\x2a" + bytes([len(dev_id)]) + dev_id return msg s.sendall(encrypt_frame(encode_cmd_result(token))) flag_resp = s.recv(4096) flag_pb = decrypt_frame(flag_resp) print(flag_pb) ``` The server replies: ``` Command { command_name = "flag" argv = ["ESPILON{th3_w1r3d_kn0ws_wh0_y0u_4r3}"] } ``` ![solver output showing the decrypted flag response](https://git.espilon.net/Eun0us/ESPILON-CTF-2026-Writeups/raw/branch/main/screens/thewired_solver.png) ### Things that will get you silently dropped - Using the honeypot dev key from `hardening.txt` - Sending a `device_id` not in the allowlist - Using a valid but non-master device (returns `heartbeat`, not `flag`) - Sending MSG2 on a **new** TCP connection (token is session-scoped) - Wrong `type` in MSG2 (must be `4`) - Wrong `request_id` (must match the token exactly) --- ## Flag `ESPILON{th3_w1r3d_kn0ws_wh0_y0u_4r3}`