ESPILON-CTF-2026-Writeups/OT/Cyberia_Grid
2026-03-22 19:18:58 +01:00
..
README.md ESPILON CTF 2026 — Write-ups édition 1 (33 challenges) 2026-03-22 19:18:58 +01:00

Cyberia Grid -- Solution

Overview

EtherNet/IP server simulating a PLC at Cyberia nightclub. The controller manages power infrastructure and contains hidden tags with encoded KIDS experiment data. A write-triggered "Psyche Processor" reveals the flag.

Steps

1. Connect and Enumerate Tags

Connect to the EtherNet/IP server on port 44818. List all available tags.

# Using cpppo client
python -m cpppo.server.enip.client --address HOST:44818 \
    'Zone_Main_Power' 'Zone_VIP_Power' 'Zone_Basement_Power' \
    'Sound_System_dB' 'BPM' 'Lighting_Main[0-7]' \
    'KIDS_Subject[0-15]' 'Knights_Cipher[0-3]' \
    'Psyche_Processor[0-3]' 'Psyche_Status' 'Decoded_Output'

2. Analyze Infrastructure Tags

  • Zone_Main_Power = 1, Zone_VIP_Power = 1 -- normal
  • Zone_Basement_Power = 0 -- basement is OFF (suspicious)
  • Sound_System_dB = 95, BPM = 140
  • Lighting_Main = [255, 200, 180, 150, 100, 80, 60, 40]

3. Analyze Hidden Tags

  • KIDS_Subject[0-15]: 16 DINTs containing XOR-encoded flag data
  • Knights_Cipher[0-3]: partial XOR key [0x4B, 0x6E, 0x69, 0] -- 4th byte is missing!
  • Psyche_Processor[0-3]: all zeros -- awaiting activation
  • Psyche_Status = "DORMANT"

4. Derive Activation Sequence

The 4 Psyche_Processor values are derived from infrastructure tag values:

Index Formula Value
0 Zone_Basement_Power XOR BPM 0 ^ 140 = 140
1 Sound_System_dB 95
2 sum(Lighting_Main) % 256 1065 % 256 = 17
3 0x1337 (hacker constant) 4919

5. Activate Psyche Processor

Write [140, 95, 17, 4919] to Psyche_Processor[0-3].

from cpppo.server.enip.get_attribute import proxy_simple as device
with device(host="HOST", port=44818) as via:
    for i, val in enumerate([140, 95, 17, 4919]):
        via.write(via.parameter_substitution(f"Psyche_Processor[{i}]"), val)

6. Read Flag

After the PLC scan cycle (~500ms), read Decoded_Output:

    flag = via.read(via.parameter_substitution("Decoded_Output"))
    print(flag)

Also: Knights_Cipher[3] is now populated (0x67 = 'g'), completing the key "Knig" which can also be used to manually XOR-decode KIDS_Subject.

Key Insights

  • Zone_Basement_Power = 0 is the first hint that something is hidden underground
  • The 0x1337 constant echoes the Operating Room challenge pattern
  • The PLC scan cycle polling pattern mimics real industrial controller behavior
  • Without authentication, anyone can read/write tags -- a common EtherNet/IP vulnerability

Flag

ESPILON{cyb3r14_ps7ch3_pr0c3ss0r}

Author

Eun0us