CVE-2022-38108: RCE in SolarWinds Network Performance Monitor

In this excerpt of a Trend Micro Vulnerability Research Service vulnerability report, Justin Hong and Lucas Miller of the Trend Micro Research Team detail a recently patched remote code execution vulnerability in the SolarWinds Network Performance Monitor. This bug was originally discovered and reported by ZDI Vulnerability Research Piotr Bazydło. The vulnerability results from the lack of proper validation of user-supplied data, which can result in the deserialization of untrusted data. An authenticated attacker can leverage this vulnerability to execute code in the context of SYSTEM. The following is a portion of their write-up covering CVE-2022-38108, with a few minimal modifications.

An insecure deserialization vulnerability has been reported in SolarWinds Network Performance Monitor. The vulnerability is due to insufficient validation of user-supplied data in the BytesToMessage function. A remote, authenticated attacker could exploit the vulnerability by sending crafted requests to an affected server. Successful exploitation can result in arbitrary code execution under the security context of SYSTEM. This vulnerability has been patched by SolarWinds and assigned CVE-2022-38108.

The Vulnerability

The SolarWinds Orion Platform is the base platform used by numerous SolarWinds products. The platform is designed to seamlessly integrate all Orion-based products into a single interface. Network Performance Monitor (NPM) is one of these SolarWinds products and is used to monitor multi-vendor network devices and servers.

The SolarWinds Orion platform adapts RabbitMQ, an open-source message broker, to send and receive messages between various software components and agents. RabbitMQ supports Advanced Message Queuing Protocol version 0-9-1 (AMQP 0-9-1), which is used by the SolarWinds platform. The SolarWinds Information Service (SWIS) is one of the modules that uses RabbitMQ to communicate with other services in the SolarWinds Orion Platform.

To send a message to SWIS, a sender can place message content in AMQP frames with the routing-key set to “SwisPubSub” and send these frames to RabbitMQ via TCP port 5671. The details of AMQP 0-9-1 frame format will be described in the detection section below.

JavaScript Object Notation (JSON) is a data-interchange format used for creating machine parseable human-readable output. A JSON object has the following syntax:

— An object is enclosed in curly braces {}
— An object comprises of zero or more items delimited by a comma (",") character.
— An item comprises of a key and a value. A key is delimited from its value by a colon (":") character.
— A key must be a string (enclosed in quotes).
— A value must be a valid type. Valid types include string, number, JSON object, array, boolean or nul
— An array is an object enclosed in square braces [].
— An array comprises of zero or more string, number, JSON object, array, boolean or null type-objects delimited by a comma (",") character.

An example JSON object is as follows:  

         {"name":"bob", "age":30}

An insecure deserialization vulnerability exists in SolarWinds NPM. The message content sent to SWIS via RabbitMQ contains Json.NET serialized objects. When receiving the message content, the DeserializeMessage() method of the .NET class EasyNetQ.DefaultMessageSerializationStrategy is called to process the message content. The method will call the BytesToMessage() method of the .NET class SolarWinds.MessageBus.RabbitMQ.EasyNetQSerializer to deserialize the message content. BytesToMessage() will call the DeserializeObject() method of the .NET class SolarWinds.Newtonsoft.Json.JsonConvert, which will eventually call the Deserialize() method of the .NET class SolarWinds.Newtonsoft.Json.Serialization.JsonSerializerInternalReader to deserialize the Json.NET serialized object.

However, all the methods mentioned above have no proper validation of the message content to see if the given object type is safe to be deserialized. Although SolarWinds already has a .NET class BlackListBinder that checks a given object type against suspicious type names, the SWIS application does not utilize BlackListBinder when processing message content from RabbitMQ. An attacker can send a message to the SWIS application via RabbitMQ and the message content contains a malicious Json.NET serialized object derived from known Json.NET deserialization gadgets from YsoSerial.Net and trigger arbitrary code execution on the server.

A remote attacker who has the credentials to access the RabbitMQ message broker could exploit the vulnerability by sending crafted messages to the target application via RabbitMQ. Successful exploitation can result in arbitrary code execution under the security context of SYSTEM.

Source Code Walkthrough

The following code snippet was taken from SolarWinds NPM version 2020.2.6. Comments added by Trend Micro have been highlighted.

In decompiled .NET class EasyNetQ.DefaultMessageSerializationStrategy:

In decompiled .NET class SolarWinds.MessageBus.RabbitMQ.EasyNetQSerializer:

