Got MODBUS? Please Check!

In the past three years, we have been fortunate to have been given the opportunity to study industrial control systems (or 'control systems' for short) in excruciating detail for vulnerabilities, exploits and mitigations. While I am a relative newcomer in industrial control security when compared to people like these guys, what we discovered in 2020 was worthy enough to write about even if only as a brief post.

When you are finished reading, please ask yourself and your team, "Do we have any MODBUS on our network? What are we doing to protect those devices from attack?"

MODBUS is normally found in industrial control environments and factories for process automation. It is not normally used in office environments except for building control (a future article). This article is geared towards any reader who operates an industrial environment or factory or a professional who supports such an environment.

What is MODBUS?

No one should be asked to learn about a network protocol like MODBUS while take a coffee or browsing break, but it is important to cover the basics as a framework for my point later. The folks at Control Solutions Minnesota write a very useful introductory tutorial on MODBUS but the key takeaway points are as follows:


  • is an industrial protocol standard that was created by Modicon, now Schneider Electric, in the late 1970's
  • is defined as a master/slave protocol, meaning a device operating as a master [the one you will most likely interact with] will poll one or more devices operating as a slave
  • remains the most widely available protocol for connecting industrial devices

While the last statement is questionable, there is no doubt that MODBUS is a widely used protocol in industrial control. We won't go into any real detail about MODBUS RTU versus MODBUS TCP but for the sharpshooters out there, we explicitly focus on MODBUS TCP for the remainder of this post.

Ok, you are still reading, what is the point right?

Well, one of the reasons MODBUS is so widely used (still today), and one of the reasons for taking time to write is that because MODBUS is so simple, it's also so dangerous. There are a very limited number of message types in MODBUS! Very few network protocols are this simple! This means they are simple to attack.

How is MODBUS used?

To put this in context, in one of the scenarios we study, we examine three different programmable logic controllers or PLC (a term we will cover another day, for now think embedded computer) and their use of MODBUS to control water pumps that raise and lower water in reservoir tanks and used a secondary sensor to monitor the level of water supply to determine when to turn the pumps on and off. In this type of scenario, an aggregation device (a computer) polls the PLCs every few seconds to get data from the PLC by sending the READ COILs, READ INPUT REGISTERs and READ HOLDING REGISTERs (using the MODBUS terminology) messages to determine the status of the pump and the level of water. If the water level is low, the pump is turned on (WRITE COIL). If the water is high enough to move the level sensor, the water turns off (WRITE COIL). This computer forwards this data onto a human machine interface or HMI (again a term for another day) which displays the data on a screen for a human to read and override the pump switches on and off. Consider that in a picture:


We can show an example of the network traffic (for those that are interested) of how a PLC implemented in the above scenario may behave when nothing is wrong. Look at the repetitioning the Info column. It is the same commands being sent repeatedly from the controlling computer to the PLC.


What does it mean?

If you are using MODBUS for automation of a manufacturing process or monitoring systems and environments, it very likely works effectively using a low-cost device. Despite this and to put it simply, it's at risk. Do not simply accept that your firewall may prevent attacks. Please consider what additional layers of security you can employ. Those of you subject to the CMMC standard may have no choice. Your team(s) may have already employed security but do not assume, ASK. What happens if your PLC is attacked? You may not just lose income; you could lose life. Is your PLC critical? Does it monitor or control a critical function for you?

It turns out, it is exceedingly simple (one exception called the Transaction Identifier is not worth elaborating on) to attack the PLC in our previous example. Consider the same image we show previously one more time but now with an attacker on the local area network where the PLC is configured. If an attacker can reach the PLC, they can inject their own traffic and the PLC will likely respond accordingly.

Make sure you understand, for this attacker to event be present, multiple dominoes must have already fallen:

  • The attacker must gain remote access to a victim network (Phishing, Server Compromise, WIFI keys).
  • The victim must be using MODBUS on their network.
  • The attacker must identify the MODBUS master and slave device through network monitoring using potentially promiscuous sniffing (which is easy to spot).
  • The attacker must monitor the network for a period to establish 'normal' behavior. For there to be an attack, they must know what payload(s) to use.

We update our previous image to demonstrate the attacker next:


What does the attacker Do?

To provide an extremely simple demonstration we show sample Python source code. We took a sample network capture from one of our test environments and ran it through Python which took less than 1 hour to create. Let us do this in stages.

Remember, we are reading from PCAP in this example. It is simple to change this to a live connection instead, but we cannot show everything in 1 shot. We use the StackOverflow example answer from this URL for our steps:

The folks at West Oahu University have a very concise document about forging MODBUS which I recommend:

