WHITEPAPER Reversing Proprietary SCADA Tech
WHITEPAPER Reversing Proprietary SCADA Tech
Quarkslab
Abstract
1
SCADA systems can be found in the core of many critical infras-
tructures, such as nuclear plants, water distribution circuits or alarm
systems.
This article is about the security study we carried out on recent,
proprietary and state-of-the-art SCADA technologies. We will mainly
focus on the methodology followed to reach our goals, as well as on some
techniques we used. This will cover fuzzing, black-box and white-box
reverse-engineering. We will talk about the reverse-engineering of the
industrial protocol, a part of the protocol stack of a SCADA supervisor
and the PLC2 firmware.
This study revealed multiple security breaches in the assessed technolo-
gies and allowed to reveal most of this protocol’s cryptographic system. To
illustrate one of these vulnerabilities, we will present an effective attack.
Disclaimer: The terms used to refer to the studied technologies are
deliberately imprecise.
1 Introduction
1.1 Motivations
In response to some recent attacks on critical industrial systems (for example
Stuxnet[8], that managed to put out of order uranium centrifuges in Iran, or
more recently Havex, a RAT targeting SCADA system), some vendors have
done, and are still doing, a lot of efforts to raise their products’ security and
resilience against malicious attacks.
The history of (in)security in SCADA systems makes the analysis of new,
more secured systems very interesting.
1 Supervisory Control And Data Acquisition, see section 1.2 for more information.
2 Programmable Logic Controller
1
1.2 What is a SCADA System?
Before getting to the main topic of this article, this paragraph quickly presents
what SCADA systems are and the purpose of some of the components we will
be dealing with in this article.
1.2.1 Definitions
The SCADA acronym refers to a subset of what is called “industrial control
systems” (ICS).
An ICS is an information system that is aimed at controlling physical systems:
sluice gates, motors, temperature or pressure sensors, etc. They can notably be
found in power plants, water distribution circuits, alarm or access control systems,
video monitoring, etc. Actually, many systems can fit into this definition.
The SCADA part refers to the monitoring and control of the physical process.
1.2.2 Components
The SCADA part of an ICS is mainly composed of three elements:
1.2.3 Particularities
Industrial devices, and particularly PLCs tend to be in function for many years
(some can run for 30 years). They also are very expensive and complicated to
replace: the devices themselves are quite expensive, but changing them also means
reprogramming all the new ones and integrating them to an existing system, or
rebuilding it from scratch. One of the consequences of this phenomenon is to
find a lot of old equipment in industrial systems.
When they are running, some ICSs (particularly the most critical ones) are
very delicate to update. When there is no complete duplication of the system, it
has to be stopped for update. When the duplication degree allows to remove
2
SCADA HMI Station
PLC
Hmi process
Shared TCP Industrial
Memory
Broker protocol Firmware
Hmi process
(when multiple
instances)
3
IHM Fuzzes
IHM Fuzzer worker valid
Project
packets
IHM Shared TCP TCP/IP with
IHM Fuzzer worker Radamsa
Project Memory Broker
IHM
IHM Fuzzer worker
Project
• the older one, that had no (or almost no) security mechanism: this one is
rather well known by the community;
• the newer one, on which we focused the most, that implements some actual
security mechanisms (that will be studied later), but almost no public
resource is available.
That said, a trick is involved here: the HMIs do not directly communicate
with the fuzzer. If it does not prevent from analyzing a crash provoked, it is
however way harder to retrieve the network capture that caused it. Indeed, the
TCP Broker do not offer any documented (or easy) way to know which HMI
instance uses which TCP connection.
To solve this problem, we had to find out how to associate a network com-
munication to an HMI process PID. We did not find any way to change the
destination TCP port of the communication (it cannot be changed in the HMI
4
project) and the source port does not give any information on the PID that uses
the TCP connection (because of the TCP Broker).
A trick based on IP aliasing has finally been used: each project is configured
to connect to a different IP address3 and the workers are configured to listen
on all these IPs on the same network interface. With this solution, the script
starting and catching the HMIs crashes on the client side generates HMI project
files with different IPs, and is able to associate an HMI PID with the IP of the
project that was passed as an argument to it. It then asks to the fuzzer the last
capture associated to this IP address. This capture is necessarily the one that
made the HMI crash, since all the HMIs started at a given moment connect to
distinct IPs.
This allowed us to put up a fuzzing architecture where resources of each
VM are used at their best and where it is possible to run n VMs containing i
HMI processes each and m VMs running j workers, for all m, n, i and j such as
n ∗ i = m ∗ j.
2.2 Results
After a very short time (around 5 minutes of fuzzing a single process) the first
crash occurred.
It was caused by an improper check on a bound, allowing to access an
arbitrary offset in an object table. A virtual method of the accessed object is
then called by the program. The crash happens during the negotiation part of
the protocol, in the first packets.
Whether this bug is exploitable or not has not been confirmed yet, but it can
at least make an HMI crash with 3 packets, without any kind of authentication
necessary. In this protocol, the HMI is the client and the PLC the server. To
perform this attack, it is necessary to succeed in intercepting a TCP session
establishment and answer in place of the PLC with the spurious packets. That
said, another manipulation allows to easily reset the TCP connection, making
things a lot easier.
We since reported it to the vendor and it has been patched by the vendor.
5
The approach we used relied on differential analysis (inspired by [7] and [2])
Thanks to a tool that allows to realign the hex-dumps of packets (hexlighter[4])
and to highlight the differences between two consecutive packers, we learn a lot
on the protocol’s structure.
Let us take a test sample where the supervision is supposed to read all the
PLC’s input and output bits, while we make them vary by changing the input
voltages. In this example, we will only look at the answers from the PLC to the
supervision.
Hexlighter allows (amongst other features) to color the hex-dumps in a way
that differences stand out. The result is hardly readable on these printed pages,
thus a graphical representation replacing each byte by a colored square has been
proposed. Figure 3 shows the result of the technique by filtering only the answers
fro the PLC:
• A black square represent a lake of value (for example when a line is shorter).
They are not used in this example.
• A green square represent a difference with the previous line (packet).
• The brighter the green color is (a gray in a paper print), the greater the
difference is (in absolute value).
• In the bottom figure, each line is compared to the first one rather than to
the previous one.
• A stable state (the packet’s form does not vary anymore) is reached at the
fourth packet sent (these packets are not shown on the figure for clarity
purpose). We can deduce that the first three packets may be part of a sort
of handshake, the other ones are the communication’s body. Let us forget
the handshake for now.
• A sequence number is clearly visible at offset 12 of all the packets (the size
of this field will be verified by letting the value increase until it is reset to
0). On figure 3, it takes the form of a vertical line at offset 12 (slightly
shaded on the bottom figure as the difference with the sequence id of the
first packet grows with time).
• A second sequence number appears at offset 73. This one grows by steps
of 2; thus the gradation more pronounced on the bottom figure.
• At the end of each packet, a 32-byte field with high entropy differs greatly
for all packets. This field strongly suggests the presence of cryptography,
possibly a HMAC or a hash.
• One byte (actually a single bit) varies in the middle of some packets. These
variations are coherent with the I/O variations applied to the PLC during
6
Figure 3: Representing differences between successive similar packets
Each line represents one packet. A the top, difference with the previous packet,
at the bottom, difference with the first packet.
the capture; we deduce that these fields represent the PLC variables read
by the supervision. The green lines in the middle of packets on the bottom
figure represent the time lapse where a variable value is different from its
value in the first packet.
Looking closer and comparing the packets in different ways (for example the
fifth packet from multiple different connection), one can deduce the semantics of
many fields. Each parameter change (write instead of read, value modification,
new session, etc.) tends to reveal its impact in the packets diffs. This method’s
key to success is to be able to easily associate a parameter change with its impact
in the network traffic.
7
The first issue we encountered was the complexity of the whole program:
multiple processes communicate through shared memory pages, they are heavily
multi- threaded, rely on asynchronous events, and embed dozen of DLLs whom
names are often not really evocative.
The main suspect SHA-256 is found, as well as other hash and encryption
algorithms (especially AES, we will come back on this later).
Setting up a breakpoint on the sha2_process function of the SHA-256
implementation in hmi_core.dll, one can verify that this function is actually
called during the communication, and is even called each time a packet is sent
or received.
8
Back to static analysis, one can find the SHA-256 functions are used to
compute a HMAC. Debugging the program gave us further information, the
packet’s payload is passed as input to the HMAC algorithm alongside what can
be called a session key of 24 bytes. Moreover, for each packet, the HMAC output
matches wit the 32 bytes with high entropy located at the end of the packet.
Using a HMAC for each packet allow to ensure packet authenticity as the
key is specific to the session and exchange in a secure (confidential) way. We
have made an important progress here, now the question is where does this key
come from? How is it exchanged?
• The first packet that is sent by the supervision is always the same (except
for the sequence id) and is sent before the generation of the session key.
• The PLC answer is constant, except for 3 scattered bytes and a block of
20 bytes that are always different
• The second packet from the supervision always vary in a signicative way
from one session to another. A block of 132 bytes is the most interesting;
it’s the only block that is large enough to contain the session key (either it
is encrypted or encoded).
• The PLC answer is only made of an applicative ack.
• The third packet sent by the client (supervision) is authenticated with a
HMAC.
• The same is true for the third packet sent by the server (PLC).
9
It seems obvious that the session key is actually exchanged in the second
packet sent by the client.
10
Client Server
hello packet
l. 20 rand. bytes
hello packet inc
llenge
chall: 20B cha
payload + HM
ACsha1 (key = K
sess , text = payload)
payload)
Rest of the com-
ACsha1 (key = Ksess , text =
munication payload + HM
...
have not totally recovered. The password based authentication mode was not
yet fully examined at the time this article is written.
The cryptosystem mostly relies on standard and solid primitives that we have
been able to identify. However more time is required to analyze the obfuscated
part and thus give a motivated opinion on the complete system. There are still
unknown parts that could lead us to think that these algorithms make use of
stored secrets (maybe in the firmware or PLC’s hardware) to exchange sensible
data. These secrets could be common to all the PLC of a same model and with
the same firmware version.
At this point, it seems sensible to look on the PLC side and more precisely
look at the firmware, in particular to verify if the counter-part of the obfuscated
functions was also obfuscated on the firmware. The hypothesis is that equipment
with lower resources may use lighter or no obfuscation.
In case this hypothesis is confirmed, it could probably allow to easily identify
which algorithm is used. That part of the analysis is covered in section 5.
However before digging into that part, we will describe the attack that allows to
steal an authenticated session.
11
4 Stealing an authenticated session with a man-
in-the-middle
As explained in section 3.3.1, a lack of entropy makes the output of the PRNG
predictable: the generated sequence is the same for every instance of the client.
This part describes the steps which allowed us to write a code demonstrating
the possibilities of this attack.
12
Figure 5: Preview of the inputs and outputs of the PLC, and of a part of the
supervision interface (on top)
A Python binding for the nfqueue PLC has been used. This binding does
not implement the set_payload function. To be able to implement the attack,
modified packets are actually dropped by the nfqueue, then sent back using a
raw socket after having modification.
As we will see later, some modifications on packets change their size, which
breaks the synchronization of the seq and ack on both ends of the TCP connec-
tion. Our code, which is only a proof of concept, does not handle this problem
of synchronization, hence the TCP connection is reset in some cases.
13
Figure 6: Desynchronization between the PLC and the supervision interface
(the client), one needs to locate in the responses the offset to the values of the
PLC variables, and to set them to the wanted value. Authentication data is
then added using the method described previously. Finally, packet is sent to the
supervision.
This method allows us to fill our first objective: control what is received
by the supervision, and hence what and operator would see on the HMI of an
industrial site. An example of implementation of this attack can be seen Fig. 6:
the state of the supervision interface, on top, is not consistent with the real state
of the LEDs of the PLC.
• Be lucky enough to intercept a write request done by the HMI. Not every
HMI do write requests, hence this scenario is not always reliable.
• Reset the connection: this forces the supervision to send a new password
authentication request. This request happens to be a write-type request,
14
allowing us to retrieve the wanted sequence number. Note there is no
password authentication, this attack is unnecessary.
• Brute force the sequence number until the PLC accepts the write request.
This solution is less viable and, in some cases, less discreet.
Using a trial and error method, we managed to generate valid write requests
for an arbitrary variable, for a given project. Only the modification of output
variables has been implemented.
4.2.2 Consequences
Our example is restricted to supervision sessions, but can also be extended to
administration sessions. It could allow an attacker to steal a reprogramming
session of a PLC to upload an arbitrary program. Every communication estab-
lished by a vulnerable client that uses this protocol can be compromised with
this attack.
A security fix for this vulnerability has been released by the manufacturer.
This attack is quite realistic: in practice, it is often possible to gain access to
an industrial system. Some of them are connected to enterprise networks or even
directly to the Internet4 . When it is not the case, they can use wireless networks
(WiFi, GSM) to operate. Even when these attack vectors are not available,
another event might make this attack possible: for example, a connection from
a maintenance agent’s laptop. These networks are most of the time flat, what
makes the attack practicable.
15
Some data in the packed firmware, including pieces of Web pages, seem to
be stored in plain text. However, a null byte is inserted every 9 bytes:
00 04 3C 68 74 6D 6C 3E 3C ..<html><
00 62 6F 64 79 3E 0A 3C 74 .body>.<t
00 61 62 6C 65 20 63 65 6C .able cel
00 6C 73 70 61 63 69 6E 67 .lspacing
00 3D 22 31 30 22 3E 0A 00 .="10">..
Thus, data seem to be stored in 9-byte blocks. Sometimes, the text is partially
stored in plain text. It these cases, this is not a null byte which is inserted, but
for example 41 or 10, as in the lines 2 and 4 of the following example:
00 3C 6D 65 74 61 20 68 74 .<meta ht
41 74 08 22 63 6F 6E 74 03 At."cont.
00 2D 74 79 70 65 22 20 63 .-type" c
10 6F 6E 74 03 3D 22 74 65 .ont.="te
40 73 09 68 61 6E 64 68 65 @s.handhe
00 6C 64 2C 20 6F 6E 6C 79 .ld, only
04 20 73 63 72 65 09 61 78 . scre.ax
16
sXXXXXXXXXhandheld, only screen and (max
This was a good progress. What we did was, every time a length was found,
to search for the 4 previous bytes in the already unpacked data and copy the
bytes following them. However, some unpacked data using this method was not
consistent.
We made the hypothesis that, for performance reasons, the unpacking algo-
rithm was not looking back the 4 bytes preceding a length each time a length
was found, but that a hash table was built during the unpacking process. This
assumptions was actually correct. The problem is that, to limit the memory
usage, the hash table has a small size. Various inputs produce the same hash
entry and collide, which leads to problems in the unpacking process if we don’t
know the hash algorithm used to compute the indexes of the hash table. There
is then a cascade of errors and, at the end, the output data becomes completely
wrong.
As the way to build the hash table is unknown, we were in a dead end.
The solution was given by reading a list of various public LZ algorithms. The
WikiBooks page on data compression [9] has been really useful: it mentions the
LZP algorithm. It is exactly this algorithm, more precisely LZP3, which is used
in the firmware.
This algorithm is detailed in [3]. An implementation has been developed. The
firmware was then fully unpacked. The end of the unpacked section contained a
CRC-32 of the whole section, which allowed us to ensure the output data was
correct.
17
Section name Address Size Permissions Unknown
.exec_in_lomem 0x0 0x7f24 -- --x (0x1 ) 0x0
.bitable 0x40000 0x40 -- --x (0x1 ) 0x0
.sdramexec 0x40040 0x4d4 -- --x (0x1 ) 0x0
.syscall 0x40540 0x18 -- --x (0x1 ) 0x0
.th_initial 0x41040 0x2c70 i- --x (0x21) 0x0
.secinfo 0x43cc0 0x318 i- r-- (0x22) 0x0
.fixaddr 0x44000 0x0 -? --- (0x4 ) 0x0
.fixtype 0x44000 0x0 -? --- (0x4 ) 0x0
.text 0x44000 0xe490f0 i- --x (0x21) 0x0
.rodata 0xe8d100 0x3f4a6c i- r-- (0x22) 0x0
.data 0x1281b80 0x27114 i- rw- (0x2a) 0x0
.bss 0x1e01040 0x7ce53c -? -w- (0xc ) 0x0
.uninitialized 0x3641040 0x394247c -? -w- (0xc ) 0x0
CLSI_CACHED_MEM_POOL 0x6f834c0 0x0 -? --- (0x4 ) 0x0
.dram_uncache 0x7ff0000 0x0 -? --- (0x4 ) 0x0
MAP_MAC_MEM 0x7ff0000 0x494 -? -w- (0xc ) 0x0
.iram0 0x10030000 0x7aa0 -? -w- (0xc ) 0x0
.iram1 0x10040000 0xc35c -? -w- (0xc ) 0x0
.crctable 0x1004f400 0x400 -? -w- (0xc ) 0x0
.softboot 0x1004f800 0x700 -? -w- (0xc ) 0x0
.bootinfo 0x1004ff00 0x1c -? -w- (0xc ) 0x0
.dtcm 0x10010000 0x2a00 -? -w- (0xc ) 0x0
The Unknown field is always set to zero, but is present in each entry of the
table.
The i permission means “initialized when loaded in memory”: this is data
that matches parts of the binary directly loaded into memory. This information
is merely empirical, and the first section does not fit into this case: it contains
firmware code but has no permission i.
The role of the ? permission is unknown. It seems that it could allow a
certain kind of reading when i is not present. It could mean “allow reading of
uninitialized data”.
Here is how the firmware is loaded into memory:
– .bitable (a header)
– .sdramexec
– .syscall
– .th_initial (code initializing the BSS, among other things).
– .secinfo (section table)
– .text
18
– .rodata
– .data
All the other sections are a priori left uninitialized. The .bss section will be,
for example, initialized at boot time by the code located in .th_initial.
6 Conclusion
The approach we followed to reverse engineer an industrial system has been
explained in this paper. The fuzzing part allowed us to get familiar with the
architecture and to identify interesting features in the involved technologies.
The black-box reverse engineering part gave us quickly enough information
to target the key elements which needed a deeper analysis. In this last step,
much of the authentication system has been understood, a vulnerability has
been identified and exploited. Finally, the analysis of the firmware gave us new
horizons to look for other vulnerabilities on the PLC.
Thereafter, this information will allow us to have a better understanding
of these technologies, or to make more specific fuzzers by knowing all the data
formats used by the protocol.
Unlike what has been previously seen, the company which manufactures
the PLC made a significant effort to secure its devices, even if there is still
some way before reaching a confidence level close to what can be found in
classical information systems. There have also been very reactive at fixing the
vulnerabilities we identified. Things are moving in the right direction.
References
[1] Aki Helin. Radamsa. https://code.google.com/p/ouspg/wiki/Radamsa.
[2] Aleksandr Timorin. SCADA deep inside: protocols and secu-
rity mechanisms. http://fr.slideshare.net/AlexanderTimorin/
scada-deep-inside-protocols-and-security-mechanisms-40672525,
2014.
[3] Charles Bloom. Lzp: A new data compression algorithm. In James A. Storer
and Martin Cohn, editors, Data Compression Conference, page 425. IEEE
Computer Society, 1996.
[4] Florent Monjalet. Hexlighter. https://github.com/fmonjalet/
hexlighter.
19
[5] Pierre Lalet. Scanning internet-exposed modbus devices for fun & fun.
http://pierre.droids-corp.org/blog/html/2015/02/24/scanning_
internet_exposed_modbus_devices_for_fun___fun.html, 2015.
20