2023 Business CTF: ICS Intrusion

Challenge Information

AttributeDetails
Event2023 Business CTF
CategorySCADA/ICS
ChallengeICS Intrusion
DifficultyEasy

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

  1. Analyze the provided network traffic capture
  2. Identify Modbus protocol communication
  3. Extract register addresses being accessed
  4. Decode the sensitive data from the registers
  5. 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

CodeNamePurpose
01Read CoilsRead digital outputs
02Read Discrete InputsRead digital inputs
03Read Holding RegistersRead analog outputs
04Read Input RegistersRead analog inputs
05Write Single CoilControl single digital output
06Write Single RegisterSet single register value
15Write Multiple CoilsControl multiple outputs
16Write Multiple RegistersSet 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:

Terminal window
wireshark capture.pcap

Step 2: Filter for Modbus Traffic

Apply a display filter to show only Modbus packets:

tcp.port == 502 || modbus

Step 3: Identify Modbus Transactions

For each transaction, note:

  1. Function Code: What operation is being performed?
  2. Register Address: Which registers are accessed?
  3. Register Count: How many registers?
  4. 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 ASCII
flag = ""
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 registers
def 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 Configuration
40100-40199: User Credentials
40200-40299: System Status
40300-40399: Alerts and Logs
40400-40499: Flag/Secrets

Example 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:

  1. Verify consistency
  2. Identify changes over time
  3. Confirm data interpretation
  4. Reconstruct complete messages

Step 8: Extract the Flag

Compile all extracted data and format appropriately:

# Common flag formats
possibilities = [
"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 file
packets = rdpcap('capture.pcap')
# Filter Modbus packets
modbus_packets = [p for p in packets if TCP in p and p[TCP].dport == 502]
# Analyze each packet
for 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