Microsoft discovered and responsibly disclosed two vulnerabilities in Rockwell Automation PanelView Plus that could be remotely exploited by unauthenticated attackers, allowing them to perform remote code execution (RCE) and denial-of-service (DoS). The RCE vulnerability in PanelView Plus involves two custom classes that can be abused to upload and load a malicious DLL into the device. The DoS vulnerability takes advantage of the same custom class to send a crafted buffer that the device is unable to handle properly, thus leading to a DoS.
PanelView Plus devices are graphic terminals, also known as human machine interface (HMI) and are used in the industrial space. These vulnerabilities can significantly impact organizations using the affected devices, as attackers could exploit these vulnerabilities to remotely execute code and disrupt operations.
We shared these findings with Rockwell Automation through Coordinated Vulnerability Disclosure (CVD) via Microsoft Security Vulnerability Research (MSVR) in May and July 2023. Rockwell published two advisories and released security patches in September and October 2023. We want to thank the Rockwell Automation product security team for their responsiveness in fixing this issue. We highly recommend PanelView Plus customers to apply these security patches.
The discovered vulnerabilities are summarized in the table below:
CVE ID | CVSS Score | Vulnerability |
---|---|---|
CVE-2023-2071 | 9.8 | Remote code execution (RCE) |
CVE-2023-29464 | 8.2 | DoS via out-of-bounds read |
In this blog post, we will focus on the technical details of the CVE-2023-2071 remote code execution vulnerability and how it was discovered, as well as provide an overview of the protocol used for both the RCE and DoS vulnerabilities. Additionally, we will offer technical details about the vulnerability and demonstrate the exploitation method. By sharing this research with the larger security community, we aim to emphasize the importance of collaboration in the effort to secure platforms and devices.
One of the primary responsibilities of the Microsoft Defender for IoT research team is to ensure that the product properly analyzes various operational technology (OT) and Internet of Things (IoT) protocols. During this process, we observed a legitimate packet capture of two devices communicating using the Common Industrial Protocol (CIP), with one device sending a request containing a path to a registry value named “ProductCode,” and the other device responding with what appeared to be the product code value. The lack of encryption and absence of prior authentication in the communication raised concerns, as it appeared to involve a remote registry query. Further investigation revealed that the requesting device was an engineering workstation, and the responding device was an HMI – specifically, PanelView Plus.
We hypothesized that this remote registry querying functionality could be abused by querying system keys to access secrets or even gain remote control. To validate this hypothesis, we needed to locate the code responsible for this functionality. Since the two devices communicated using the CIP, our first step was to understand the protocol in depth.
CIP is an industrial protocol designed for industrial automation applications. Various vendors in the industrial sector utilize this protocol, and the communication we observed took place over Ethernet/IP – a protocol that adapts CIP to standard Ethernet.
According to the official CIP documentation: “A CIP node is modeled as a collection of Objects. (…) A Class is a set of Objects that all represent the same kind of system component. An Object Instance is the actual representation of a particular Object within a Class.”
From this description, we can deduce that CIP is an object-oriented protocol, where messages are directed towards specific objects, identified by their Class ID and Object Instance ID. Additionally, the term “Service Code” is defined as: “An integer identification value which denotes an action request that can be directed at a particular object instance or object attribute”. Therefore, when messaging an object, we should also specify a Service Code, which informs the object what action it should perform.
The CIP specification outlines common Class IDs and Service IDs, as well as ranges for vendor-specific IDs.
Returning to the packet capture, we observed that both Service ID and Class ID values were vendor specific. This means that to understand the meaning of these Class and Service IDs and locate the code responsible for the functionality, we must analyze the HMI firmware.
According to Rockwell Automation’s online resources, PanelView Plus HMIs operate on the Windows 10 IoT (or Windows CE for older versions) operating system. We were able to extract the DLLs and executables related to Rockwell Automation from the most recent firmware. There are several DLLs responsible for receiving different Class IDs and processing their requests, one of which is responsible for processing the Class ID we observed in the packet capture.
Upon examining the functionality associated with this Class ID, we confirmed that it is indeed responsible for querying the registry and sending the value in the response. However, we also discovered that the code managing this functionality performs input verification, allowing the reading of registry values only from specific Rockwell keys.
Although our initial hypothesis was proven incorrect, this finding allowed us to gain valuable insights into Rockwell’s process of handling different CIP classes. Additionally, we learned how to identify the classes that a specific DLL is responsible for processing. This knowledge leads us to our second hypothesis: there might be another custom class, managed by the same DLL as the one responsible for the registry class, that could be exploited to gain remote control of the device.
We began analyzing the DLL that handles the custom CIP class for reading and writing registry keys and discovered that this DLL also manages two other undocumented custom CIP classes from Rockwell. We decided to investigate these classes further to determine if they could be exploited for our attack and help validate our hypothesis.
The first class we examined had an intriguing functionality: it accepts a path to a DLL file, a function name, and a third parameter as input. It then loads the DLL using LoadLibrary and calls the specified function using GetProcAddress, passing the third parameter as an argument.
This seemed like a possible avenue for executing arbitrary code. However, there was a catch: the class included a verification function that checked if the DLL name was remotehelper.dll and if the function name was one of the predefined values. If these conditions were not met, the class would return an error and not execute the function.
Next, we examined the second class found within the same DLL. This class allowed reading and writing files on the device. It also included a verification function, but it was more permissive: it only checked whether the path for reading/writing began with a specific string. We realized that this class could potentially be exploited by uploading a malicious DLL to the device and place it in almost any location.
Having gained a comprehensive understanding of the vulnerabilities, we had an idea of how an attacker could utilize the two custom classes to launch code remotely on the device. The idea was to compile a DLL compatible with Windows 10 IoT, the operating system of the device. This DLL would contain the code we wanted to run on the device and would be exported under the name GetVersion, which is one of the valid function names that can be invoked by custom class 1. We would then use custom class 2 to upload our DLL to the device, placing it in a random folder and naming it remotehelper.dll. Finally, we would execute it using custom class 1.
To further explore how the vulnerability can be exploited, we decided to leverage an existing function in the original remotehelper.dll file. We discovered that this file had an export called InvokeExe, which allowed running any executable file on the device. However, this function was not in the list of valid function names for custom class 1, so we could not use it directly. To overcome this obstacle, we patched the remotehelper.dll file and altered one of the valid export names to point to the InvokeExe function. We then uploaded our patched DLL to the device, placing it in a different folder than the original. Subsequently, we used custom class 1 to invoke our patched DLL and run cmd.exe, which granted us a command shell on the device. We confirmed that the exploit was successful and that we had gained full control of the device.
Microsoft recommends the following measures to help protect organizations from attacks that take advantage of the PanelView Plus vulnerabilities shared in this blog post:
To assist with identifying impacted devices, Microsoft released a tool for scanning and performing forensics investigation on Rockwell Rslogix devices as part of its arsenal of open-source tools available on GitHub.
Microsoft Defender for IoT provides the following protection measures against these vulnerabilities, associated exploits, and other malicious behavior:
Yuval Gordon
Microsoft Threat Intelligence Community
For the latest security research from the Microsoft Threat Intelligence community, check out the Microsoft Threat Intelligence Blog: https://aka.ms/threatintelblog.
To get notified about new publications and to join discussions on social media, follow us on LinkedIn at https://www.linkedin.com/showcase/microsoft-threat-intelligence, and on X (formerly Twitter) at https://twitter.com/MsftSecIntel.
To hear stories and insights from the Microsoft Threat Intelligence community about the ever-evolving threat landscape, listen to the Microsoft Threat Intelligence podcast: https://thecyberwire.com/podcasts/microsoft-threat-intelligence.