Over one weekend in late July, attackers disrupted water and wastewater controls across more than 30 Minnesota communities. Braham lost its treatment plant for two hours. Maple Plain declared a local state of emergency. The suspected entry point was CVE-2021-22681 — a Rockwell Automation authentication bypass with no vendor patch, five years after it was disclosed. Days later, CISA warned every water system in the country to do one specific thing: get your programmable logic controllers (PLCs) off the public internet.
You don’t run a water utility. But operational technology (OT) is everywhere the physical world meets a network — your smart home, a maker project, a solar inverter, a 3D-printer farm, a building’s HVAC. And the way industrial gear gets owned is simpler than most IT attacks, which makes it a fantastic thing to learn. This tutorial builds a completely safe, software-only OT lab so you can see it for yourself.
Safety first, twice. Never scan, connect to, or “test” a real PLC, water system, building controller, or any live OT you don’t own — a mistimed packet can physically break equipment or endanger people. Everything here is a simulated PLC on your own laptop. This is an OT-flavored extension of your ethical-hacking home lab.
Why OT Is a Different Animal
Industrial control systems break the assumptions IT security is built on:
- They can’t just be patched. A PLC controlling a pump may run 24/7 for a decade. “Reboot to apply updates” isn’t an option, which is how a 2021 bug is still live in 2026.
- The protocols have no security. Modbus, the most common industrial protocol, was designed in 1979. It has no authentication and no encryption. If you can reach a Modbus device on the network, you can read and write its registers — turn a pump on, open a valve — no password required. That’s not a bug; that’s the protocol working as designed.
- The impact is physical. An IT breach leaks data. An OT breach can drop a treatment plant offline, exactly like Braham’s.
Put those together and the defensive priority becomes obvious: since you can’t patch fast and the protocol won’t protect itself, the network reachability is the whole ballgame. Keep attackers off the wire and the insecure protocol stops mattering.
Build the Lab: A Software PLC
We’ll use OpenPLC, a free, open-source PLC runtime, so no hardware and nothing physical can go wrong. Run it in Docker so it’s isolated and disposable — see our Docker security guide if containers are new to you.
# Run OpenPLC in an isolated container (bind to localhost only!)
docker run --rm -it -p 127.0.0.1:8080:8080 -p 127.0.0.1:502:502 \
--name openplc openplc/openplc
Note the 127.0.0.1: prefixes — that binds the PLC to your loopback interface only, so nothing is exposed beyond your own machine. Open http://127.0.0.1:8080, log in (default openplc/openplc), and you have a running PLC serving Modbus TCP on port 502 — the same protocol and port the real controllers speak.
Speak Modbus: See How Trivial It Is
Now let’s talk to it the way an attacker would. Install a Modbus client:
pip install pymodbus
Read and write the PLC’s registers with a few lines of Python — no credentials anywhere, because the protocol has none:
from pymodbus.client import ModbusTcpClient
c = ModbusTcpClient("127.0.0.1", port=502)
c.connect()
# Read 10 'coils' (on/off outputs — think pumps, valves, relays)
print("Coils:", c.read_coils(0, 10).bits)
# Now WRITE one. On a real device this could start a motor.
c.write_coil(0, True) # flip output 0 ON — no password, no log-in
print("After write:", c.read_coils(0, 10).bits)
c.close()
Run it and watch a “physical output” flip state because you asked nicely. That’s the entire Minnesota attack in miniature: reach the controller on the network, speak its unauthenticated protocol, change its state. There’s no exploit and no password to crack — the only thing standing between an attacker and the pump is whether they can reach port 502.
Defend It Like CISA Says
CISA’s guidance to the water sector translates perfectly to your gear. In priority order:
1. Get it off the internet — this is 90% of the win.
Bind services to localhost or a private LAN, never 0.0.0.0 on a public IP. Confirm with the attack-surface skills from our file-transfer exposure guide: from another machine, nmap -p 502 YOUR.IP should show closed or filtered, never open.
2. Put remote access behind a VPN gateway. Legitimately need to reach a controller remotely? Don’t expose the PLC — expose a VPN, and reach the PLC through it. A WireGuard tunnel means an attacker has to breach the VPN before they can even see port 502. CISA’s exact phrasing: remote access “through a VPN or gateway device, not directly to the PLC.”
# Minimal WireGuard idea: you connect to the VPN, THEN reach 10.0.0.5:502.
# The PLC is never on a public interface at all.
[Interface]
PrivateKey = <server-key>
Address = 10.0.0.1/24
ListenPort = 51820
[Peer] # your laptop
PublicKey = <your-key>
AllowedIPs = 10.0.0.2/32
3. Change every default credential.
The 2023–2024 water attacks succeeded partly on default passwords on internet-exposed devices. Even where the protocol is passwordless, the management UI (like OpenPLC’s openplc/openplc) is not — change it.
4. Segment the network. OT devices belong on their own VLAN, isolated from your normal computers and especially from the internet. This is the compartmentalization mindset applied to hardware: if your laptop gets malware, it still can’t reach the pump.
5. Watch the wire. On real OT you can’t run antivirus on a PLC, so you monitor the network instead. Want to go further in the lab? Deploy Conpot, an ICS honeypot, and watch what automated scanners try against a fake PLC — a safe way to see real attacker behavior without any real device at risk.
Your OT Hardening Checklist
- Inventory every networked device that touches the physical world (smart home, inverters, controllers, HVAC, printers).
- From an outside machine, scan your public IP for OT ports (502 Modbus, 102 S7, 44818 EtherNet/IP, 20000 DNP3). None should be open.
- Move any remote OT access behind a VPN — never expose the device directly.
- Change all default credentials on management interfaces.
- Put OT gear on its own isolated VLAN.
- Subscribe to CISA ICS advisories for anything you run.
The Bottom Line
The Minnesota attackers didn’t use a zero-day or a clever exploit. They used a five-year-old bug that will never be patched, against controllers that were reachable from the internet running a protocol with no passwords. That combination is unwinnable if attackers can reach the device — and completely defanged if they can’t. You can’t fix the protocol and you can’t always patch the hardware, so you win the same way the water sector has to: take the controller off the internet and put a locked door in front of it. Build the lab, flip a coil with zero authentication, and you’ll never look at an “internet-connected” anything the same way again.
The full incident report — including why a five-year-old Rockwell bug still has no patch — is on breached.company: Thirty Minnesota Water Utilities Hit in One Weekend.



