Some Forensics challenges in HTB Cyber Apocalypse 2024
Preface
Hi guys, it’s me again. It’s been a while since I’ve written writeups. University’s projects, CTF events, …, I’m currently up to my neck right now. But the most important thing is that I’m lazy. Anyway, I have participated in Hack The Box Cyber Apocalypse: Hacker Royale this weekend with WannaW1n. It’s a big event in March 2024 and a fun event to begin as a beginner. Because I’m lazy I don’t have much time so I will write about 4 last challenges of Forensics. Here we go…
Data Siege
Note
It was a tranquil night in the Phreaks headquarters, when the entire district erupted in chaos. Unknown assailants, rumored to be a rogue foreign faction, have infiltrated the city’s messaging system and critical infrastructure. Garbled transmissions crackle through the airwaves, spewing misinformation and disrupting communication channels. We need to understand which data has been obtained from this attack to reclaim control of the and communication backbone. Note: flag is splitted in three parts.
We only have a packet capture as the evidence.
As you can see in the above image, there are some strange HTTP connections to the IP 10.10.10.21.
I decided to extract those things out.
The first request was to get a file from this URL http://10.10.10.21:8080/nBISC4YJKs7j4I. The file’s content look like this:
This is the RCE payload that exploit Apache ActiveMQ vulnerability (CVE-2023-46604). From this payload, threat actor continue downloading aQ4caZ.exe file from the same URL.
Here is the output of DIE:
We’ve known this is a C# dotnet executable so let’s move on to dnSpy for further analysis.
So this is an EzRAT sample, a C2 malware back in 2020: Link
At this point, I knew we had to decrypt the traffic which was between the server and the victim.
You can see in this part of the code, the agent connect to the C2 server using socket with pre-defined IP and port in constants.
And that is the server’s IP and port number. We can use a simple filter to the pcap and follow its stream to display the encrypted traffic:
Back to the malware, after it connected to the server, the agent will wait for server’s commands in RequestLoop() method.
When it received the response, the data will be transfered to GetCommand() function for further processing. After that, it will be execute by HandleCommand()
The buffer will be splited into two parts by this character ‘§’. The first part is the len of the encrypted buffer. The second is the buffer we need to decrypt it.
This is the decrypt function, the encryption will use the same parameter so I just show you this part.
You can get encryptKey in the defined constants Constantes.EncryptKey. That’s all we need to decrypt the traffic.
Here is a simple code that decrypt the challenge’s encrypted traffic.
fromCrypto.CipherimportAESfromCrypto.Util.Paddingimport*fromCrypto.ProtocolimportKDFimportpysharkimportbase64password=b'VYAemVeO3zUDTL6N62kVA'salt=bytes([86,101,114,121,95,83,51,99,114,51,116,95,83])derived_bytes=KDF.PBKDF2(password,salt,dkLen=48)key=derived_bytes[:32]iv=derived_bytes[32:]pcap=pyshark.FileCapture('capture.pcap',display_filter='tcp.port == 1234')server_cmd=[]client_response=[]forpacketinpcap:ip_source=packet['IP'].get_field("ip.src")data=packet['TCP'].get_field("tcp.payload")ifdata==None:continuedata=bytes.fromhex(data.replace(':',''))ifip_source=='10.10.10.22':client_response.append(data)else:server_cmd.append(data)foriinrange(len(server_cmd)-1):split_char='§'# 0xA7Cipher=AES.new(key,AES.MODE_CBC,iv)ifi==12:# Last packetdata=base64.b64decode(server_cmd[12])[16:].decode()print("SERVER: Transfer file to client.","FILE DATA:",f"{data}",sep='\n')breakdata=base64.b64decode(server_cmd[i].split(b'\xa7')[1])command=unpad(Cipher.decrypt(data),AES.block_size)data=base64.b64decode(client_response[i])response=Cipher.decrypt(data)[16:]print(f"SERVER: {command}",f"CLIENT: {response}",sep='\n')
Combining three parts of the flag, we will get the final flag.
Game Invitation
Note
In the bustling city of KORP™, where factions vie in The Fray, a mysterious game emerges. As a seasoned faction member, you feel the tension growing by the minute. Whispers spread of a new challenge, piquing both curiosity and wariness. Then, an email arrives: “Join The Fray: Embrace the Challenge.” But lurking beneath the excitement is a nagging doubt. Could this invitation hide something more sinister within its innocent attachment?
This challenge is about Visual Basic for Application. The only evidence is a docm file which has malicious vba code. We will use olevba to extract the code from it, pretty easy right?
As you can see, the code is obfuscated a little bit but it ain’t a big problem. The attacker just changed only the variable’s name but not the logic of the function. If you want a cleaner code, just change the name to something that suit you. Now I will explain what those functions do.
The code will check the victim’s domain, if is not GAMEMASTERS.local, the code will not run the next part
VBA will take a part of the document then xor it. After that it write to mailform.js and execute the jscript in %appdata%\Microsoft\Windows.
That’s how the malicious code works. From this point, you can write a script to recover the payload or you can remove the if condition statement which checks the hostname, this will make the code write out the javascript file automatically.
The jscript is not quite complicated than the previous one as we can do the trick to make it print out the next script, by replacing eval() with Wscript.Echo(). You need to run this by using cscript.exe to print it in your terminal. On the other hand, if you run with wscript.exe, you will get a message box.
Despite using the trick, you can manually decrypt this one because it uses simple functions.
Here is how they work. Just focus on two core functions: JrvS() and xR68()
The RC4 function will take a passphrase from the previous VBA code. It is the argument of this file:
I used cyberchef to do my job. Using RC4 with the given password and base64 decode function, you will have this:
The final flag is in that script too!
Confinement
Note
Our clan’s network has been infected by a cunning ransomware attack, encrypting irreplaceable data essential for our relentless rivalry with other factions. With no backups to fall back on, we find ourselves at the mercy of unseen adversaries, our fate uncertain. Your expertise is the beacon of hope we desperately need to unlock these encrypted files and reclaim our destiny in The Fray.
Note: The valuable data is stored under \Documents\Work
Moving on to this challenge, we will meet a ransomware. Just like other similar cases, we will have to decrypt the encrypted files if possible. But first, let’s find the threat.
We have an ad1 image. It is AccessData Logical Image (Ref). Basically, it is just a disk image file, we will use FTK Imager to load these file. For Autopsy, we will use FTK to mount these images first and then, use Autopsy to analyse as logical files.
Let’s take a deep dive into this case. The victim has mentioned the valuable data is stored under “\Documents\Work”.
The encrypted files has an extension .korp. In addtion, we have ULTIMATUM.hta as a note from the ransomware group.
In the Downloads folder, we have ats_setup.bat which was intialized a reverse shell connection to the attacker. This is the result from a download action which you can see in Edge browser’s history. This is the initial access phase from TA.
The attacker used powershell as the default shell when get a connection from the victim. But there is no Powershell folder in %appdata%\Windows\ path so we can not get a log from there.
The second way is from Windows Event log. I used chainsaw for this process.
After getting a connection from the victim, TA continue downloading a password-protected zip file named intel.zip. He decompressed the file and ran some executables in it. One is the browser-pw-decrypt.exe, maybe this is for browser’s credentials extraction. Another one is intel.exe, I guess this is the ransomware. ./mimikatz.exe is used to extract LSASS secret and fscan64.exe maybe for connection scanning? When finished, the attacker deleted all of the associated files which make us likely have no chance to obtain the malware.
Now the question is: Where is the intel.zip? We have known that the attacker had erased it from the system. BUT, before running those executables again, TA ran some commands to disable the Windows Defender! From this point, we can actually recover the ransomware if it was quarantined by the Defender. Let’s check the Windows Defender folder.
Also, the Defender’s log had logged this event:
We have almost of the critical evidences in this folder. The important file is in Quarantine and we have to decrypt it. (Ref)
Okay we have the sample now, that SHA1 hash is matched with the log. Let’s reverse it!
This is the function will recusively enumerate in the directory to encrypt files. It takes some valid extension to encrypt, some are not, e.g: .korp, .hta or desktop.ini file.
The function calls another one which is coreEncrypter.EncryptFile(). In this function, we can see it intializes AES-CBC-256 as the core encrypter.
The password is used for the deriving phase is generated in the Main() function of the program.
Although the UID was generated randomly, we still can recover it from ULTIMATUM.hta file as the ransomware writes UID to that file in alert.ValidateAlert().
The password is the result of Base64Encode(SHA512(UID + salt)).
Now we have all of the important parameters to decrypt the files. Here is the script that can be used to do that process.
As the days for the final round of the game, draw near, rumors are beginning to spread that one faction in particular has rigged the final! In the meeting with your team, you discuss that if the game is indeed rigged, then there can be no victory here… Suddenly, one team player barged in carrying a Windows Laptop and said they found it in some back room in the game Architects’ building just after the faction had left! As soon as you open it up it turns off due to a low battery! You explain to the rest of your team that the Legionnaires despise anything unethical and if you expose them and go to them with your evidence in hand, then you surely end up being their favorite up-and-coming faction. “Are you Ready To Run with the Wolves?!”
In the last challenge, we have to recover the “backdoor” in a given memory image. That files is a hibernation file.
In order to analysing this image, you will have to use Hibr2Bin.exe from Magnet or using Volatility 3 version from ForensicXLab. The first solution caused me some troubles so I had to downgrade my Volatility version.
From the process list, the most suspicious process here is just TheGame.exe. Its location is in C:\Users\architect\Desktop\publish. But you can see from the dumpfiles plugin, “publish” folder has more suspicious files than TheGame.exe itself. By enumerating this folder, you will find out that this is actually a project that was generated by Visual Studio.
I checked the handles of TheGame process (PID 6348) and saw an intersting result:
Yup this is a very familiar DLL call.
So we must dump out those two files to proceed to the next stage: TheGame.exe and TheGame.dll.
I ran DIE to detect what kind of that DLL is:
I must say I kinda like dotnet assembly. Let’s check it out.
When we load this file to dnSpy, we can catch up to something like this:
Strange isn’t it? So dnSpy can’t decompile this file properly even though some dll exporting and constants can be that clear.
I decided to give ILSpy a try and it worked perfectly!
In this code, there is nothing more than some AMSI check functions. The base64 string is just an EICAR’s test string that people used to test the antivirus (Ref). Nothing in this code seem malicious.
usingSystem;usingSystem.IO;usingSystem.Reflection.Emit;usingSystem.Text;usingSystem.Threading;privateunsafestaticvoidMain(string[]argv){string[]array=newstring[8]{"usp10.dll","rasapi32.dll","dwmapi.dll","mpr.dll","advpack.dll","winspool.drv","imm32.dll","msimg32.dll"};nint[]array2=newnint[array.Length];for(inti=0;i<array.Length;i++){nintnum=LoadLibraryA(array[i]);if(num==IntPtr.Zero){((Console)OpCode).WriteLine("Unable to load "+array[i]);}array2[i]=num;}strings="WDVPIVAlQEFQWzRcUFpYNTQoUF4pN0NDKTd9JEVJQ0FSLVNUQU5EQVJELUFOVElWSVJVUy1URVNULUZJTEUhJEgrSCoNCg==";byte[]array3=((Convert)OpCode).FromBase64String(s);string@string=((Encoding)(*(OpCode*)((Encoding)OpCode).UTF8)).GetString(array3);((Console)OpCode).WriteLine("Initializing AMSI Interface!");if(AmsiInitialize("Testing",outvaramsiContextHandle)!=0){((Environment)OpCode).Exit(-1);}intmillisecondsTimeout=600000;((Console)OpCode).WriteLine("AMSI Connection Established!");((Console)OpCode).WriteLine("Testing against known malicious sample!");if(AmsiScanString(amsiContextHandle,@string,"TEST",IntPtr.Zero,outvarresult)!=0){((Environment)OpCode).Exit(-2);}if(result==AmsiResult.AMSI_RESULT_DETECTED){((Console)OpCode).WriteLine("Testing String finished!");((Console)OpCode).WriteLine("Scanning malicious code: kernel32.dll");}byte[]array4=((File)OpCode).ReadAllBytes("C:\\Windows\\system32\\kernel32.dll");if(AmsiScanBuffer(amsiContextHandle,array4,array4.Length,"TEST",IntPtr.Zero,outresult)!=0){((Environment)OpCode).Exit(-3);}if(result==AmsiResult.AMSI_RESULT_NOT_DETECTED){((Console)OpCode).WriteLine("Scanning finished, no threads found!");}try{((Console)OpCode).WriteLine("Clean library detected -> Backdooring!");FileStreamfileStream=((File)OpCode).OpenWrite("C:\\Windows\\system32\\kernel32.dll");((Stream)(*(OpCode*)fileStream)).Seek(((Stream)(*(OpCode*)fileStream)).Length,SeekOrigin.Begin);((Stream)(*(OpCode*)fileStream)).Write(array3,0,array3.Length);}catch{}Console.WriteLine("Sleeping forever");Thread.Sleep(millisecondsTimeout);
There is actually a very weird part in this code. Here it is:
Why did ILSpy give us something like this? At that moment, I couldn’t understand what its really mean.
I spent a day viewing, doing stupid things in this dll and also TheGame.exe but its just a loader for TheGame.dll. For others dll, I didn’t see anything suspicious too.
In the next day, I found this interesting blog post.
TL;DR: The blog was about a technique that is used to hide .NET opcodes from some .NET assembly editor like dnSpy.
From this blog, there is two thing that we need to pay attention to.
The challenge’s DLL is the second. How can we extract the malicious code? Just use the IDA and press F5 👀
The function at the line 309 is the function we need to looking for. After doing the decryption, which is a xor function with the given key and ciphertext, we will get a cmd command has a flag in it. This command will be executed later by calling WinExec at the line 310. That’s all!
I’m sorry for this careless writeup about the last challenge. Because I’m not a Reverse guy 🥲. That’s all I can do for you guys to get a better view of this challenge. See you guys in the next post!