NOTE: Make sure you understand. The logic we present here will apply to any MODBUS device but if you chose to replicate this approach, you will need to prepare for a lot of trial and error changing values. We also leave off forging packets to change running state.

  1. First, we show Python using the wonderful scapy API to detect MODBUS traffic. This will simply print every MODBUS request found. Think cause and effect. If there is a request (from the Master) there should be a response.
    Got MODBUS
    This will identify the master device(s) that are likely monitoring the slaves in the network.
  2. Next, we can detect the slave devices with a single change.
    Got MODBUS
    This will identify the slave devices.
  3. What now? Well in our example, an HMI is monitoring the slave(s) in this network. We end by showing PCAP to forge status responses building on the last snippet. We want to copy one of these ModbusADUResponse packets and change the values before we send it. Before this, look at a scapy reprint of one of our example MODBUS packets with the sensitive details removed:
    ###[ TCP ]###
                    sport     = 502
                    dport     = 8374
                    seq       = XXXXX
                    ack       = XXX
                    dataofs   = 5
                    reserved  = 0
                    flags     = PA
                    window    = 229
                    chksum    = 0x198944
                    urgptr    = 0
                    options   = []
            ###[ ModbusADU ]###
                    transId   = 0xXXXXe
                    protoId   = 0x0
                    len       = 7
                    unitId    = 0x0
            ###[ Read Input Registers Response ]###
                    funcCode  = 0x4
                    byteCount = 4
                    registerVal= [22535, 22339]
    The fields we are concerned with are at the bottom of the packet we just printed. Forging is simple. Once you detect a packet sending status from slave to master, make a copy of that packet and start changing fields inside like the following completely random values:

    if mb.ModbusPDU04ReadInputRegistersResponse in packet:
        forged_packet = packet.copy( )
        forged_packet.funcCodef = 0x99
        forged_packet.byteCount = 4
        forged_packet.registerVal = [22999,22888]

    Now that we have changed fields in this cloned packet how do we send it?

    sendp(forged_packet) #sending packet at layer 2

    To repeat, you won't see much success simply with a copy/paste of this code, but it absolutely is the basis for forging MODBUS to compromise systems with potentially disastrous side effects.

What Should We Do?

As I get older, I find myself preferring simple over complex. What should you do? We can only provide suggestions here:

  1. Are you (or your customer) running MODBUS?
    If you have a manufacturing or industrial process or support a customer that has one you should attempt to find out if that process uses MODBUS TCP. Just start by asking if you have any MODBUS on your network.
  2. Run nmap (or masscan) scan for TCP/502
    You can scan (or ask a team to scan for you) the subnets in your network for any hosts that have this port open. You should be VERY careful on how you do this because there are some control systems out there you just do not scan. If you choose to run this scan you can manage risk by only scanning for this port and doing so after-hours or on the weekend. If your processes cannot be interrupted, you could consult with the engineers that setup your network as there are a multitude of ways to passively detect this protocol.
  3. Is your MODBUS device up to date?
    You should check with your network team (or you if you are the network team) and determine if the MODBUS device is up to date with its firmware. This is a direct avenue of attack that you may recall reading about recently, see here.
  4. Is this network monitored by IDS?
    If you discover you have MODBUS on your network, you should immediately ask yourself if there is an IDS monitoring the subnet where MODBUS was found. There is almost no excuse today for not running an IDS as you can use a Raspberry Pi or low-cost PC configured with Linux to do this.

    If you already have IDS, make sure to find out if your IDS is configured with MODBUS specific rules. This is a crucial step that is easy to miss. For example, Suricata does not enable MODBUS by default, it must be enabled. For more information checkout this presentation.

    If you are lucky enough to afford a product from a vendor who specializes in these scenarios they serve as an IDS already. You do not need to double up on the security unless you are a glutton for punishment.
  5. If necessary, purchase a PC, choose your IDS and install ASAP.
    Depending on your network size, you can get away with a Raspberry Pi (8GB of RAM, do not settle for less) or a small form-factor PC to run your IDS. It will be more expensive to download, install make sure this PC has IDS software configured to monitor for MODBUS and finally send your logs somewhere they can be reviewed.

    If there is enough interest, we can write about our recommendation on which open-source IDS to use for industrial control security in the future.
  6. Monitor the IDS logs.
    It is like going to the dentist. You must do it. Monitor the logs and look for alerts for your MODBUS devices.
  7. Consider network engineering.
    If you reach this point, I am impressed. You can strengthen your security if you consider how you might be able to move the MODBUS device into an isolated subnet if it is not there already. The Purdue Enterprise Reference Architecture (PERA) is an example approach to where to place control systems in relation to your users and Internet connectivity. This is a separate article which we can address in the future.