Our new Biannual ICS Risk & Vulnerability Report is the most up-to-date look at CVEs disclosed in OT devices.
Check it out!
The Race to Native Code Execution in PLCs
By Tal Keren | May 28, 2021
Claroty has found a severe memory protection bypass vulnerability (CVE-2020-15782) in Siemens PLCs, the SIMATIC S7-1200 and S7-1500.
An attacker could abuse this vulnerability on PLCs with disabled access protection to gain read and write access anywhere on the PLC and remotely execute malicious code.
Siemens has updated the firmware for both the SIMATIC S7-1200 and S7-1500 PLCs to address this vulnerability and informs customers about the details in its advisory, SSA-434534.
Users are urged to update to current versions.
Claroty is not aware of any public exploitation of this vulnerability.
Achieving native code execution on an industrial control system such as a programmable logic controller (PLC) is an end-goal relatively few advanced attackers have achieved. These complex systems have numerous in-memory protections that would have to be hurdled in order for an attacker to not only run code of their choice, but also remain undetected.
Previous work has required physical access and connections to the PLC, or techniques that target engineering workstations and other links to the PLC in order to gain that level of code execution. Claroty, meanwhile, has taken those efforts a step further using a newly discovered vulnerability that bypasses the PLC sandbox within Siemens’ SIMATIC S7-1200 and S7-1500 PLC CPUs to run native code in protected areas of memory. An attacker could use this vulnerability, CVE-2020-15782, to remotely obtain read-write memory access that would be difficult to detect and remove.
This disclosure is an outcome of Siemens’ and Claroty’s existing partnership, which fosters not only tight cooperation between our research team and the vendor on disclosures, but also in the security of the overall industrial ecosystem. The close coordination between Siemens and Claroty included an exchange of technical details, attack techniques, and mitigation advice that helped shape the patches available in today’s update from Siemens. Siemens and Claroty wish to emphasize that users apply the S7-1200 and S7-1500 CPU updates as well as those for other affected products given the critical nature of this vulnerability.
The holy grail in PLC vulnerability research, from the attacker perspective, is to achieve unrestricted and undetected code execution on the PLC. This means, being able to hide code deep inside the PLC that will be undetected by the operating system, or any diagnostic software.
Over the years we’ve seen many attempts to achieve such a capability on Siemens PLCs given the company’s position among the market’s leaders. First, we had Stuxnet, which gained user-level code execution on the old SIMATIC S7-300 and S7-400. The code alteration itself was done by manipulating the local Step 7 projects files. Then, Stuxnet was able to hide the code alteration on the PLC by manipulating the WinCC binaries on the local engineering station. Doing so allowed the malware to not only stealthily install itself on PLCs, but also shield itself from WinCC when the control software attempted to read infected memory blocks from the PLC. This issue was resolved with a combination of Microsoft updates to its Windows operating system and Siemens product updates as documented in SSA-110665 and SSA-027884.
Next, we witnessed the Rogue7 attack. The researchers behind Rogue7 were able to create a rogue engineering station which can masquerade as the TIA portal to the PLC and inject any messages favorable to the attacker. By understanding how cryptographical messages were exchanged, they were able to hide code in user memory, which is invisible to the TIA engineering station. Siemens partially resolved this issue and provided mitigations, as documented in SSA-232418.
The same year Ali Abbasi and Tobias Scharnowski presented how they physically attacked the SIMATIC 1200 to gain code execution on Siemens S7 PLCs. They used a UART physical connection to dump the firmware and found an exploit chain that enabled them to hide code in a deeper place within the system and obtain code execution without restrictions. Siemens resolved this issue in SSA-686531.
Today, we take this research one step further and demonstrate a new and sophisticated remote attack that allows us to gain native code execution on Siemens S7 PLCs. Our attack targets deep in the kernel and avoids any detection because we are able to escape the user sandbox and write a shellcode into protected memory regions.
Understanding—and Jailbreaking—the PLC Sandbox
The integrity of a PLC is crucial to operators and engineers, and an attacker’s goal would be to damage that integrity by hiding code on the controller and elevating privileges. Our vulnerability, CVE-2020-15782, bypasses existing protections within the execution environment of the PLC, including a sandbox where engineering code would normally run. Claroty was able to use this vulnerability to escape the sandbox in order to gain direct access to memory, then write and inject shellcode to execute our attack on Siemens 1200/1500 PLCs.
In order to execute this attack, one would need network access to the PLC. In addition, the attacker would need PLC download rights. Since TIA Portal V12, Siemens provides various mitigation controls to limit user network and read/write access to the PLC, especially the password protection mechanism. Additionally, starting with V17, Siemens introduces TLS communication using individual certificates between PLCs, HMIs and TIA Portal, which reduces the potential attack surface significantly.
To understand our specific attack, we first want to outline the generic structure of a standard PLC. Its CPU is either a 16- or 32-bit microprocessor consisting of a memory chip and integrated circuits that manage control logic, process monitoring, and communication. The CPU directs the PLC to execute control instructions, communicate with other devices, carry out logic and arithmetic operations, and perform internal diagnostics.
It also runs memory routines, constantly checking the PLC to avoid programming errors, and ensure the memory is undamaged.The logic runs in a sandbox environment,—sometimes referred to as “jail.” The logic being transferred to the controller is limited to specific memory regions and APIs provided by the vendor.
In the case of the Siemens S7 PLCs—which runs on the ADONIS kernel and an ARM or MIPS processor—there are numerous programming languages available to configure the controller, including Statement List (STL), Ladder Diagram (LD), Function Block Diagram (FBD), and Structured Control Language (SCL).
Regardless of input sources, the PLC program will be compiled into MC7 / MC7+ bytecode, which is a lower-level representation of the code. After being compiled by the engineering station—the Siemens TIA Portal—code blocks (in MC7/MC7+ format) are downloaded and installed into a PLC via Siemens’ S7Comm / S7Comm+ protocol. Then, the MC7 virtual machine in the PLC will dispatch the code blocks and interpret and execute the bytecode.
It is not possible to decode MC7/MC7+ bytecode without reverse engineering, because Siemens has not publicly provided documentation to do so. Therefore, we had to reverse engineer the MC7/MC7+ bytecode language set in order to understand its internal mechanism and find bugs.
Since the virtual machine restricts the resources accessed by the users’ programs, the compiled bytecode can only be used for access to the allowed resources by the operating system rather than direct hardware operation. This is to restrict the user and the running code to a defined set of actions that are considered safe. For example, the operating system will restrict any direct access to protected memory, but will allow the use of any function from the standard library provided by Siemens (e.g. ADD_I – Add Integer subroutine). In other words, the operating system is “locking” the user’s code in a sandbox/container with a limited access to resources, memory, and functionality that could potentially damage the PLC and/or the entire process.
In order to escape, or “jailbreak,” the native SIMATIC S7-1200 and S7-1500 sandboxes, Claroty used its memory protection bypass vulnerability. The vulnerability enables an attacker to write arbitrary data and code to supposedly protected memory areas, or read sensitive data to launch further attacks.
Escaping the sandbox means an attacker would be able to read and write from anywhere on the PLC, and could patch an existing VM opcode in memory with malicious code to root the device. Claroty, for example, was able to inject ARM/MIPS shellcode directly to an internal operating system structure in such a way that when the operating system uses a specific opcode that we chose, our malicious shellcode would execute, giving us remote code execution. We used this technique to install a kernel-level program with some functionality that is completely hidden to the operating system.
CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer
CVSS v3.1 Score: 8.1
Affected devices are vulnerable to a memory protection bypass through a specific operation. A remote unauthenticated attacker with network access to TCP port 102 could potentially write arbitrary data and code to protected memory areas or read sensitive data to launch further attacks.
Today, Siemens released advisory SSA-434534 that notifies its users of this vulnerability. Siemens also released updates for various products, including S7-1500 and S7-1200, that remediate the vulnerability. Users are urged to update to the latest versions. The company said it is preparing further updates for products where updates are not yet available; Siemens also provided specific mitigation measures that users can apply to reduce the risk.