# 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 <HOST> 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         = ["<hex_token>"]
    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 = "<token>"
    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 <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
