ESPILON-CTF-2026-Writeups/OT/Protocol_Seven
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

Protocol Seven -- Solution

Overview

Multi-protocol challenge requiring cross-referencing three OT protocols. Eiri Masami distributed Protocol Seven's components across BACnet, OPC-UA, and EtherNet/IP. Players must extract data from all three and combine them to decrypt the flag.

Architecture

Layer Protocol Port Provides
1 BACnet/IP 47809/udp XOR encryption key (8 bytes)
2 OPC-UA 4841/tcp Encrypted payload (32 bytes)
3 EtherNet/IP 44819/tcp Rotation nonce (integer)

Steps

1. Port Discovery

Scan the target -- three open ports: 47809/udp, 4841/tcp, 44819/tcp.

2. Layer 1 -- BACnet Key Extraction

Send WhoIs to port 47809 → IAm from device 7777. Read object-list: 8 AnalogValue objects named Harmonic_0 through Harmonic_7.

Read the device description: "Key Harmonic Array -- integer components matter"

Read presentValue of each harmonic:

Harmonic_0 = 69.14  -> int(69)  = 'E'
Harmonic_1 = 105.92 -> int(105) = 'i'
Harmonic_2 = 114.37 -> int(114) = 'r'
Harmonic_3 = 105.68 -> int(105) = 'i'
Harmonic_4 = 95.44  -> int(95)  = '_'
Harmonic_5 = 75.81  -> int(75)  = 'K'
Harmonic_6 = 101.22 -> int(101) = 'e'
Harmonic_7 = 121.55 -> int(121) = 'y'

XOR key = Eiri_Key (8 bytes)

3. Layer 2 -- OPC-UA Payload Extraction

Connect anonymously to opc.tcp://HOST:4841/protocol7/. Read Server.NamespaceArray → find urn:protocol-seven:payload.

Browse Protocol7_Vault:

  • Payload_Encrypted: 32-byte ByteString (the ciphertext)
  • Layer_Info: "Payload encrypted with 8-byte repeating XOR key -- see BACnet harmonics"
  • IV_Hint: "Rotation offset from CIP controller -- read NONCE tag"

4. Layer 3 -- EtherNet/IP Nonce Extraction

Connect to EtherNet/IP on port 44819. Read tags:

  • NONCE = 3 (the rotation offset)
  • Layer_Hint: "Rotate payload by NONCE bytes before XOR decryption"
  • Assembly_Check = [47809, 4841, 44819] (confirms all three ports)

5. Decryption

# XOR payload with repeating key
xored = bytes(payload[i] ^ key[i % 8] for i in range(32))
# Rotate right by NONCE (undo the left rotation used during encryption)
flag = xored[-nonce:] + xored[:-nonce]
# Strip null padding
print(flag.rstrip(b'\x00').decode())

Key Insights

  • The BACnet device description explicitly says "integer components matter"
  • The OPC-UA hints point directly to BACnet and EtherNet/IP
  • The EtherNet/IP Assembly_Check tag confirms the three-port architecture
  • Eiri_Key as the XOR key is a mnemonic hint (Eiri Masami is the creator)
  • The challenge teaches multi-protocol OT environments and data cross-referencing

Flag

ESPILON{pr0t0c0l_7_m3rg3_c0mpl3t3}

Author

Eun0us