2023 Business CTF: ICS Intrusion
Challenge Information
| Attribute | Details |
|---|---|
| Event | 2023 Business CTF |
| Category | SCADA/ICS |
| Challenge | ICS Intrusion |
| Difficulty | Easy |
Summary
ICS Intrusion is an easy-level SCADA challenge focused on network traffic analysis and forensics. After gaining access to enemy infrastructure, a network packet capture was taken from their Modbus control network. The objective is to analyze the captured traffic to identify which Modbus registers contain sensitive information and extract that data for intelligence purposes.
Challenge Information
The challenge description states:
“After gaining access to the enemy’s infrastructure, we collected crucial network traffic data from their Modbus network. Our primary objective is to swiftly identify the specific registers containing highly sensitive information and extract that data.”
Challenge Objectives
- Analyze the provided network traffic capture
- Identify Modbus protocol communication
- Extract register addresses being accessed
- Decode the sensitive data from the registers
- Locate the flag or sensitive information
Analysis
Modbus Protocol in Network Traffic
Modbus TCP packets contain the following key elements:
Packet Structure:
[Ethernet] [IP] [TCP] [Modbus Protocol Data Unit]
Modbus PDU:- Transaction ID (2 bytes)- Protocol ID (2 bytes) = 0x0000- Length (2 bytes)- Unit ID (1 byte)- Function Code (1 byte)- Payload (variable length)Common Modbus Function Codes
| Code | Name | Purpose |
|---|---|---|
| 01 | Read Coils | Read digital outputs |
| 02 | Read Discrete Inputs | Read digital inputs |
| 03 | Read Holding Registers | Read analog outputs |
| 04 | Read Input Registers | Read analog inputs |
| 05 | Write Single Coil | Control single digital output |
| 06 | Write Single Register | Set single register value |
| 15 | Write Multiple Coils | Control multiple outputs |
| 16 | Write Multiple Registers | Set multiple register values |
Register Address Mapping
Industrial systems typically use:
- 00000-09999: Discrete Inputs
- 10000-19999: Coils
- 30000-39999: Input Registers
- 40000-49999: Holding Registers
Sensitive data is often stored in higher address ranges.
Solution
Step 1: Extract and Examine the Traffic Capture
Using Wireshark or similar tools, open the provided PCAP file:
wireshark capture.pcapStep 2: Filter for Modbus Traffic
Apply a display filter to show only Modbus packets:
tcp.port == 502 || modbusStep 3: Identify Modbus Transactions
For each transaction, note:
- Function Code: What operation is being performed?
- Register Address: Which registers are accessed?
- Register Count: How many registers?
- Data Values: What values are being read/written?
Example Analysis:
Packet: Function Code 03 (Read Holding Registers) - Starting Address: 40000 - Quantity: 10 - Response Data: [0x1234, 0x5678, 0x9ABC, ...]Step 4: Extract Sensitive Data
Focus on unusual register access patterns:
# Pseudocode for analyzing Modbus captures
captured_registers = { 40001: [0x48, 0x65], # "He" 40002: [0x6C, 0x6C], # "ll" 40003: [0x6F, 0x20], # "o " 40004: [0x46, 0x4C], # "FL" 40005: [0x41, 0x47], # "AG" # ...}
# Convert register values to ASCIIflag = ""for addr in sorted(captured_registers.keys()): values = captured_registers[addr] for byte_val in values: if 32 <= byte_val <= 126: # Printable ASCII flag += chr(byte_val)
print(f"Extracted: {flag}")Step 5: Decode Multi-Register Data
Some registers may contain combined data:
# Handling 32-bit values split across 16-bit registersdef combine_registers(high_word, low_word): """Combine two 16-bit registers into 32-bit value""" return (high_word << 16) | low_word
def extract_string_from_registers(register_values): """Extract ASCII string from register list""" data = bytearray() for reg_val in register_values: # Extract high byte and low byte high_byte = (reg_val >> 8) & 0xFF low_byte = reg_val & 0xFF
if high_byte > 0: data.append(high_byte) if low_byte > 0: data.append(low_byte)
return data.decode('ascii', errors='ignore')Step 6: Analyze Specific Register Ranges
Target registers typically containing sensitive information:
40000-40099: System Configuration40100-40199: User Credentials40200-40299: System Status40300-40399: Alerts and Logs40400-40499: Flag/SecretsExample Wireshark filter for specific registers:
modbus.func_code == 3 && (modbus.starting_address >= 40000 && modbus.starting_address <= 40500)Step 7: Cross-Reference and Validate
Compare multiple packets accessing the same registers to:
- Verify consistency
- Identify changes over time
- Confirm data interpretation
- Reconstruct complete messages
Step 8: Extract the Flag
Compile all extracted data and format appropriately:
# Common flag formatspossibilities = [ "HTB{...}", "FLAG{...}", "CTF{...}", # Or raw ASCII from registers]
print(f"Flag: {flag}")Advanced Analysis Techniques
Modbus Dissection in Python
from scapy.all import *
# Read PCAP filepackets = rdpcap('capture.pcap')
# Filter Modbus packetsmodbus_packets = [p for p in packets if TCP in p and p[TCP].dport == 502]
# Analyze each packetfor i, packet in enumerate(modbus_packets): print(f"\nPacket {i}:") print(f" Source: {packet[IP].src}") print(f" Destination: {packet[IP].dst}") if Raw in packet: payload = packet[Raw].load # Parse Modbus PDU transaction_id = int.from_bytes(payload[0:2], 'big') protocol_id = int.from_bytes(payload[2:4], 'big') length = int.from_bytes(payload[4:6], 'big') unit_id = payload[6] func_code = payload[7]
print(f" Transaction ID: {transaction_id}") print(f" Function Code: {func_code}")
if func_code == 3: # Read Holding Registers starting_addr = int.from_bytes(payload[8:10], 'big') quantity = int.from_bytes(payload[10:12], 'big') print(f" Reading {quantity} registers starting at {starting_addr}")Key Takeaways
- Network Visibility: SCADA systems often transmit sensitive data in plaintext
- Protocol Analysis: Understanding industrial protocols is crucial for forensics
- Data Extraction: Wireshark and scripting can automate flag extraction
- Register Mapping: Knowing standard Modbus addresses helps identify sensitive data
- Traffic Patterns: Unusual access patterns may indicate reconnaissance or data exfiltration
- Lack of Encryption: Legacy ICS systems often lack encryption; analyze at your will
Tools and Resources
- Wireshark: Network packet analyzer with Modbus dissector
- Scapy: Python library for packet manipulation
- PyModbus: Python library for Modbus client/server
- Modbus Specification: IEC 61131-3 standard
- IDA Pro: Reverse engineering captured binaries
- Volatility: Analyzing network captures and memory