In decompiled .NET class SolarWinds.Newtonsoft.Json.Serialization.JsonSerializerInternalReader:

Exploit Detection

To detect an attack exploiting this vulnerability, the detection device must monitor and parse traffic on TCP port 5671. Note that traffic is encrypted via SSL/TLS and should be decrypted before performing the following steps.

The detection device must first determine if the client is attempting to initiate an AMQP 0-9-1 connection by looking for the protocol header as the format shown below:

If such an AMQP protocol header is found, the detection device must continue to monitor the traffic and look for AMQP 0-9-1 frames.

AMQP 0-9-1 frames

AMQP 0-9-1 frames carry protocol methods, message content, and other information. All frames have the same general format: frame header, payload, and frame end. The frame end is represented by the byte value \xCE. The general frame format is shown as below:

There are four frame types in AMQP 0-9-1: Method, Content header, Content body, and Heartbeat frames. Each frame type has its own frame payload format. The payload format of Method, Content header, and Content body frame are related to this report and will be described in the following paragraphs. Note that, in the following paragraphs, the "Offset" value is relative to the beginning of the frame payload (offset 0x07 in the general frame format shown above).

 The payload format of the Method frame is as shown below:

The Method Arguments List field, depending on its Method id, can contain zero or more data values of various data types. Each data type is represented in its own specification. The data types include integer, bits, string, timestamp, and field table (key/value pair). The details of each data representation will not be described in this report.

The payload format of the Content header frame is as shown below:

The user data that a sender wants to send to the receiver can be carried in one or more Content body frames following the Content header frame. That is, the user data can be split into several Content body frames. The Body size field of the Content header frame is to record the total size of the original user data (before being split) sent by the sender.

The payload format of the Content body frame is as shown below:

The Binary content field carries the whole (if not split) or a part of user data that the sender wants to send to the receiver.

The detection device must first look for the Method frame which contains the routing-key “SwisPubSub”. To do this, the detection device must check each frame to see if its frame type is \x01 and Class id is \x3c (Basic class) and Method id is \x28 (Publish) and its Method Argument List field contains the string “SwisPubSub”. If such a frame is found, the detection device must continue to look for the Content body frame and inspect its Binary content field as JSON-format data to see if it contains a malicious serialized object. Note that the JSON-format data could be split into multiple Content body frames and the detection device must be able to assemble all Binary content fields together from these Content body frames before inspecting it.

The JSON-format data must be inspected using any suitable parsing method below:

Method 1 - The detection device can parse JSON

The detection device must search for the “$type” key and check if its value begins with any of the following strings:

If found, the traffic should be considered malicious and an attack exploiting this vulnerability is likely underway.

Using the class names (like “System.Windows.Data.ObjectDataProvider”) as the indication of the exploitation of this vulnerability is based on the observation that this insecure deserialization vulnerability relies on the use YsoSerial.Net gadget that works with Json.NET, and also based on the fix from the SolarWinds NPM program update, which uses a deny-list method to verify the type of the serialized object.

Method 2 - String-based detection

The detection device must check if the JSON-format data contains a string that can be matched with the regular expression as below:

If found, the traffic should be considered malicious and an attack exploiting this vulnerability is likely underway. Below is an example of a malicious serialized object in JSON-format:

Note that all string matching should be performed in a case-sensitive manner.

Conclusion

SolarWinds addressed this vulnerability with the release of SolarWinds Platform version 2022.4 RC1 and later. In addition to installing the updated version, enterprises can also protect themselves by blocking the affected ports from external network access if they are not required. The vendor also recommends applying proper segmentation controls on the network where you have deployed the SolarWinds Platform and SQL Server instances. This should also be considered a best practice and a part of a robust defense-in-depth strategy. They also recommends that customers follow the guidance provided in the SolarWinds Secure Configuration Guide. Finally, ensure only authorized users can access the SolarWinds Platform. 

Special thanks to Justin Hong and Lucas Miller of the Trend Micro Research Team for providing such a thorough analysis of this vulnerability. For an overview of Trend Micro Research services please visit http://go.trendmicro.com/tis/.

The threat research team will be back with other great vulnerability analysis reports in the future. Until then, follow the team on Twitter, Mastodon, LinkedIn, or Instagram for the latest in exploit techniques and security patches.

Article Link: Zero Day Initiative — CVE-2022-38108: RCE in SolarWinds Network Performance Monitor