HTB: CA2023 — Forensics Interstellar C2

Khris Tolbert
Maveris Labs
7 min readMar 24, 2023

--

The folks at HackTheBox put on another fun/great event!

One of my favorite solves from this event was the Forensic Interstellar C2 challenge. I really enjoyed the realistic-ish hunt via PCAP of a suspected PowerShell dropper and it’s encrypted traffic. It was a nice break from burning myself out on crypto challenges (why does sagemath hate me so much?).

As this challenge was ranked “hard” and at the time I began my attempt against it, only 30 or 40 solves existed, I was curious if I would even complete the challenge in time… (SPOILER: Somehow I did!)

HA! Take that meme, I actually for once did complete it in time!!!

Given solely a PCAP to begin, the 4th packet in kicks off the party:

Wireshark. Yeah. That’s what this is.

Browsing the entire PCAP, many more HTTP requests were seen, so I decided to go ahead and dump them all with tshark:

tshark -r capture.pcapng --export-objects 'http,destdir'

From there, I was then able to see all of the dumped HTTP objects within the PCAP:

$ ls -al destdir/*            
-rwxrwx--- 1 root vboxsf 478360 Mar 23 09:56 %3fdVfhJmc2ciKvPOC
-rwxrwx--- 1 root vboxsf 1516 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(1)'
-rwxrwx--- 1 root vboxsf 11 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(10)'
-rwxrwx--- 1 root vboxsf 11 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(11)'
-rwxrwx--- 1 root vboxsf 42 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(12)'
-rwxrwx--- 1 root vboxsf 103 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(13)'
-rwxrwx--- 1 root vboxsf 6703168 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(14)'
-rwxrwx--- 1 root vboxsf 1516 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(15)'
-rwxrwx--- 1 root vboxsf 55 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(16)'
-rwxrwx--- 1 root vboxsf 2508 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(17)'
-rwxrwx--- 1 root vboxsf 42 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(18)'
-rwxrwx--- 1 root vboxsf 55 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(19)'
-rwxrwx--- 1 root vboxsf 3 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(2)'
-rwxrwx--- 1 root vboxsf 81 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(20)'
-rwxrwx--- 1 root vboxsf 55 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(21)'
-rwxrwx--- 1 root vboxsf 88 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(22)'
-rwxrwx--- 1 root vboxsf 846588 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(23)'
-rwxrwx--- 1 root vboxsf 42 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(24)'
-rwxrwx--- 1 root vboxsf 3 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(25)'
-rwxrwx--- 1 root vboxsf 1516 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(3)'
-rwxrwx--- 1 root vboxsf 81 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(4)'
-rwxrwx--- 1 root vboxsf 1580 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(5)'
-rwxrwx--- 1 root vboxsf 81 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(6)'
-rwxrwx--- 1 root vboxsf 3 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(7)'
-rwxrwx--- 1 root vboxsf 3 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(8)'
-rwxrwx--- 1 root vboxsf 103 Mar 23 09:56 '%3fdVfhJmc2ciKvPOC(9)'
-rwxrwx--- 1 root vboxsf 18960 Mar 23 09:56 94974f08-5853-41ab-938a-ae1bd86d8e51
-rwxrwx--- 1 root vboxsf 12632 Mar 23 09:56 'Anni%3fTheda=Merrilee%3fc'
-rwxrwx--- 1 root vboxsf 2035 Mar 23 09:56 vn84.ps1

Inside of vn84.ps1, a jumbled PowerShell script showed a BitsTransfer (L5) from 64.226.84.200 (end of L1) to download a payload encrypted with a predefined key (L10) and IV (L11):

The tangled mess known simply as vn84.ps1
${K`EY} = [byte[]] (0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0)
${iv} = [byte[]] (0,1,1,0,0,0,0,1,0,1,1,0,0,1,1,1)
http://64.226.84.200/94974f08-5853-41ab-938a-ae1bd86d8e51

The payload downloaded via BitsTransfer can be found as a file named after the web path,94974f08–5853–41ab-938a-ae1bd86d8e51, in the dump of all the HTTP objects (neat, huh?):

$ xxd 94974f08-5853-41ab-938a-ae1bd86d8e51 | head
00000000: 2cef ef8e 516c 1aea ee9c 9c05 c584 a4bc ,...Ql..........
00000010: 1791 d526 804e b1d4 7d0e b442 59ed 288b ...&.N..}..BY.(.
00000020: 99c6 5ec6 36fc da43 dce5 a53f f720 bfda ..^.6..C...?. ..
00000030: 2fc1 19ad 34d5 2a85 6b49 31a4 65fa a3be /...4.*.kI1.e...
00000040: 3890 119f bdf3 2500 9b52 cc15 dbcd de9f 8.....%..R......
00000050: 0a9c 207a 054f 87db f9d1 50bb fe1e a9e4 .. z.O....P.....
00000060: 1225 2d37 982d ffb8 69ad f63f baf8 5cd5 .%-7.-..i..?..\.
00000070: e86c 458c c6d9 b24b 23b2 7fd0 6260 a51d .lE....K#...b`..
00000080: c6ab 21dd caf2 df3e 8956 9477 98a9 163e ..!....>.V.w...>
00000090: fb7e f9d0 6154 85fa 3b3a 7a16 4098 3d9c .~..aT..;:z.@.=.

Throwing together a quick python script, I was able to decrypt the blob with the provided key and IV:

Python decryptor for phase 1
$ xxd ../phase1.dec | head            
00000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000 MZ..............
00000010: b800 0000 0000 0000 4000 0000 0000 0000 ........@.......
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 8000 0000 ................
00000040: 0e1f ba0e 00b4 09cd 21b8 014c cd21 5468 ........!..L.!Th
00000050: 6973 2070 726f 6772 616d 2063 616e 6e6f is program canno
00000060: 7420 6265 2072 756e 2069 6e20 444f 5320 t be run in DOS
00000070: 6d6f 6465 2e0d 0d0a 2400 0000 0000 0000 mode....$.......
00000080: 5045 0000 4c01 0300 0000 0000 0000 0000 PE..L...........
00000090: 0000 0000 e000 0201 0b01 0800 0042 0000 .............B..

$ file ../phase1.dec
../phase1.dec: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows

Ok, cool it’s a .NET executable! If you know me, you know what time it is…

IT’S DNSPY TIME!!!! ::RANDOM LOUD ALARM NOISES:: ::15 SECOND TECHNO INSTRUMENTAL BREAK::

…Now that that’s over with, I fired up dnSpy to survey and study the malware. Tons of places to start:

Behold! More Functions!!!

After skimming the most likely starting spots, I focused initially on primer. Either this function was going to make painting my Jeep a heck of a lot easier, or it’s probably the initial start-up for this dropper. A few things caught my eye:

Primer Function of dropper c2. Not paint.

An initial hardcoded key can be found on L40, followed by a web check-in on lines L42–48, and finally the logic for the rekey can be found on L74. So essentially, the first check-in is encrypted with the hardcoded key, and then subsequent traffic should be encrypted with the value of NEWKEY8839394 received from the server. Oh and the IV isn’t mentioned, so I assumed (and verified upon glancing at the Encryption/Decryption routines) that it is very likely the first 16 bytes of the payload. Also of note, the payloads received via GET request were base64 encoded.

With this knowledge, it was time to move to the next stage. Using the data from the path /Kettie/Emmie/Anni?Theda=Merrilee?c, I decrypted the payload and was met with the updated settings for the C2, including the new key:

Python decryptor for phase 2
RANDOMURI19901dVfhJmc2ciKvPOC10991IRUMODNAR
URLS10484390243"Kettie/Emmie/Anni?Theda=Merrilee", "Rey/O... ...ndrika/Ilysa/Caroljean?Aline=Tine"34209348401SLRU
KILLDATE16652025-01-015661ETADLLIK
SLEEP980013s10089PEELS
JITTER20250.25202RETTIJ
NEWKEY8839394nUbFDDJadpsuGML4Jxsq58nILvjoNu76u4FIHVGIKSQ=4939388YEKWEN
IMGS19459394"iVBORw0KGgoAAAANSUhEUgAAAB4AAAAe... ...m3hFDfYAAAAASUVORK5CYII="49395491SGMI

The key for phase 3, as discovered in the primer function earlier, was found at NEWKEY8839394:

nUbFDDJadpsuGML4Jxsq58nILvjoNu76u4FIHVGIKSQ=

A bunch of base64 strings were also found at the very bottom. These were a little bit of a time sink as I foolishly tried to investigate each one, only to realize that they are just simple PNG files the C2 uses to POST data back to the server. More on that in a minute.

I now need to go back and discover the actual C2 post/receive engine. I stumbled onto the function ImplantCore.

ImplantCore Function of the dropper C2

Interesting things to examine: L40–41 demonstrates the web request, then decryption of the payload from the server, L68 shows an example use of the EXEC function, and the main commands for the C2 can be seen.

Delving into EXEC, I found this function drives the POST responses back to the webserver:

Exec Function of the dropper C2

Essentially, EXEC will call Encryption with the compress flag set to true and the ImgGen class to grab a PNG containing the payload.

The Encryption function is pretty straight forward AES encryption with base64 encoding with a couple wrinkles. There is a boolean for gzip compression as well as an override for the output data (un) if specified (unByte):

Encryption function of the dropper c2

In the class ImgGen, the function Init grabs the base64 values of the images found in phase2_dec, RandomString appends garbage data as needed, and the heavy lifter is GetImgData:

You know the drill. It’s obvi the ImgGen class.

GetImgData takes a pre-canned PNG (from phase2 dec) and adds garbage to it until the file is up to 1500 bytes. Then it appends the encrypted, compressed, but not base64'd value of the data the C2 wishes to POST back to the server.

Armed with this knowledge, I was (FINALLY) able to decrypt the POST requests with the updated key found in phase2. Cobbling the below python script together provided two executable binaries, a screenshot, a mimikatz dump, some unknown files, and a partridge in a pear tree (yeah, you’re right, it’s too early for the Christmas jokes):

Python decrypto for phase 3
$ ls -al ../dec_*
-rwxrwx--- 1 root vboxsf 2827854 Mar 23 13:03 '../dec_%3fdVfhJmc2ciKvPOC(14).bin'
-rwxrwx--- 1 root vboxsf 5132 Mar 23 13:03 '../dec_%3fdVfhJmc2ciKvPOC(17).dec'
-rwxrwx--- 1 root vboxsf 32 Mar 23 13:03 '../dec_%3fdVfhJmc2ciKvPOC(20).dec'
-rwxrwx--- 1 root vboxsf 27 Mar 23 13:03 '../dec_%3fdVfhJmc2ciKvPOC(22).dec'
-rwxrwx--- 1 root vboxsf 847050 Mar 23 13:03 '../dec_%3fdVfhJmc2ciKvPOC(23).png'
-rwxrwx--- 1 root vboxsf 32 Mar 23 13:03 '../dec_%3fdVfhJmc2ciKvPOC(4).dec'
-rwxrwx--- 1 root vboxsf 27 Mar 23 13:03 '../dec_%3fdVfhJmc2ciKvPOC(5).dec'
-rwxrwx--- 1 root vboxsf 6 Mar 23 13:03 '../dec_%3fdVfhJmc2ciKvPOC(6).dec'
-rwxrwx--- 1 root vboxsf 201746 Mar 23 13:03 ../dec_%3fdVfhJmc2ciKvPOC.bin

The screenshot contains the key:

Yeah, I know… that’s waaaaaaay too small to read in the deafult view. But trust me, it’s there in the top right :-)

FLAG: HTB{h0w_c4N_y0U_s3e_p05H_c0mM4nd?}

Conclusion

Again, this was a great challenge I really enjoyed that showcases the use of scripting for forensics uses. Finding SharpSploit, mimimatz output, Core.exe and the obfuscation techniques definitely added to the immersion of the challenge. I also will add that solving this aided my approach and process on the Relic Maps challenge, as the Powershell found inside the HTA was also obfuscated and made use of AES with a hardcoded key.

Maveris is an IT and cybersecurity company committed to helping organizations create secure digital solutions to accelerate their mission. We are Veteran-owned and proud to serve customers across the Federal Government and private sector. Maveris Labs is a space for employees and customers to ask and explore answers to their burning “what if…” questions and to expand the limits of what is possible in IT and cybersecurity. To learn more, go to maveris.com

--

--

Khris Tolbert
Maveris Labs

Sometimes things break and I happen to be behind the keyboard. I’m just as confused as you are.