# Cyberia Grid | Field | Value | |-------|-------| | Category | OT | | Difficulty | Medium-Hard | | Points | 500 | | Author | Eun0us | | CTF | Espilon 2026 | --- ## Description Cyberia is not just a nightclub. An industrial PLC controller manages the building power infrastructure over EtherNet/IP. The previous owner — rumored to be connected to the Knights of the Eastern Calculus — added extra tags that do not correspond to any physical equipment. Read the tags. Find the hidden data. The Psyche Processor awaits activation. - EtherNet/IP: `tcp/:44818` Format: **ESPILON{flag}** --- ## TL;DR Read all EtherNet/IP tags including hidden ones (`KIDS_Subject`, `Knights_Cipher`, `Psyche_Processor`). Derive the 4-value activation sequence from infrastructure tag values (BPM, sound level, lighting sum, hacker constant 0x1337). Write to `Psyche_Processor[0-3]`. After one scan cycle, read `Decoded_Output` for the flag. --- ## Tools | Tool | Purpose | |------|---------| | Python 3 + `cpppo` | EtherNet/IP client (read/write tags) | | Knowledge of EtherNet/IP | Understanding CIP tag addressing | --- ## Solution ### Step 1 — Connect and enumerate tags Using the cpppo EtherNet/IP client: ```python from cpppo.server.enip.get_attribute import proxy_simple as device with device(host="", port=44818) as via: # Read infrastructure tags zone_main = via.read("Zone_Main_Power") zone_vip = via.read("Zone_VIP_Power") zone_bsmt = via.read("Zone_Basement_Power") # = 0 (OFF — suspicious) sound_db = via.read("Sound_System_dB") # = 95 bpm = via.read("BPM") # = 140 lighting = [via.read(f"Lighting_Main[{i}]") for i in range(8)] # = [255, 200, 180, 150, 100, 80, 60, 40] # Read hidden tags kids = [via.read(f"KIDS_Subject[{i}]") for i in range(16)] cipher = [via.read(f"Knights_Cipher[{i}]") for i in range(4)] # cipher = [0x4B, 0x6E, 0x69, 0] -- 4th byte missing psyche_st = via.read("Psyche_Status") # = "DORMANT" ``` > 📸 `[screenshot: cpppo client output listing all tag values including hidden ones]` **Observation:** `Zone_Basement_Power = 0` — the basement is OFF. This is the first hint that something is hidden underground. ### Step 2 — Analyze the hidden tags - `KIDS_Subject[0-15]`: 16 DINT values containing XOR-encoded flag data - `Knights_Cipher[0-3]`: partial XOR key `[0x4B, 0x6E, 0x69, 0]` = `"Kni?"` — 4th byte missing - `Psyche_Processor[0-3]`: all zeros — needs activation - `Psyche_Status = "DORMANT"` ### Step 3 — Derive the activation sequence Each `Psyche_Processor` value is derived from existing infrastructure tags: | Index | Formula | Calculation | Value | |-------|---------|-------------|-------| | 0 | `Zone_Basement_Power XOR BPM` | `0 ^ 140` | 140 | | 1 | `Sound_System_dB` | `95` | 95 | | 2 | `sum(Lighting_Main) % 256` | `1065 % 256` | 17 | | 3 | `0x1337` (hacker constant) | `4919` | 4919 | > 📸 `[screenshot: Python calculation showing the four derived activation values]` ### Step 4 — Activate the Psyche Processor Write the derived values: ```python with device(host="", port=44818) as via: for i, val in enumerate([140, 95, 17, 4919]): via.write(via.parameter_substitution(f"Psyche_Processor[{i}]"), val) ``` ### Step 5 — Wait one scan cycle and read the flag After ~500ms (one PLC scan cycle): ```python import time time.sleep(0.6) with device(host="", port=44818) as via: flag = via.read("Decoded_Output") print(flag) # Also: Knights_Cipher[3] is now populated: 0x67 = 'g' → key = "Knig" ``` > 📸 `[screenshot: Decoded_Output tag returning the flag after Psyche Processor activation]` ### Key concepts - `Zone_Basement_Power = 0` is the first hint that something is hidden underground - The `0x1337` constant is a recurring hacker reference across the OT challenges - The PLC scan cycle polling pattern mirrors real industrial controller behavior - EtherNet/IP has no built-in authentication — anyone can read/write tags on the network --- ## Flag `ESPILON{cyb3r14_ps7ch3_pr0c3ss0r}`