DEV Community

Cover image for A Brick, a Post-it, and admin/admin — How I Learned OT Security by Building a Factory in My Bedroom
Andrea Oliva
Andrea Oliva

Posted on

A Brick, a Post-it, and admin/admin — How I Learned OT Security by Building a Factory in My Bedroom

THE BRICK AND THE POST-IT

My chemical plant's first vulnerability wasn't a bug, a piece of malware, or a port left open to the internet.

It was a brick.

Brick-to-block-open-the-door

In the computer room — the one with a door held open by a brick — I found a sticky note with credentials on it. They weren't even the right credentials for the system I wanted to break into. But they made me think the way whoever wrote them thinks, so I tried the most obvious pair in the world: admin / admin. And I was in.

A brick propping open a door that should be locked. A sticky note guarding a password. A factory-default admin/admin. Three layers of security, three layers defeated — not by a genius hacker, but by a student on day one, carrying no tools at all.

If that happens in the IT office, it's a problem. When it happens on a factory floor, where that same computer commands real pumps and valves, it's a different planet.

The problem: learning OT without a factory

I study computer security. Lately I've been drawn to OT — operational technology, the security of factories, power plants and industrial systems. The problem is simple: you can't learn to defend a factory from a book, and nobody will lend you theirs.

Then I realized the answer was already inside the question: if you don't have one, you build one.

The build: three commands and a lot of patience

The lab is called GRFICSv3: an open source project that simulates an entire chemical plant — the PLC, the operator interface, the network, even the server rooms — inside Docker, on a home computer.

Three commands and done:

curl -O https://raw.githubusercontent.com/Fortiphyd/GRFICSv3/main/docker-compose.yml
docker compose pull
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

"Three commands and done" is the story version. The real version includes my first error, arriving right on schedule at command number two:

permission denied while trying to connect to the docker API at unix:///var/run/docker.sock
Enter fullscreen mode Exit fullscreen mode

If you hit this — and you will — here's the diagnosis: the Docker daemon is running fine, but your user isn't in the group that's allowed to talk to it. The fix is one line:

sudo usermod -aG docker $USER
Enter fullscreen mode Exit fullscreen mode

Then close every terminal window and reopen them: group membership is only read at login, so the old terminal stays "outside the group" even after the command succeeds. Verify with docker ps (no sudo) — if it answers, you're in.

Why this happens, in two lines: Docker communicates through a Unix socket (/var/run/docker.sock) reserved to members of the docker group — and belonging to that group effectively grants root-level powers over the machine. Perfectly fine on a lab PC at home; on a company server, it's one of those things somebody should go check.

Then the factory switched on. For real: a 3D chemical plant with tanks, pumps and valves at work — and the computer rooms: one locked with a key, the other held open by a brick. Same plant, two doors, two security philosophies. In OT the perimeter is physical before it is digital: whoever holds the key — or the brick — to the PLC cabinet, holds the plant.

Day one inside the plant

Lab 3D

Using the PLC's default credentials — the same ones you can find on the internet — I walked straight into the plant's brain. Then into the operator's interface. And with one click on a pump, I watched the 3D plant react.

Translation: with no particular training, on day one, I already had control of an industrial process. It was my own lab, entirely legal, designed for exactly this. But it's the same shiver — I later learned — that control-room operators feel when they see a cursor moving on the screen all by itself.

The Plant Under X-Rays

tcpdump

The day after, the factory stopped being a video. It had to become a conversation.

Modbus — the protocol that runs the world's factories — has a feature that sounds like a joke: there is no login. Not "weak authentication" — the concept of identity simply doesn't exist. Born in 1979 for serial lines, wrapped into TCP in the nineties, it arrives today on port 502 of any PLC — and whoever reaches it holds the same authority as the engineer who programmed it.

So I asked my first-ever question to an industrial plant: eight lines of Python, the packet built byte by byte. (My second documented error came immediately: pip refuses to install anything — the system Python is "externally managed". Fine: the hard road turned out to be the right one, because with a library I would never have seen the protocol naked.)

First reading: all zeros. Second: all zeros. I was reading the right page of the wrong book — registers 0 to 9 are empty; life is elsewhere. Like a polite burglar looking for the safe, I did the smartest thing available: I went and read the legitimate navigator's map. Inside the operator interface sits the list of what the plant polls every day: AFlow, offset 101, input register. Flow A.

I widened the reading to that zone and the factory started talking to me: twelve live registers. Values drifting slowly (levels, temperatures), values pinned at full scale (valves 100% open), small values breathing (compressor B).

Then the experiment that closes the circle: I moved to the other side of the desk — the operator interface — and closed a valve, like a good technician. I went back to my terminal, the unauthorized one, and read again: two registers had vanished. The valve status: zeroed. The flow: zeroed.

I had just watched the command → sensor chain from the point of view of someone who isn't supposed to see it. From the office network. Without authenticating. Without anyone knowing I was watching.

That's the moment "OT security" stops being a word and becomes a feeling in your stomach.

The Attack

