About Modbus TCP

Vanilla Modbus TCP is a simple protocol that utilizes a basic request-response design. The specification is available from Modbus.org. at no charge.

The protocol transports application layer messages uses a simple envelope called the MBAP. The application layer itself supports function codes that completely determine the shape of the contents.

Modbus servers are easy to fuzz test. You can simply iterate through the various function code models. Modbus clients are more challenging, because any decent implementation will only parse response data that appears to be from the request. In other words, you will usually only be testing the parser for that particular request. This is very different to a DNP3 that has function + object semantics that allow for a nearly infinite number of permutations. To thoroughly test a Modbus client, the tester must iteratively reconfigure and test every possible function code that can be sent from the master.

Functions supported

The Modbus fuzzer provides good coverage via modeling of the following commonly-used function codes:

  • Read coils (0x01)
  • Read discrete inputs (0x02)
  • Read holding registers (0x03)
  • Read input registers (0x04)
  • Write single coil (0x05)
  • Write single register (0x06)
  • Write multiple coils (0x0F)
  • Write multiple registers (0x10)

Future enhancements:

  • Additional function code modeling
  • Procedures that inject random application layer data

Health checks

The Modbus slave tests optionally use a simple READ_COILS request as a health check. This check can be disabled.

Modbus clients do not send a health check message, as there is no request you can send to a client to stimulate a response. Instead, the fuzzer waits for the next request as a health check, and then sends the next test frame with the same transaction id as the request.

Parameters

Parameters differ for the slave and master tests.

Slave

  • unitid - The unit id of the modbus slave - This is the most common parameter and must be adjusted for to match the configuration of the target.

  • retries - Health check retries - The number of times the health check will be tried before failing the test procedure.

  • timeout - Read timeout (ms) - The read timeout in milliseconds for the health check

  • healthType - Health check type - The health check type to use [ReadCoils, None]

  • healthMode - Health check mode - Enumeration [Before, After] that determines when the health check occurs relative to the test frame.

Master

  • timeout - Read timeout (ms) - The read timeout in milliseconds to wait for a request before failing the test procedure.

Procedures

  • pdu-request - Slave PDU request - Sends a large number of malformed and unexpected PDUs to a slave. Can be re-run with multiple seeds.

  • pdu-response - Master PDU response - Sends a malformed or unexpected response after each request from the master. This procedure should be run for each request type. Most Modbus masters allow polls to be configured at a arbitrarily high rate. At may not be possible to test write coil/register functionality any way other than manually without the source code.

Test Plans

Your Aegis installation of contains recommended test plans for Modbus slaves and masters.

  • plans\modbus-master.xml
  • plans\modbus-slave.xml

In most cases, the only parameters you need to adjust will be the unitid of the target when testing slaves, and possibly the host (IP) parameter if you're testing an external target. Refer to the parameters section if you need to adjust timeouts or health checking.

The recommended test plan repeats some of the procedures with different fill or random seeds.

You should repeat the full master test plan with a high-frequency request for each function code that you can configure to do so. For instance, you might have four master configurations that respectively scan:

  • Read coils (0x01)
  • Read discrete inputs (0x02)
  • Read holding registers (0x03)
  • Read input registers (0x04)

If you can configure your software to send control requests, run the suite against those function codes as well.