Traditionally, industrial control systems have been isolated networks with controlled states and very consistent traffic. Developers simply needed to make sure that the devices on these networks could handle the expected traffic. However, nowadays these networks are becoming less and less isolated, increasing the possibility of unusual traffic reaching them. If not properly handled, unusual traffic can force the devices into unstable states, resulting in unwanted behavior such as crashes or security vulnerabilities.
Fuzz-testing is a popular security evaluation technique, in which hostile inputs are crafted and passed to the target software in order to reveal failures and security bugs. Nonetheless, for ICS systems the widespread use of proprietary protocols makes it difficult to apply existing fuzz-testing techniques; which work best when protocol semantics are known, targets can be instrumented or at least large network traces are available.
Fuzzing Overview
Barton Miller, the father of fuzz-testing, observed during a thunderstorm that the lightning-induced noise on his network connection caused programs to crash. The addition of randomness to the software's inputs, triggered bugs that had never been found during the testing processes. After further investigation, Miller found that the types of bugs that were triggered from these tests included race conditions, buffer overflows, failure to check return code and format string problems.
Fuzzing is a strategy for finding bugs in software applications. The intention is through some unexpected combination of inputs, to push the target software into a state that was unforeseen by the developers. A fuzzer generates random inputs - both correctly formed and intentionally malformed - and sends them to the target program. Both the random inputs and the response of the software are logged by the fuzzer and if available, by the software’s own debugging tools. By generating random inputs rather than deliberately designed inputs, a fuzzer can potentially find combinations that a developer would not have expected. Robust software handles unexpected inputs without crashing, this is the reason why fuzzing helps developers to create robust software.
The fuzzing steps are as follows:
Today most software has aggressive input checking and will handle random streams of bytes without crashing. Consequently, current fuzz-testing tools have been adjusted to be more effective on such software, by becoming more selective in how they fuzz the inputs. There usually are multiple layers of processing that data has to go through before it reaches the target software’s application logic whether or not the data has been fuzzed. Fuzzed input has the ability to trigger bugs or to be rejected by any layer of processing it passes through before it gets to the application logic. The fuzzer needs to generate inputs that are clean enough to pass any sanity checks in the application but malformed enough to trigger bugs in the application's logic.
In practice, the most successful fuzzers create fuzzed inputs based on full knowledge of the layout and contents of the software's input. If a fuzzer knows how a specific byte is going to be interpreted, it can manipulate the byte in ways that are more likely to compromise the target. For example, if a particular sequence of bytes contains information on the length of a string that is located in the next sequence of bytes; a fuzzer can try to increase, decrease or set the length value to a negative number. The target software’s sanity checks may miss one of these cases and blindly pass the malformed input on to the application logic.
Fuzzing Methods
There are two different categories of fuzzers, based on how they create the inputs:
- Generation-based fuzzers build their fuzzed inputs based on generation rules, such as how a valid input is structured or what the protocol states are. The most simple generation-based fuzzers, generate inputs by creating strings of random bytes and lengths. Today’s state-of-the-art generation-based fuzzers, fall into the subcategory of block-based fuzzers. BooFuzz -a fork and successor of the Sulley fuzzing framework- and Peach, are both block-based fuzzers. These kinds of fuzzers require a deep knowledge of the protocol structure and test case definition to generate fuzzed inputs. Recent generation-based fuzzer like Vuzzer, are able to automatically generate input test cases for basic communications.
- Mutation fuzzers operate by reading known good inputs and then inserting corruptions and swapping bytes to create fuzzed inputs. Some modern mutation fuzzers make their fuzzing decisions based on a description of the software's input layout. Other mutation fuzzers do not need to know anything about the structure of the data they are fuzzing, they can blindly read known good inputs and mutate without knowing the semantics of the protocol they are fuzzing. Most mutation fuzzers use previously recorded network traffic as a basis for mutation, although there have been some inline fuzzers that read in live traffic. Radamsa is an input generation tool for basic protocols to identify field boundaries. LZFuzz framework is an online fuzzer which intercepts traffic directly, analyzes it with the Lempel–Ziv compression algorithm and sends the manipulated packages to the device.
Fuzzing Proprietary Protocols
It is generally believed that if a fuzzer can understand and adapt to its target, it will be more successful than a fuzzer that does not. Therefore, it is important for fuzzers to be able to take advantage of any knowledge available about the target protocol. When no protocol specifications are available, we can reverse engineer the protocol manually or with the help of debuggers. In practice, this can be extremely time-consuming and thus is rarely an option for ICS systems. Furthermore, it is not always possible to install debuggers on some equipment, making reverse engineering even more difficult. Consequently, it is important to use fuzzing tools that can work efficiently on well-known ICS protocols such as Modbus, DNP3, OPC and Profinet and also on proprietary protocols, without any knowledge of the protocol they are fuzzing.
ICS Protocols Fuzzers
Numerous fuzz testing suites targeting ICS protocols are available:
- beSTORM offers a commercially available EtherNet/IP fuzzing tool.
- Aegis is a smart fuzzing framework for Modbus, DNP3 and the IEC104 protocol.
- Peach - with a commercial and a community version - has multiple tests for both systems and network protocols, including protocols from the industrial world such as Modbus, DNP3 and BACnet. In addition, it has enough documentation to be able to create and model the different tests that you want to create.
- Defensic is a commercial automated fuzzing framework with support for a wide variety of ICS protocols such as Modbus, Profinet, DNP3, OPC, BACnet, IEC104 and more.
In the open source arena:
- Sulley fuzzer includes modules for popular ICS protocols such as DNP3, Inter-Control Center Communications Protocol, and Modbus, although the tool seems to be unmaintained.
- Boofuzz is a fork of the Sulley fuzzing framework which is actively maintained.
- LZFuzz, developed at Dartmouth, fuzzes SCADA communications with unknown protocol structures.
- ENIP Fuzz is an ICS fuzzing program that uses the Python-based packet manipulation tool (scapy) to craft customized fuzzing inputs. It targets fields within ENIP and CIP request packets.
- Radamsa is a popular mutation-based fuzzing tool.
- Vuzzer is an Application-aware fuzzer.
- Profuzz is a Profinet fuzzer based on scapy.
ICS Fuzzing Tests
The State of Fuzzing 2017 is based on 4.8 billion test results from anonymous customers using Synopsys Fuzz Testing - Defensic - from Jan. 1 through Dec. 31, 2016. The report provides insights into the protocols used by different industry verticals and the relative maturity of those protocols. When grouped by industry vertical, the protocols demonstrating the least maturity - i.e., highest number of failures recorded over the shortest amount of time - and therefore the highest risk, were found in Industrial Control Systems - ICS -. Four protocols - IEC-61850 MMS, IEC-104 Server, OPC UA, and MODBUS PLC - each had time to first failures recorded in under 5 minutes:
Conclusions
Fuzzing the implementations of industrial network protocols such as Modbus, DNP3, Profinet, OPC, IEC104 and proprietary protocols, is an important first step towards obtaining insights about the resilience of the systems against new threats, and is also a big step towards developing more secure industrial control systems. The protocols used in ICS systems are no longer isolated, instead they are increasingly interconnected. Fuzz-testing can quickly and efficiently test these systems for possible bugs and reveal security weaknesses that may result in unwanted behavior such as crashes or security vulnerabilities. However, these type of tests must always be performed on non-production environments and lab systems to avoid impacting production systems or safety network components.
Do you want to learn more?
We are giving a two-days training about advanced ICS hacking at HITB Singapore.
Get your ticket!
https://conference.hitb.org/hitbsecconf2020sin/sessions/2-day-training-2-advanced-ics-hacking/.
References:
- https://hal.inria.fr/hal-01571775/document
- https://www.researchgate.net/publication/290732323_MODBUS_protocol_fuzzing_for_cyber-security_evaluation_of_industrial_control_systems
- https://dspace5.zcu.cz/bitstream/11025/35426/1/Niedermaier.pdf
- https://www.gondree.com/pdfs/tacliad_icss_17.pdf
- https://github.com/roddux/fuzref
- https://www.synopsys.com/content/dam/synopsys/sig-assets/reports/state-of-fuzzing-2017.pdf
Yamila Levalle
Security Researcher at Dreamlab Technologies