The reconnaissance had made everything surgical: I knew exactly where to write. The setpoints lived in holding registers 10 through 13, the global commands in coils 0 and 40. All that was left was doing it — and the first write was a caress: rewriting to the purge register the value it already had. Modbus answers writes with an exact echo of the request, and the echo came back identical, byte for byte. Twelve bytes in, twelve bytes out: the PLC had said "roger that" to someone who wasn't its operator.

Then the real command. Purge setpoint: from 65535 — wide open — to 32768, half travel. In my monitor, the cycle changed amplitude: where it used to peak near sixty thousand, it now stopped at half. And in the 3D simulation, the valve moved: first at 100%, then at 50%. At my command. Without anyone having given me permission.

Then the next step: the manual-mode coil. The automatic cycle stopped entirely and the valve pinned itself to my number. Not "roughly thirty-two thousand": exactly 32768. The rhythm was mine, the position was mine. From a machine on the office network, with no authentication, I had full control of a plant line.

The last command is called Run. Twelve bytes, and the factory stopped: main flow to zero, level frozen, valves in their safe positions. I switched it back on right away — and it came back halfway: the main process stayed down. Broken? No. The plant was in manual mode and was obeying, with absolute coherence, the setpoints written inside it — including a feed at zero that I had never touched. The factory wasn't broken: it was executing an incomplete set of commands. Mine.

That's the moment I understood how real industrial incidents are born: almost never from malice. Almost always because someone — authorized or not — commands with a partial picture, and the machine takes them literally.

So I did the last thing, the one movies never show: I put everything back the way it was. Original setpoint, automatic mode, Run on. The main flow climbed slowly back to 41,972 — the starting number, identical. The factory had never noticed me.

No alarm. No log. No trace of me.

And that's the sentence that closes the attack and opens the defense: twelve bytes to stop a factory, and nobody who could ever know you were there. Now it's the defender's turn.

The Defense

Firewall

The next day, I crossed to the other side of the barricade. And the first lesson as a defender is brutal: Modbus has no password to change. The protocol doesn't own the concept. You don't put a lock on a door that was never built to have one — you protect the path.

So I changed the passwords that do exist — the PLC's web panel, the firewall console (and my first-ever defender password, I confess, was "psw1234": the human factor isn't cured by a lab, it's supervised for life) — and ran the attack again: it still worked, identical to yesterday. Passwords protect the panels; the command channel doesn't have any.

After checking the firewall, I found the culprit: at the top of the rule list, there was an "allow everything" with an honest label attached: "TEMP — allow all traffic for troubleshooting — DO NOT LEAVE IN PRODUCTION." Left in production. Firewalls only look at the first rule that matches.

With the orphan rule deleted, I rebuilt it the right way: an allowlist — first the permission for the only machine that must talk to the plant (the operator's interface), then the denial for everyone else. Specific rules on top, general rules below.

The measurement: the twelve bytes that stopped the factory yesterday die in a timeout today. The operator watches their values move. The plant produces. Two opposite outcomes, same protocol, one day apart: the difference wasn't made by technology — that was already there, in both cases. It was made by care.

And then the ending nobody had written for me. On the day of the perfect restore — setpoints rewritten, modes returned, flow back to exactly its starting value — the plant's central tank exploded. Not while I was attacking: the day after, while I was defending. Less material in the vessel, the factory limping on in degraded mode.

The command restore had succeeded. But the physical state of the process had shifted days earlier: purge manipulated, partial restart, unstable equilibrium. The damage was already in transit — and no firewall stops a package already shipped.

That's the line I carry with me, as a student and as a future professional: commands are reversible; consequences are not. Data can be restored; physics cannot. That's why industrial security isn't an IT specialty: it's a trade of its own — where the defender's last rule isn't in any manual: keep watching the plant even after you've won.

Why you should care (even if you're not in security)

Three lines of technical truth first: Modbus has no authentication and no encryption — in Sicily, in Ohio, in Osaka, same bytes. A port 502 open from the office network is a finding everywhere on Earth. The physics doesn't care about jurisdictions.

If you think this is a European compliance thing, look at the record. Colonial Pipeline (US, 2021): one ransomware infection, fuel shortages along the East Coast, a national emergency declared. Oldsmar, Florida (2021): an intruder remotely changed a water treatment plant's chemical dosing. Stuxnet (Iran), the Ukrainian blackouts (2015, 2016), Triton (Saudi Arabia, 2017 — malware aimed at the safety systems of a petrochemical plant). The geography changes; the twelve bytes don't.

The laws are just local translations of the same lesson. Europe wrapped it into NIS2 — large companies must audit their suppliers, and suppliers are often small businesses with one PLC and one default password. The US has its own stack: TSA security directives for pipelines (post-Colonial), NERC CIP standards for the power grid, CISA's relentless ICS advisories, and CIRCIA — mandatory 72-hour incident reporting for critical infrastructure, on its way. Internationally, IEC 62443 is the common language of OT security. And note the mechanism that makes this everyone's business: questionnaires travel. A small factory in Catania supplying a German utility receives the same security questionnaire as a vendor in Ohio supplying a Dutch one. Requirements cross borders faster than goods do.

Besides: I built my chemical plant in my bedroom, for zero euros, in one evening. The barrier to entering this field is no longer equipment. It's curiosity.

Top comments (0)