# Operating Room -- Solution ## Overview Modbus TCP server simulating a hospital operating room control system. The player must discover the correct unit ID, map the registers, reverse the XOR-encoded state machine, and execute 6 timed transitions. ## Steps ### 1. Discover Unit ID Scan Modbus unit IDs (slave addresses). The server only responds to **unit ID 13**. Default unit ID 1 returns Modbus exceptions. ```python from pymodbus.client import ModbusTcpClient client = ModbusTcpClient("HOST") client.connect() for uid in range(1, 20): r = client.read_holding_registers(0, 1, slave=uid) if not r.isError(): print(f"Unit ID {uid} responds!") ``` ### 2. Map Registers Read holding registers 0-255 on unit 13: - **Registers 0-19**: Operating room telemetry (temperature, humidity, pressure, O2, etc.) - **Register 13**: `0x4C4E` ("LN" -- Lain easter egg) - **Register 19**: `0x0D13` -- this is the XOR key - **Registers 100-105**: State machine (state, encoded hint, timer, transitions, error, key) - **Register 105**: `0x0D13` -- XOR key copy (confirms reg 19) - **Register 110**: Write target (trigger register) - **Registers 200-215**: All zeros (flag area, populated after completion) ### 3. Understand the State Machine - Register 100 = current state (starts at 0) - Register 101 = encoded hint - Register 105 = XOR key (0x0D13) - Decode: `expected_value = reg_101 XOR 0x0D13` - Write `expected_value` to register 110 to advance the state - Each transition must happen before register 102 (timer) reaches 0 ### 4. Execute Transitions | State | Subsystem | Decoded Value | Source | |-------|-----------|--------------|--------| | 0 | HVAC | 220 | reg 0 (temperature) | | 1 | Pressure | 15 | reg 2 (pressure) | | 2 | O2 | 50 | reg 3 (O2 flow) | | 3 | Ventilation | 1200 | reg 4 (fan RPM) | | 4 | Lighting | 800 | reg 5 (lux) | | 5 | Safety | 4919 (0x1337) | special | ### 5. Read Flag After all 6 transitions, register 100 = 7 (complete). Read registers 200-215 and decode uint16 pairs to ASCII. ```python regs = client.read_holding_registers(200, 16, slave=13).registers flag = "" for val in regs: if val == 0: break flag += chr((val >> 8) & 0xFF) + chr(val & 0xFF) print(flag) ``` ## Key Insights - XOR key `0x0D13` is stored in two places (reg 19 and reg 105) as a breadcrumb - The decoded values for states 0-4 match the current telemetry readings - State 5 uses the special value `0x1337` (hacker reference) - Wrong writes or timeouts reset the state machine to 0 ## Flag `ESPILON{m0dbu5_0p3r4t1ng_r00m}` ## Author Eun0us