"Ankh-Morpork's quietly indispensable utility, operating from repurposed university basements and one building that insists it was never meant to be a building at all."
Welcome to the Unseen University Power & Light Co. company and simulator.
This is a causally correct, layered, and testable simulation of an industrial control system (ICS) environment, designed for developing convincing security proofs-of-concept without risking production systems.
Real ICS/SCADA environments are:
- Fragile: a misplaced packet can cause physical consequences
- Legacy-ridden: decades-old systems with no security considerations
- High-stakes: blackouts, floods, or worse
This simulator lets you explore attack paths, test detection mechanisms, and develop PoCs against a realistic OT environment that won't leave a city in the dark.
The UU P&L infrastructure includes:
| System | Description | Control Hardware |
|---|---|---|
| Hex Steam Turbine | Main power generation with hardwired logic and polling loops | Allen-Bradley ControlLogix (1998) |
| Alchemical Reactor | Volatile energy conversion with chemical and metaphysical variables | Siemens S7-400 (2003) |
| Library Environmental | Temperature, humidity, and magical stability control | Schneider Modicon (1987) + Modbus gateway |
| City-Wide Distribution | SCADA managing substations across Ankh-Morpork | RTUs via DNP3, Wonderware HMI |
Plus the supporting cast: historians storing 10+ years of operational data, safety PLCs with redundant sensors, protective relays, PMUs, and yes, a Windows 98 machine that's been collecting turbine data for 25 years.
This simulator provides:
- Physics-aware devices: PLCs, RTUs, and safety controllers with realistic scan cycles (25-100ms)
- Time-synchronised behaviour: deterministic stepping for reproducible scenarios
- Real network attack surfaces: Protocol servers on actual TCP/IP ports for external tool access
- OT protocols: Modbus TCP/RTU, DNP3, IEC 60870-5-104, IEC 61850, OPC UA, S7comm
- Network segmentation: control zones, DMZs, and firewall simulation
- Security layers: authentication, logging, and anomaly detection
- Use mbtget, nmap, Metasploit and scripts against running simulation
- Red team attack scripts and blue team defence tool
.
├── components/
│ ├── devices/ # PLCs, RTUs, HMIs, historians, safety controllers
│ ├── network/ # Network simulation, attack surfaces (protocol servers)
│ ├── physics/ # Turbine dynamics, power flow, thermal models
│ ├── protocols/ # Modbus, DNP3, IEC-104, S7, OPC UA semantics
│ ├── security/ # Logging, authentication, anomaly detection
│ ├── state/ # Shared state fabric and data store
│ └── time/ # Deterministic time orchestration
├── config/ # YAML device configs, network topologies, SCADA tag databases
├── scripts/ # Red team attack scripts (external)
│ ├── recon/ # Reconnaissance and footprinting
│ ├── discovery/ # Device enumeration and memory mapping
│ ├── vulns/ # Vulnerability probes (OPC UA, S7, Modbus)
│ ├── exploitation/ # Attack demonstrations and PoCs
│ ├── analysis/ # Post-collection data analysis
│ └── assessment/ # Security assessment demonstrations
├── tests/
│ ├── unit/ # Component-level tests
│ ├── integration/ # Cross-component tests
│ └── scenario/ # End-to-end scenario validation
└── tools/ # Simulator manager, Blue Team CLI (internal defence)
Like an engineer's workbench where:
- Devices behave according to real industrial logic and timing
- Physics models drive actual state changes (not just data)
- Protocols translate interactions into proper network semantics
- Security observes and constrains without hiding underlying behaviour
The simulator follows a strict causal layering: higher layers consume, never define, lower layers:
┌─────────────────────────────────────────────────────────────────┐
│ 8. Scenarios & PoCs │
│ Red team attack scripts │ Blue team defence tools │
├─────────────────────────────────────────────────────────────────┤
│ 7. Adapters & IO │
│ Real network stacks, protocol libraries, external boundary │
├─────────────────────────────────────────────────────────────────┤
│ 6. Security & Policy │
│ Authentication, encryption, logging, anomaly detection │
├─────────────────────────────────────────────────────────────────┤
│ 5. Protocol Semantics │
│ What Modbus/DNP3/S7 messages mean, not just their bytes │
├─────────────────────────────────────────────────────────────────┤
│ 4. Device Layer │
│ PLCs, RTUs, HMIs, historians, safety controllers │
├─────────────────────────────────────────────────────────────────┤
│ 3. Physics Engines │
│ Turbine dynamics, power flow, thermal models │
├─────────────────────────────────────────────────────────────────┤
│ 2. State Fabric │
│ Consistent shared state that all components read/write │
├─────────────────────────────────────────────────────────────────┤
│ 1. Time & Orchestration │
│ Single time source, deterministic stepping │
└─────────────────────────────────────────────────────────────────┘
This maps roughly to the Purdue Model levels used in real ICS environments: from Level 0 field devices up through control, operations, and enterprise zones.
The simulator exposes real network services on TCP/IP ports that external tools can target:
┌────────────────────────────────────────────────────────┐
│ External Attack Tools (Terminal 2) │
│ - nmap: Port scanning │
│ - mbtget: Modbus client │
│ - Metasploit: SCADA exploits │
│ - Custom scripts: pymodbus, python-snap7 │
└───────────────────┬────────────────────────────────────┘
│ Real TCP/IP connections
↓
┌────────────────────────────────────────────────────────┐
│ Network Protocol Servers (components/network/servers) │
│ - ModbusTCPServer: ports 10502-10506 │
│ - S7Server: port 102 │
│ - DNP3Server: ports 20000-20002 │
└───────────────────┬────────────────────────────────────┘
│ Memory map sync
↓
┌────────────────────────────────────────────────────────┐
│ Device Logic (components/devices) │
│ - TurbinePLC, ReactorPLC, SafetyPLCs │
│ - SCADA servers, HMI workstations │
│ - Historians, engineering workstations │
└───────────────────┬────────────────────────────────────┘
│ Physics interaction
↓
┌────────────────────────────────────────────────────────┐
│ Physics Engines (components/physics) │
│ - TurbinePhysics, ReactorPhysics, GridPhysics │
└────────────────────────────────────────────────────────┘
This architecture allows realistic attack demonstrations where:
- Simulation runs in Terminal 1 with exposed services
- Attacker tools run in Terminal 2 using standard ICS tooling
- Attacks have observable impact on simulated physical processes
- Defender tools run in Terminal 3
# Clone and install
git clone https://github.com/tymyrddin/power-and-light-sim.git
cd power-and-light-sim
pip install -r requirements.txt
# Run the simulator
python tools/simulator_manager.py
# The simulation opens real network ports:
# - Modbus TCP: ports 10502-10506 (PLCs, safety controllers)
# - S7: port 102 (reactor PLC)
# - DNP3: ports 20000-20002 (RTUs)
# Run tests (in another terminal)
pytest tests/unit # Component tests
pytest tests/unit -m "not slow" # Skip slower tests
pytest tests/integration # Cross-component testsConfiguration files in config/ define:
- Device definitions and control zones (
devices.yml) - Network topology and segmentation (
network.yml) - Protocol bindings and behaviour (
protocols.yml) - SCADA tag databases (
scada_tags.yml) - HMI screen configurations (
hmi_screens.yml) - Simulation parameters (
simulation.yml)
The simulator ships with a set of red team scripts and blue team challenges. The simulator starts with the system in a vulnerable state and challenges follow an attack-then-defend pattern: exploit the weakness first, then close the door.
| Challenge | Topic | Difficulty | Red team (attack) | Blue team (defend) |
|---|---|---|---|---|
| 1 | Password protect the SCADA | Beginner | Connect anonymously, read/write SCADA | Enable OPC UA authentication |
| 2 | Role-based access control | Beginner-Intermediate | Abuse authenticated access | Enforce RBAC so roles limit operations |
| 3 | Logging and auditing | Beginner | Act without leaving traces | Query and analyse security audit logs |
| 4 | Anomaly detection | Intermediate | Inject out-of-range values | Deploy statistical and range-based detection |
| 5 | Function code filtering | Intermediate | Use dangerous Modbus function codes | Filter and block unsafe function codes |
| 6 | Dual authorisation | Intermediate | Bypass single-user safety controls | Require two-person approval for safety ops |
| 7 | Encrypt SCADA communications | Intermediate | Sniff credentials on the wire | Deploy TLS on OPC UA with certificates |
| 9 | Network segmentation | Intermediate | Move laterally across zones | Implement IEC 62443 zones with firewall |
Challenges are independent. Start wherever you like. If you prefer to work through them in order, Challenge 1 is a gentle introduction. If you want to dive straight into architecture, start with 9.
Red team scripts live in scripts/ (organised by attack phase). Blue team defences are managed through tools/blue_team.py.
Terminal 1: Run the simulation
$ python tools/simulator_manager.py
# Output shows exposed attack surfaces:
Protocol servers running: 7
- hex_turbine_plc:modbus (port 10502)
- hex_turbine_safety_plc:modbus (port 10503)
- reactor_plc:modbus (port 10504)
- library_hvac_plc:modbus (port 10505)
...Terminal 2: Reconnaissance with real ICS tools
# Scan for exposed services
$ nmap -p 10500-10600 localhost
# Enumerate Modbus devices
$ mbtget -r -a 0 -n 10 localhost:10502 # Read turbine PLC registers
# Fingerprint device
$ nmap -sV -p 10502 localhostTerminal 2: Malicious write attack
# Trigger emergency trip on turbine
$ mbtget -w -a 1 -v 1 localhost:10502 # Write to coil[1] = Emergency trip
# Watch Terminal 1 for impact:
# [SIM: 5.23s] [WARNING] TurbinePLC: Emergency trip commanded!
# [SIM: 5.23s] [CRITICAL] TurbineSafetyPLC: FORCING SAFE STATETerminal 2: Python-based attack script
# Custom attack using pymodbus
from pymodbus.client import AsyncModbusTcpClient
client = AsyncModbusTcpClient("localhost", port=10502)
await client.connect()
# Read current turbine speed
speed = await client.read_input_registers(0, 1)
print(f"Turbine speed: {speed.registers[0]} RPM")
# Malicious setpoint change
await client.write_register(0, 5000) # Dangerous overspeed setpointThe scripts/ directory contains external attack tools organised by phase:
# Reconnaissance: footprint exposed services
python scripts/recon/turbine_recon.py
# Vulnerability probing: test for unauthenticated access
python scripts/vulns/opcua_readonly_probe.py
python scripts/vulns/modbus_coil_register_snapshot.py
# Exploitation: demonstrate impact
python scripts/exploitation/turbine_overspeed_attack.py
python scripts/exploitation/turbine_emergency_stop.pyThe Blue Team CLI (tools/blue_team.py) provides runtime security operations:
# Check overall security posture
python tools/blue_team.py status
# Query audit logs for attack evidence
python tools/blue_team.py audit query --category security --severity WARNING
# Deploy defences
python tools/blue_team.py anomaly enable
python tools/blue_team.py modbus enable
python tools/blue_team.py firewall add-rule --name "Block attacker" --action deny --source-ip 10.0.0.99This project is under active development. Current implementation status:
| Component | Status | External Access |
|---|---|---|
| Core devices (PLC, RTU, HMI) | ✅ Functional | Via Modbus TCP |
| Safety controllers (SIL2/SIL3) | ✅ Functional | Via Modbus TCP |
| SCADA servers (tag database) | ✅ Functional | Via Modbus TCP |
| Historian (10-year data retention) | ✅ Functional | Via OPC UA |
| Network attack surfaces | ✅ Functional | Real TCP ports |
| Modbus TCP/RTU protocol | ✅ Functional | mbtget, pymodbus |
| IEC 60870-5-104 protocol | ✅ Functional | IEC 104 clients |
| S7 protocol | ✅ Functional | python-snap7 |
| DNP3 protocol | ✅ Functional | DNP3 clients |
| Physics engines (turbine, reactor) | ✅ Functional | Via device PLCs |
| Security logging (ICSLogger) | ✅ Functional | IEC 62443, ISA 18.2 |
| ICS audit trails & alarms | ✅ Functional | All devices integrated |
| Test coverage | ✅ 1570 tests | Unit + Integration |
Legend: ✅ = Complete, 🔄 = In Progress, ❌ = Not Started
Contributions welcome:
- New device types (IEDs, PMUs, relays)
- Protocol implementations
- Physics models (thermal, hydraulic, electrical)
- Security rules and detection logic
- Scenario libraries
Before adding tests, read tests/README.md for dependency ordering. Respect the layering: fix the architecture, not the test.
This simulator is for authorised security research, education, and testing only. Use it to develop and validate PoCs in a safe environment before engaging with real systems under proper authorisation.
The authors take no responsibility for misuse. If you're testing real ICS/SCADA systems, make sure you have explicit written permission and understand the physical consequences.
This project is licensed under the Polyform Noncommercial License.
You are welcome to use this software for:
- Learning and experimentation
- Academic or independent research
- Defensive security research
- Developing and validating proof-of-concepts
- Incident response exercises
- Non-commercial red/blue team simulations
You may not use this software for:
- Paid workshops or training
- Consultancy or advisory services
- Internal corporate training
- Commercial product development
If you want to use this project in a paid or commercial context, a commercial license is required.
See COMMERCIAL-LICENSE.md for details.
This project is actively developed and maintained to support realistic security research and training.
The license ensures that:
- Security research remains accessible
- Defensive knowledge can spread
- Commercial exploitation is fair and sustainable
If you are unsure whether your use case is commercial, ask. Ambiguity is solvable; silence is not.
"The thing about electricity is, once it's out of the bottle, you can't put it back." ~ Archchancellor Ridcully (probably)
Last Updated: February, 2026