STRRAT (Strigoi) - Malware Analysis Lab Published: 2022-04-15 · Archived: 2026-04-05 16:25:08 UTC Overview Part 1: STRRAT Dropper and STRRAT Deobfuscation Let’s take a look at a recent sample of the Java-based malware known as STRRAT. We will cover some techniques on how to identify the malware and reverse engineer it. We will start with a malicious JAR file being distributed through email malspam campaigns, and in this instance the file had the name INQUIRY______535262623.jpg.jar Source: Malshare.com Extra Public Reporting: Karsten Hahn - G Data Extra Public Reporting: Microsoft Extra Public Reporting: Brad Duncan First off we obtain a sample with a particular SHA256 hash: Starting Host IOC: ec48d708eb393d94b995eb7d0194bded701c456c666c7bb967ced016d9f1eff5 Given this is a Java-based RAT we can start by opening it using JD-GUI, a Java Decompiler. https://www.jaiminton.com/reverse-engineering/strrat Page 1 of 124 If we expand out the only class this contains, we immediately begin to see references to its resource section, wscript, and “user.home”. Given these references, and the lack of classes, this is a good indicator that the Java Archive will likely function as a dropper, placing a script with the name “loorqhustq.js” in the users home directory. To understand the script being dropped to “loorqhustq.js”, we can take a look at the resource section by extracting the Java Archive using 7-Zip. At a glance this isn’t too large; however, it does have a Base64 blob which looks to be present and some data manipulation to ensure this can’t easily be decoded. One way to tackle this is to replace references of “eval” (which is essentially telling JavaScript to execute and evaluate what it is being passed, and instead make this https://www.jaiminton.com/reverse-engineering/strrat Page 2 of 124 “console.log”. By doing this the malicious JavaScript will instead log what it is being presented, rather than processing and evaluating it. To do this we still need a way to interpret the JavaScript in a safe setting. By opening up Google Chrome and pressing “F12” we can view the console. At this point we can copy in our modified JavaScript and have Chrome interpret it for us. The end result is a variable being defined containing an object called lmao$$$_. This is an ActiveXObject storing a Base64 encoded string; however, because we ran this inside of a browser and replaced the eval statements, we get an Uncaught ReferenceError. This is expected as we didn’t want the dropper to progress, and only wanted to extract this Base64 string. By copying solely the string into CyberChef, we’re able to begin extracting what will be dropped. https://www.jaiminton.com/reverse-engineering/strrat Page 3 of 124 Examining this decoded string reveals a variable which is being defined as “longText”, before being manipulated to make a valid Base64 string which is once again decoded to disk, this time in the user’s application data directory to a file called r.txt Before we look into extracting ‘r.txt’, we can continue to look at what is happening when the dropper triggers. Examining the first part of the dropper, we find it is enumerating if the Java Runtime Environment is present, and where it is, it will attempt to execute the dropped “r.txt” as a Java Archive, if not, it will run a function called “GrabJreFromNet”. https://www.jaiminton.com/reverse-engineering/strrat Page 4 of 124 Looking at the function GrabJreFromNet, we can see that it attempts to reach out to hxxp[://]wshsoft[.]company/jre7[.]zip to pull down a version of JRE. This is then saved to a zip file in the user’s application data directory before it is extracted to disk, used to run r.txt, and a run key is setup for persistence to ensure it always runs whenever that user logs on. Network IOC: hxxp[://]wshsoft[.]company/jre7[.]zip Registry Run Key Persistence (Host IOC): HKCU\Software\Microsoft\Windows\CurrentVersion\Run\ntfsmgr At this point we can go ahead and take the first 4 lines of this second stage dropper, and add an entry to once again log to the console the contents of “longText” which will be decoded to r.txt as a Java Archive and run. https://www.jaiminton.com/reverse-engineering/strrat Page 5 of 124 The output is a “PKZIP” archive, which we can identify through the presence of a MANIFEST.MF as a Java Archive. We’re able to download this file to disk and retrieve the new hash of this Java Archive using PowerShell. get-filehash .\STRRAT.jar https://www.jaiminton.com/reverse-engineering/strrat Page 6 of 124 0A6D2526077276F4D0141E9B4D94F373CC1AE9D6437A02887BE96A16E2D864CF Host IOC: 0A6D2526077276F4D0141E9B4D94F373CC1AE9D6437A02887BE96A16E2D864CF By checking the hash against VirusTotal we can see it hasn’t been analysed and shared publicly yet. To help ensure AV vendors are aware of this STRRAT sample, we can submit it to VirusTotal for scanning. 27/60, not a bad rate of detection, noting this doesn’t represent all detection capabilities by vendors, and just because a vendor doesn’t flag it here, doesn’t mean they won’t detect or prevent it in production. Opening STRRAT in JD-GUI, we can take a look at the manifest file to find the ‘Main’ class which will be executed when the archive is run. https://www.jaiminton.com/reverse-engineering/strrat Page 7 of 124 By examining the main class we get a lot of obfuscated classes, and references to “StringBuilder” being leveraged. The string ‘STRRAT” is also present once we deobfuscate this sample. At this stage deobfuscating the code manually would be a bit of a challenge. Luckily we have java-deobfuscator available to us which can perform a lot of the heavy lifting. To use this we will first create a yaml file called detect.yml which will be used to detect what obfuscator is in use. input: C:\Users\User\Desktop\STRRAT\Stage 2\STRRAT.jar detect: true From here we can pass this as the configuration to deobfuscator, and find that this looks to be using “Allatori’s Java Obfuscator - String Encryption”. java -jar deobfuscator.jar --config detect.yml https://www.jaiminton.com/reverse-engineering/strrat Page 8 of 124 The irony is that the website providing this tool is calling us a “hacker” for reverse engineering the Java Archive. From here we can create another file set to deobfuscate the Java Archive in question using the first recommended transformer. input: C:\Users\User\Desktop\STRRAT\Stage 2\STRRAT.jar output: C:\Users\User\Desktop\STRRAT\Stage 2\STRRAT-Deobfuscated.jar transformers: - com.javadeobfuscator.deobfuscator.transformers.allatori.StringEncryptionTransformer After executing the transformer in question we’re presented with a number of “decryption methods”, and “encrypted strings” being rectified. In this instance there’s some output errors also, but this isn’t of concern. java -jar deobfuscator.jar --config config.yml At this point we can see a number of Java Archive files being referenced: https://www.jaiminton.com/reverse-engineering/strrat Page 9 of 124 Of these referenced includes a project “system-hook” which is essentially being used here as a Java-based key-logger. Examining the Main Class further we can now find reference to a pastebin URL being contacted. This gives us some potential C2 infrastructure leveraged by this malware. It should be noted this can be modified by the Pastebin user to point elsewhere. https://www.jaiminton.com/reverse-engineering/strrat Page 10 of 124 Dynamic Infrastructure (Network IOC): hxxps[://]pastebin[.]com/raw/Jdnx8jdg Pastebin Actor Account (Network IOC): hxxps[://]pastebin[.]com/u/wshsoft At the time of writeup this page had been visited 32,736 times, and pointed to the domain pluginserver[.]duckdns[.]org Current Infrastructure (Network IOC): pluginserver[.]duckdns[.]org In addition there’s a hardcoded URL mentioned which looks to contact the below: Network IOC: hxxp[://]str-master[.]pw/strigoi/server/ping[.]php?lid= Taking a look at the class cbnfdhn.class, we can get a feel for some potential functionality of STRRAT including shutting down an operating system, uploading and downloading files… Enumerating the OS, processes, key-logging, stealing saved credentials. https://www.jaiminton.com/reverse-engineering/strrat Page 11 of 124 In addition there’s a reference to “crimson_info.txt” which has been publicly reported as a fake ransomware module. Part 2: Extracting and Decrypting STRRAT Configuration https://www.jaiminton.com/reverse-engineering/strrat Page 12 of 124 To perform more thorough analysis on the deobfuscated STRRAT, we’re going to leverage a tool called ‘Recaf’. This will allow us to decompile Java classes in a more user-friendly way given the malware authors have reused class and method names. Upon decompiling this we’re going to take a look at the primary entry point of the program in the “Main” class. An easy way to find this class is to search for “void main” because the main class method isn’t intended to return any output. In the below we see a watermark added to the malware to show that “Allatori Obfuscator 7.3 DEMO” was used to obfuscate it. In addition we can see it is checking for the number of arguments provided, and where this isn’t provided it will run the Main.bsgshsbs method (which is returning an object to be created from the ‘dfghrth’ class). Further to this we can see a message of “This PC is not supported” being returned after this if a string isn’t able to be assigned from the output of Main.sdfsldf. To find the right method definition here we can search for “String sdfsldf()” given we know it is returning a string, and here we can see that it is simply looking for the path the running JAR file is running from (likely taken from this StackOverflow post). Examining the object created from the “dfghrth” class reveals this is a file lock being created in the user’s home directory. If there are command-line arguments added this will create a file lock with the name “64578lock.file” in the user’s home directory given this number is passed as a parameter when creating this lock object. https://www.jaiminton.com/reverse-engineering/strrat Page 13 of 124 This serves as the port that the RAT will connect back to. In the case where no command-line arguments are provided, this will first create an object called “object2” from the Main class method “bsgshsbs”. To make finding these references easier, we’ll begin right clicking them and using “Goto definition”. We can also reveal references to this particular method by instead clicking “Search references”. https://www.jaiminton.com/reverse-engineering/strrat Page 14 of 124 Examining this method we can see that it looks to be taking in a stream from a file within its resources called ‘config.txt’, Base64 decoding it, and then it passes this and the string “strigoi” to another method, this time within the sabretb class called “dfhttegd”. https://www.jaiminton.com/reverse-engineering/strrat Page 15 of 124 Within this class and method we can see that STRRAT is performing an AES decryption routine based on the provided AES encrypted stream from config.txt, and a “password” of “strigoi”. Although I’m no crypto expert, in short, the password is being used to derive a secret key via the “password-based key derivation function 2” (PBKDF2), 65536 SHA1 hashing iterations, a key size of 128, using CBC mode, and a salt which is the ‘nonce’ extracted from our AES encrypted string. In this instance the “salt” (nonce) functions as the Initialisation Vector used with the AES Key to decrypt the string. More reading around AES Encryption and Decryption in Java can be found created by baeldung To decrypt this using CyberChef we would have to first get the salt (nonce) used, derive the PBKDF2 key, and then use this with the appropriate IV to decrypt our content. https://www.jaiminton.com/reverse-engineering/strrat Page 16 of 124 This is a bit of work, and can quickly get confusing. Because STRRAT is implementing a decryption method, we can go ahead and take the relevant parts of the decryption method to decrypt the config file ourselves. If we copy “sabretb” and “dfhttegd” from “sabretb”, and also “bsgshsbs” from Main, we’ve got the start of a decryption program (noting we will need to import the appropriate libraries in use). https://www.jaiminton.com/reverse-engineering/strrat Page 17 of 124 In the above we’ve copied the core content in; however, there’s still some issues based on duplicate named variable declarations, classes which aren’t throwing an exception, and an issue based on how it is reading the file input. I’ve gone ahead and rectified this with the end result being a Decrypter which takes 2 arguments, (input file, output file). Note: At present during our analysis there’s some unknown configuration values as we haven’t completely reveresed the malware. https://www.jaiminton.com/reverse-engineering/strrat Page 18 of 124 The decrypter as it stands so far can be found below: import java.nio.ByteBuffer; import java.io.File; import java.nio.file.StandardOpenOption; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.charset.StandardCharsets; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class STRRATConfigDecrypt { https://www.jaiminton.com/reverse-engineering/strrat Page 19 of 124 public static void main(String[] args) throws Exception { System.out.println("###################################################"); System.out.println("# STRRAT Malware (v.1.4) Decrypter by @CyberRaiju #"); System.out.println("###################################################"); if (args.length < 1) { System.out.println(); System.out.println("PEBCAK - Use this with 2 arguments, an input and output file"); System.out.println("Example:"); System.out.println( "java -jar STRRATConfigDecrypt.jar \'C:\\Users\\User\\config.txt\' \'C:\\Users\\User\\decryp } else { String inputdirectory = args[0].replace("\\", "\\\\"); String outputdirectory = args[1].replace("\\", "\\\\"); File configfile = new File(inputdirectory); byte[] config = Files.readAllBytes(configfile.toPath()); byte[] parsedBytes = Base64.getDecoder().decode(config); byte[] decryptedConfig = DecryptAES("strigoi", parsedBytes); String string[] = new String(decryptedConfig, StandardCharsets.UTF_8).split("\\|"); System.out.println("Network IOC: " + string[0]); System.out.println("File Lock: " + string[1] + "lock.file"); System.out.println("Network IOC: " + string[2]); System.out.println("Network IOC: " + string[3]); System.out.println("Unknown Parameter: " + string[4]); System.out.println("Unknown Parameter: " + string[5]); System.out.println("Unknown Parameter: " + string[6]); System.out.println("Unknown Parameter: " + string[7]); System.out.println("Possible License/Campaign ID: " + string[8]); Path output = Paths.get(outputdirectory); Files.write(output, "# STRRAT Malware (v.1.4) Decrypter by @CyberRaiju #\r\n".getBytes()); for (String str : string) { str = str+"\r\n"; Files.write(output, str.getBytes(),StandardOpenOption.APPEND); } } } public static SecretKey SecretKey(String password, byte[] data) throws Exception { PBEKeySpec a = new PBEKeySpec(password.toCharArray(), data, 65536, 128); byte[] b = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(a).getEncoded(); return new SecretKeySpec(b, "AES"); } public static byte[] DecryptAES(String password, byte[] bytes) throws Exception { ByteBuffer byteBuffer; int n; https://www.jaiminton.com/reverse-engineering/strrat Page 20 of 124 byteBuffer = ByteBuffer.wrap(bytes); n = byteBuffer.getInt(); if (n < 12 || n > 16) { throw new IllegalArgumentException( "Nonce size is incorrect. Make sure that the incoming data is an AES encrypted file."); } byte[] object3 = new byte[n]; byteBuffer.get(object3); SecretKey key = SecretKey(password, object3); byte[] byArray2 = new byte[byteBuffer.remaining()]; bytes = byArray2; byteBuffer.get(byArray2); Cipher crypto = Cipher.getInstance("AES/CBC/PKCS5PADDING"); IvParameterSpec IVSpec = new IvParameterSpec(object3); crypto.init(2, key, IVSpec); return crypto.doFinal(bytes); } } After ensuring the config file has been extracted, by running this using Visual Studio Code and the following command line: cd 'c:\Users\User\Desktop\STRRAT\Stage 2\STRRAT-Deobfuscated\carLambo\resources\Decrypter\STRRATConfigDecrypt'; We’re presented with a decrypted configuration output which has also been stored in a file called “decrypted.txt”. Network IOC: moregrace[.]duckdns[.]org Host IOC: 3219lock.file Network IOC: hxxp[://]jbfrost[.]live/strigoi/server/?hwid=1&lid=m&ht=5 Network IOC: palaintermine[.]duckdns[.]org Although the config parameters have been extracted, it’s not clear on exactly what they’re used for. By looking back into the method “sdfsldf” in the Main class we can see it is checking arguments provided, and if an argument https://www.jaiminton.com/reverse-engineering/strrat Page 21 of 124 was provided, it would only use the 3rd configuration parameter from the file (the jbfrost[.]live URL) in a call to “cbnfdhn.sabretb”. In addition to this, the above mentioned method is all about making a GET request to the server and retrieving the response to return as a string. We know that this string is being returned to cbnfdhn.dfhttegd which if we look into is holding a public string that can be referenced from multiple classes, so we know it is being stored for later usage. https://www.jaiminton.com/reverse-engineering/strrat Page 22 of 124 By viewing references to this, we can see the different methods which either “PUT” a value into this variable, or “GET” the value from the variable. https://www.jaiminton.com/reverse-engineering/strrat Page 23 of 124 At this point we know that the variable is written to within 5 methods, and read from 5 methods. If we examine where it is being read from by right clicking and selecting “Edit with Assembler”, we can see that all of these methods are creating sockets and using this as the callback address. In addition we can see reference to what appears to be “Reverse Proxy” and “HDRDP” debug/response messages. https://www.jaiminton.com/reverse-engineering/strrat Page 24 of 124 By performing some OSINT using urlscan.io we find that this URL used to just return ‘pluginserver[.]duckdns[.]org’, which is the same domain we found linked to our pastebin URL. It’s very likely that this domain was being used to fetch plugins for STRRAT. To tie most of this back together we can return to method “sdfsldf” within the Main class and examine more closely what it is doing here. https://www.jaiminton.com/reverse-engineering/strrat Page 25 of 124 In the above we see it is defining a couple of variables, one for the primary plugins URL which is extracted from the config file, and one which is pointing to the pastebin URL containing the same domain. We then see it is using this to download the appropriate Java Archive files (plugins), before a request is made to a master server which looks to have been registered to take a license ID. In this case the license ID would be “khonsari”. We can also confirm that after this a file lock is being created in the user home directory by examining the object defined within object9 which in this case is an instance of “dfghrth”. https://www.jaiminton.com/reverse-engineering/strrat Page 26 of 124 At this stage we can begin to update our decrypter to refine what we’re pulling in from the config file. It should be noted that we’ve inferred this is STRRAT version 1.4 by examining the method “shshnfdn” within “cbnfdhn” which looks to be a check to see if STRRAT has been installed on this host or not. If we move back to examining the main method which will continue to run, we can see that one of the parameters passed as “True” is used to determine if persistence will be setup using a scheduled task called “Skype”, with another being used to determine if the configuration will be passed to a new array. This new array is then used within sstydgn.sdfsldf, where the stringArray3 7th parameter is also set to true. https://www.jaiminton.com/reverse-engineering/strrat Page 27 of 124 Host IOC: Scheduled Task - "Skype" If we once again examine references to this, it appears as if these values are also being used to determine if persistence is installed, only this time it is writing to the user’s startup directory. https://www.jaiminton.com/reverse-engineering/strrat Page 28 of 124 At this stage we have enough information and context to complete our STRRAT configuration decrypter and can compile a Java Archive to extract the configuration from a given config.txt file. "C:\Program Files\OpenJDK\openjdk-11.0.9_11\bin\java.exe" -jar STRRATConfigDecrypt.jar "C:\Users\User\Desktop\S The completed STRRAT Config Decrypter has been made available for use here. This takes a configuration file and decrypt’s it. Alternatively, after collaborating with some bright minds on Twitter (shoutout to Chaitanya - @CbGmanit who reached out with assistance on properly getting the salt (nonce) used), the following recipe has been devised to fully decrypt this using CyberChef here From_Base64('A-Za-z0-9+/=',true) To_Hex('Space',0) Register('([\\s\\S]{11}).([\\s\\S]{47})',true,false,false) Register('([\\s\\S]*)',true,false,false) https://www.jaiminton.com/reverse-engineering/strrat Page 29 of 124 Derive_PBKDF2_key({'option':'UTF8','string':'strigoi'},128,65536,'SHA1',{'option':'Hex','string':'$R1'}) Register('([\\s\\S]*)',true,false,false) Find_/_Replace({'option':'Regex','string':'.*'},'$R2',false,false,true,false) Find_/_Replace({'option':'Regex','string':'^([\\s\\S]{60})'},'',true,false,true,false) AES_Decrypt({'option':'Hex','string':'$R3'},{'option':'Hex','string':'$R1'},'CBC','Hex','Raw',{'option':'Hex','s Find_/_Replace({'option':'Regex','string':''},'',true,false,true,false) Register('([a-zA-Z.]*).([a-zA-Z0-9.]*).([a-zA-Z0-9\\:?@=\\-&%//.]*).([a-zA-Z.]*).([a-zA-Z0-9.]*).([a-zA-Z0-9.]*) Find_/_Replace({'option':'Regex','string':'.*'},'$R4',false,false,true,false) Find_/_Replace({'option':'Simple string','string':'$R4'},'C2: $R4',false,false,true,false) Register('([\\s\\S]*)',true,false,false) Find_/_Replace({'option':'Regex','string':'.*'},'$R5',false,false,true,false) Find_/_Replace({'option':'Simple string','string':'$R5'},'Primary Lock/Port: $R5',false,false,true,false) Register('([\\s\\S]*)',true,false,false) Find_/_Replace({'option':'Regex','string':'.*'},'$R6',false,false,true,false) Find_/_Replace({'option':'Simple string','string':'$R6'},'Plugins Download URL: $R6',false,false,true,false) Register('([\\s\\S]*)',true,false,false) Find_/_Replace({'option':'Regex','string':'.*'},'$R7',false,false,true,false) Find_/_Replace({'option':'Simple string','string':'$R7'},'Secondary C2: $R7',false,false,true,false) Register('([\\s\\S]*)',true,false,false) Find_/_Replace({'option':'Regex','string':'.*'},'$R8',false,false,true,false) Find_/_Replace({'option':'Simple string','string':'$R8'},'Secondary Lock/Port: $R8',false,false,true,false) Register('([\\s\\S]*)',true,false,false) Find_/_Replace({'option':'Regex','string':'.*'},'$R9',false,false,true,false) Find_/_Replace({'option':'Simple string','string':'$R9'},'Startup Folder Persistence: $R9',false,false,true,fals Register('([\\s\\S]*)',true,false,false) Find_/_Replace({'option':'Regex','string':'.*'},'$R10',false,false,true,false) Find_/_Replace({'option':'Simple string','string':'$R10'},'Secondary Startup Folder Persistence: $R10',false,fal Register('([\\s\\S]*)',true,false,false) Find_/_Replace({'option':'Regex','string':'.*'},'$R11',false,false,true,false) Find_/_Replace({'option':'Simple string','string':'$R11'},'Skype Scheduled Task Persistence: $R11',false,false,t Register('([\\s\\S]*)',true,false,false) Find_/_Replace({'option':'Regex','string':'.*'},'$R12',false,false,true,false) Find_/_Replace({'option':'Simple string','string':'$R12'},'License ID: $R12',false,false,true,false) Register('([\\s\\S]*)',true,false,false) Find_/_Replace({'option':'Regex','string':'.*'},'$R13\\n$R14\\n$R15\\n$R16\\n$R17\\n$R18\\n$R19\\n$R20\\n$R21',f Simply put in the config file above, and receive your decrypted configuration file. Update: 6/4/2022 - This has also been ported to Python3 and improved upon for those who like to incorporate this into their automation pipelines, or who just enjoy some ASCII artwork ;) and can be found here. This takes a jar file (strrat) which contains the configuration file within its resources and automatically reads and decrypts this without the need to extract it first. Usage: python3 decrypt-strrat.py [PATH TO STRRAT] https://www.jaiminton.com/reverse-engineering/strrat Page 30 of 124 Part 3: Examining RAT Flow and Functionality To drill into this a bit more, we need to know what Java classes are going to be most interesting. One way of doing this is to extract the classes and filter based on their size, because a larger class may often be indicative of more code making up more interesting functionality. https://www.jaiminton.com/reverse-engineering/strrat Page 31 of 124 The easiest way to view this code is to view it in Decompiler view rather than viewing them in the ‘Edit with Assembler’ view we used above. If we’re having issues with using the Decompiler, it can often be useful to revisit previous steps. For example if we’re unable to decompile a class, perhaps we should try to deobfuscate the malware using the second transformer recommended by java-deobfuscator, or we could try a different decompiler within Recaf. In this instance there doesn’t appear to be any issues, so let’s first look back at the references to our public static string object ‘cbnfdhn.dfhttegd’ which is essentially holding the value “pluginserver[.]duckdns[.]org”. Within the fgfnbnc class we find this is referenced 3 times. In the first instance we see it is the method cbnfdhn.dfhttegd being run rather than the public string being accessed. https://www.jaiminton.com/reverse-engineering/strrat Page 32 of 124 Because this is a method, we disregard this hit, but make note that whenever the method fgfnbnc.dfhttegd is run, it will attempt to run the method cbnfdhn.dfhttegd. Looking at the next method we can see the reference to HRDP-MGR we saw previously with a little more context. In this instance we can see a new registry key being created which ensures that User Names are not shown at the login screen. Host IOC: HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System /v dontdisplaylastusername = 1 This is interesting as it immediately follows what looks to be ensuring that Terminal Services are enabled, and a call to add a user account. To determine if there’s a hardcoded user account we can look out for we will need to examine ‘object2’ which is being cast to a string here; however, before we do we’ll begin to rename some of these https://www.jaiminton.com/reverse-engineering/strrat Page 33 of 124 variables to help keep track of what we’re looking at. To do this we will need to ensure we’ve highlighted the correct class reference, and right click > rename. Using Recafe all associated class references will be updated. In this instance I’ve renamed it to PluginsServerURL, and also renamed the other reference in this socket connection to PluginsServerPort. Moving back to ‘object2’, we can see this is being assigned by fgfnbnc3.dfhttegd. By viewing the definition of this variable, we find it is defined in the same class we’re currently in. Renaming this variable and revisiting the call, we see that there’s an object definition of fgfnbnc3 from the class fgfnbnc which is why we didn’t see a class with the name fgfnbnc3. The benefit of renaming the String is that now we can find all references to that easily. If we continue to examine this class we find that there’s a definition of this variable within fgfnbnc’s fgsbdfgsb method. Examining this method reveals it is a small function used to build a random string to be used as a Username. https://www.jaiminton.com/reverse-engineering/strrat Page 34 of 124 It’s important to remember that because we’ve managed to get some decompiled code, string builders like this can be replicated using VS Code to confirm what we’re reading. Although this is a basic method, we can still recreate it by making a class that spits out the output of this method. From this we can see this will create a random string with 5 characters. https://www.jaiminton.com/reverse-engineering/strrat Page 35 of 124 To get some structure behind analysing this malware flow, we’ll return to the main class that we know will be run as soon as this malware kicks off. First we’ll begin to rename any methods or variables we’ve found so far and give them more descriptive names based on their perceived functionality. I won’t walk through all of the analysis before renaming the variables to assist with analysing the malware in a more meaningful way. We’ll continue to rename more as we determine their purpose; however to start off the following have been renamed: cbnfdhn.sabretb (Method) = cbnfdhn.MakeGetRetResponse Main.sdfsldf (Method) = Main.ObjMakeGetRetResponse Main.sdfsldf (Static String) = Main.STRPluginLocations Main.sabretb (Static String) = Main.STRFileSeparate Main.bsgshsbs (Object) = Main.ObjFileLock1 Main.dfhttegd (Object) = Main.ObjFileLock2 dfghrth (Class) = FileLock Main.sdfsldf (Method, no input) = Main.GetJarRunPath cbnfdhn.sdfsldf (Method, inputs) = cbnfdhn.C2ConnectAndRun cbnfdhn.mdgghtdsh (Static InputStream) = cbnfdhn.InStream1 cbnfdhn.sgsfghhg (Static OutputStream) = cbnfdhn.OutStream1 cbnfdhn.hghteerd (Method, no input) = cbnfdhn.ConnectToC2 cbnfdhn.gsbthstgb (Static String) = cbnfdhn.Port1 xbxcv (Class) = UserIdleObject Main.bsgshsbs (Method, no inputs) = Main.ExtractConfig sabretb.dfhttegd (Method, inputs) = sabretb.DecryptConfig sabretb.sdfsldf (Method, inputs) = sabretb.DeriveIV sabretb.sabretb (Method, inputs) = sabretb.CreateSecKey Main.dfhttegd (Method, no inputs) = Main.ConnectUnknownURL cbnfdhn.sdfsldf (Method, one int input) = cbnfdhn.GetFolderPath cbnfdhn.sdfsldf (Method, one string array input) = cbnfdhn.Uninstall cbnfdhn.bsgshsbs (Static String) = cbnfdhn.FolderPath cbnfdhn.sfsrgsbd (Static String) = cbnfdhn.STRLogsLocation cbnfdhn.sabretb (Static String) = cbnfdhn.STRBackupC2 cbnfdhn.sdfsldf (Static Boolean) = cbnfdhn.ActiveConToC2 cbnfdhn.thtyrths (Method, no input) = cbnfdhn.ParseNumOfCommands cbnfdhn.sabretb (Method, one int input) = cbnfdhn.ReceiveCommands https://www.jaiminton.com/reverse-engineering/strrat Page 36 of 124 If we now examine the main method again we find the below: If the malware is able to get the current malware run path and place dependency files in a folder called ‘lib’, it will then attempt to get the AppData directory based on CSIDL 26. The malware will continue to extract/decrypt its config file and make requests to get any plugins from the URL configured. Finally after this we see it connect to the C2 ready to execute commands received. It should be noted that our defined variables PluginsServerURL and PluginsServerPort are both being reused here as the C2 configuration from within the decrypted config file. In the above we see the start of our C2ConnectAndRun method. In this instance it will check if a directory already exists called strlogs in the malware working directory, if not it will create one. It will also create an object containing information on whether the infected user is idle, and how long they’ve been idle for, before it inevitably connects to the C2. https://www.jaiminton.com/reverse-engineering/strrat Page 37 of 124 The ConnectToC2 method is pretty straight forward, based on the decrypted configuration file it will first close off any sockets if they already exist with the C2, next it will attempt to connect to the C2 server, and where that fails it will fallback to its backup C2. https://www.jaiminton.com/reverse-engineering/strrat Page 38 of 124 At this point we can begin to see the different commands taken by this malware as they’re received into the array ‘stringArray2’ from the designated C2, which is also placed into stringArray3. https://www.jaiminton.com/reverse-engineering/strrat Page 39 of 124 https://www.jaiminton.com/reverse-engineering/strrat Page 40 of 124 Based on this we know that STRRAT 1.4 has the following commands available. reboot https://www.jaiminton.com/reverse-engineering/strrat Page 41 of 124 shutdown uninstall disconnect down-n-exec update up-n-exec remote-cmd power-shell file-manager keylogger o-keylogger processes h-browser startup-list remote-screen rev-proxy hrdp-new hrdp-res chrome-pass foxmail-pass outlook-pass fox-pass tb-pass ie-pass all-pass save-all-pass chk-priv req-priv rw-encrypt rw-decrypt show-msg screen-on Let’s examine these commands more in depth: Command Functionality: reboot This command simply runs the following: Runtime.getRuntime().exec("cmd.exe /c shutdown /r /t 0"); Command Functionality: shutdown https://www.jaiminton.com/reverse-engineering/strrat Page 42 of 124 This command simply runs the following: Runtime.getRuntime().exec("cmd.exe /c shutdown /s /t 0"); Command Functionality: uninstall This command runs the following (Noting we’ve renamed the method to “Uninstall”): cbnfdhn.Uninstall(stringArray); The uninstall method will then proceed to delete the scheduled task persistence called skype regardless of if it exists, get the directory the malware is running from, delete it from the directory specified by CLSID 7 and 24 Listings can be found here, ping localhost to delay execution for a moment, and then delete the object passed to it, before what appears to be deletion of run keys. It should be noted that the CLSID values are being passed as an integer (Decimal) rather than Hex and would need to be converted to get that 26 = AppData, and 7 = Users Startup Folder. Command Functionality: disconnect This command will set a boolean variable we’ve renamed as ActiveConToC2 to false, before closing any stream inputs that are being used in ertdbdth to log key pushes, and then calls exit for this process thus terminating the running STRRAT instance. https://www.jaiminton.com/reverse-engineering/strrat Page 43 of 124 In essence the disconnect method is terminating the process and disconnecting the C2 connection to STRRAT. Command Functionality: down-n-exec This command will call 2 more functions inside of cbnfdhn, sabretb (object, string), and dfhttegd (string) which we’ll take a closer look at so they can be renamed. The first passed parameter to sabretb is an object that will be containing a url from which to retrieve a remote file from. This takes the received file and stores it in object3 which is then launched using either java.exe, wscript.exe, or cmd.exe depending on its extension. From here we can rename this sabretb method DownloadAndExecute. Finally examining dfhttegd (string) we can see this is just used to update the C2 on the STRRAT status, so we can name this and sdfsldf (string) StatusUpdate and StatusUpdateSend. https://www.jaiminton.com/reverse-engineering/strrat Page 44 of 124 Command Functionality: update This command will create a new object as a file passed to it by running cbnfdhn.gsbthstgb, release the current fileLock with a method called sdfsldf, execute the object that was passed down to the malware, and then uninstall the current STRRAT malware. This seems to be a fairly hacked together (pun intended) update mechanism to send an updated version of STRRAT to infect the system, and remove the existing version. There’s not a lot of error handling to ensure that this is successful though, so if the update fails to execute the new version of STRRAT or the wrong number of parameters is sent, this can lead to STRRAT uninstalling itself without actually updating. We will rename cbnfdhn.gsbthstgb to cbnfdhn.CreateFileObj for further analysis Command Functionality: up-n-exec This command will function similar to down-n-exec, only instead of it retrieving a file from a defined URL to run (download and execute) this is going to take an uploaded file directly from the C2 and execute it (upload and execute) https://www.jaiminton.com/reverse-engineering/strrat Page 45 of 124 Command Functionality: remote-cmd This command has 2 primary components, a new object creation with cbnfdhn.sfsrgsbd (this is very similar to sdfsldf (string) we renamed to StatusUpdateSend, except it does so using a new socket that’s created to the C2), and a new instance of dgdfndnbcn which is created using the newly created socket, and a string array containing “cmd.exe”. We’ll rename cbnfdhn.sfsrgsbd to cbnfdhn.StatusUpdateSendNewSock. Analysing the new instance of dgdfndnbcn, we can see that this is about 150 lines of decompiled code long, but we can start with the definition using a socket object and a string array. https://www.jaiminton.com/reverse-engineering/strrat Page 46 of 124 Although the obfuscation here makes things a little bit confusing, if we look at what we’re dealing with as a whole, we can see there’s an input and output stream from the C2, a new process using ProcessBuilder, and new threads that will be started for a given process. What’s interesting with this is that only a socket and cmd.exe is being passed to this process creation, and there’s no command-line parameters given. The reason for this is because it creates a new instance of sabretb, which in this case is the process being run, and is redirecting input and output from cmd.exe directly to the established socket connection to the C2. https://www.jaiminton.com/reverse-engineering/strrat Page 47 of 124 If an error occurs a boolean is switched and the socket is released. To this end, remote_cmd is a way of issuing remote commands to the endpoint in the form of a reverse shell. We can rename dgdfndnbcn to ReverseShell for ease of analysis. Command Functionality: power-shell This command functions much the same as remote_cmd, only it is executing an instance of powershell.exe with the command-line “-“ as opposed to running cmd.exe, which I assume is to support command-line arguments with PowerShell. Command Functionality: file-manager This command first creates connects to a new Socket on the C2 and sends a status update that the file-manager has been opened before creating a new instance of ‘ghdfdndfn’ using the created socket as a passed parameter. By examining ‘ghdfdndfn’ we can see that a new object reference to itself is defined as ghdfdndfn2, before a variable of sdfsldf is set to the passed Socket, dfhttegd is set as the input stream to this socket, and sabretb is set as the output stream to this socket. https://www.jaiminton.com/reverse-engineering/strrat Page 48 of 124 The main functionality of this object is stored within the class dfhttegd where commands can be sent via the established socket connection once the file-manager command has been run. The commands that can be sent are: navigate nav-key-log open delete savefile bringfile navigate https://www.jaiminton.com/reverse-engineering/strrat Page 49 of 124 If navigate is sent, a new call is made to dfhttegd, passing a string that is returned from a call to sabretb which takes a passed string as a parameter. To figure out what is happening, we need to take a look at sabretb. Taking a provided string, sabretb creates an array of files (directories included) based on the given string and then formats the returned file information for ease of visibility for each given file in the array. In addition this will check if the file is a directory, and if so it will insert a ‘D’ into the returned response. If not it will insert a ‘F’, and perform calculations of the file size by dividing of 1024 to get the number of kilobytes for each file returned. This means that “navigate” effectively functions as a command to “view inside this directory and show me the contents”. nav-key-log “nav-key-log” performs the same call; however, instead of passing a string provided by the C2, it will automatically pass, cbnfdhn.STRLogsLocation which is the location of STRRAT logs we’ve previously renamed, and thus we can infer this command is to navigate to the log directory and display contents. open If “open” is sent, STRRAT takes this as an instruction to execute the file using cmd.exe which will use the default COM object for the particular file extension it is attempting to run. Runtime.getRuntime().exec(new StringBuilder().insert(0, "cmd.exe /c \"").append(stringArray[1]).append("\"").to delete If “delete” is sent, STRRAT makes a call to sdfsldf (file) passing into it the output of a new file object being created with a given string passed to it. By examining sdfsldf we can see that this is a simple function designed to first determine if the object referenced by the string passed is a directory, if so then it will recursively delete all the files inside of this, and the directoy. If not, it will simply delete the file passed to it. https://www.jaiminton.com/reverse-engineering/strrat Page 50 of 124 savefile If “savefile” is sent, STRRAT makes a call to sdfsldf (String) passing in a given file which is read into a FileOutputStream to allow it to be written to disk. bringfile Finally, if “bringfile” is sent, STRRAT creates a new file object and checks if the file object (handle) it now has is a file or not, if not an error is sent back stating that “You cannot download a folder”. Where it is a file, it will make a call to sabretb (file) passing it in this file. https://www.jaiminton.com/reverse-engineering/strrat Page 51 of 124 sabretb (file) will send the bytes of the given file back through to a FileInputStream allowing the file to be downloaded. From the above scenarios, although we’re not sure if these commands are sent manually or by an interactive file-manager hosted by the C2, we can conclude that “file-manager” provides a virtual file manager which allows the above functionality. Command Functionality: keylogger This command focuses primarily around the class ghgmgf. If ghgmgf.sabretb is not true, this will create a new object from the class ghgmgf, if it is true it will be set to false. https://www.jaiminton.com/reverse-engineering/strrat Page 52 of 124 By examining ghgmgf we see that sabretb is a simple static boolean being referenced. Further to this we can examine the primary ghgmgf method to get an idea of what is happening. Taking into account the existing socket connection which is passed into this method, there’s also a null string being passed when creating the object, and due to this an entry at line 101 isn’t triggered until after a new ghgmgf object has been instantiated and started. Examining line 101 reveals HTML text which is being passed to ‘bsgshsbs’ for writing, which includes the terms ‘Keyboard Log’ and ‘Generated by Strigoi Master’ This is very basic HTML and winds up looking similar to the below, presumably appended with Keylogs as keystrokes are logged, and it tells us that the author of this malware possibly favors a dark theme. https://www.jaiminton.com/reverse-engineering/strrat Page 53 of 124 It should be noted that if any failures occur an instance of ‘gsbthstgb()’ is called which looks to be closing any existing sockets and logging that a Keylogger has been shutdown. To understand what this command aims to do we need to look at the below line which runs when a new object of ghgmgf is created after the null check above is performed. new Thread(new xnxcxvb((ghgmgf)object)).start(); By decompiling ‘xnxcxvb’ we can see that it implements the Runnable class with an instance of ghgmgf it is being passed that is assigned to ‘sdfsldf’. https://www.jaiminton.com/reverse-engineering/strrat Page 54 of 124 The key component here is that when a new thread is being created it will run ‘ghgmgf.sabretb(this.sdfsldf)’, which means we can take a look at the method inside ‘sabretb(ghgmgf)’ to determine what will happen. It’s within this method that a GlobalKeyboardHook is registered, which we know is used by the System Hook Plugin that STRRAT relies on. By decompiling this class we can see a number of keycodes being registered for listening, and a number of combination of keys to ensure that these are also logged. https://www.jaiminton.com/reverse-engineering/strrat Page 55 of 124 https://www.jaiminton.com/reverse-engineering/strrat Page 56 of 124 Given this context and because we previously saw the below line within ‘ghgmgf’ this.sfsrgsbd = ((Socket)object).getOutputStream(); We can infer that all keys logged are sent directly back to the established socket connection to the C2 in realtime, and that the command ‘keylogger’ functions as expected as a keylogger leveraging the low level library hook freely available. Command Functionality: o-keylogger This command uses the same method as ‘keylogger’, only it instead passes in a string specifying the location to log keys to disk instead of a socket. This file is a HTML file that takes the name “keylogs_.html" and is stored in https://www.jaiminton.com/reverse-engineering/strrat Page 57 of 124 our previously discovered "STRLogsLocation". From this we can infer that o-keylogger starts an offline keylogger which writes its output to disk rather than sending over an established socket. Command Functionality: processes This command creates a new object of class ‘sbsgssdfg’, passing into it the existing socket connection. Examining ‘sbsgssdfg’ we find that this implements another class that uses the Runnable class ‘sbsbgsrg’, which if we examine this can see that upon running it will execute the ‘sdfsldf (sbsgssdfg)’ method. Examining this method we can see that it is looking for parameters to have been passed, as either ‘reload’ or ‘kill’. https://www.jaiminton.com/reverse-engineering/strrat Page 58 of 124 Where ‘reload’ is passed, it will run an instance of sdfsldf(), and where ‘kill’ is passed, it will use the inbuilt Windows ‘taskkill’ command to kill a process based on its PID passed to the kill command. Examining sdfsldf(), we can see that this leverages the inbuilt Windows ‘wmic’ to enumerate process information. https://www.jaiminton.com/reverse-engineering/strrat Page 59 of 124 From this we can infer that ‘processes’ is used to interact with running processes on a system to either enumerate and show them, or kill one specified by its PID. Command Functionality: h-browser This command primarily functions from within the ‘sgsfghhg’ class. This leverages the ‘HBrowserNativeApis’ class to return appropriate bitmap representations for specific browser windows running on the victim machine. https://www.jaiminton.com/reverse-engineering/strrat Page 60 of 124 https://www.jaiminton.com/reverse-engineering/strrat Page 61 of 124 There’s a lot of code in amongst here for drawing and sending over a socket the visual contents of essentially a ‘virtual web browser’ to the adversary so we’ll hone in on some specific code. The first thing we can notice inside ‘sgsfghhg’ is the presence of a number of commands being sent down the socket including ‘start’, ‘stop’, ‘mouse-event’, and ‘key-event’. https://www.jaiminton.com/reverse-engineering/strrat Page 62 of 124 Within the above we also see that when ‘start’ is sent we get another new thread spawning for an object ‘fdghdmh’. new Thread(new fdghdmh(sgsfghhg2, (String)object3)).start(); This gives us a new method which will be run when this command is sent down which is ‘sgsfghhg.sdfsldf(sgsfghhg, String)’. https://www.jaiminton.com/reverse-engineering/strrat Page 63 of 124 By examining this method we can see this is largely based around creating a byte array that’s written down the Socket in the form of a rendered PNG. https://www.jaiminton.com/reverse-engineering/strrat Page 64 of 124 Although in this instance there’s some broken decompiled code, we can see many instances of this referencing chrome.exe and firefox.exe within methods including sdfsldf(). and sabretb(). https://www.jaiminton.com/reverse-engineering/strrat Page 65 of 124 Finally if we cross reference any references to these we can see that a large proportion of this is facilitated in the method ‘dfhttegd(String)’ which contains references to a ‘Strigoi Browser’ which starts as either a chrome or firefox process depending on what is on the victim computer. From this we can infer that ‘h-browser’ is used to spawn a virtual ‘HTML Browser’ dubbed ‘Strigoi Browser’ using either Firefox or Chrome as the host process for this. Command Functionality: startup-list This command creates a new object of class ‘sstydgn’, passing into it the existing socket connection. Once again we see a familiar thread creation, this time defined within the class ‘ncgdfhbn’. Once again implementing the runnable class this is set to kick off ‘sstydgn.sdfsldf(ssydgn)’. https://www.jaiminton.com/reverse-engineering/strrat Page 66 of 124 From here we see this takes one of 3 commands, ‘reload’, ‘delete’, or ‘add’. reload When ‘reload’ is sent this command will proceed to run an instance of ‘sstydgn.sdfsldf()’. This will first run ‘wmic’ to enumerate current notable autostart entries on the system. When accounting for escape characters the command run is as follows. wmic /node:. /namespace:'\\root\cimv2' path win32_startupcommand get name,location /format:list This then performs data processing based on the way results are returned. An example of a returned entry is included below: Location=HKU\S-1-5-19\SOFTWARE\Microsoft\Windows\CurrentVersion\Run https://www.jaiminton.com/reverse-engineering/strrat Page 67 of 124 Name=OneDriveSetup If we look at how this manifests in the code we see the following: From the above and example provided we can see this is splitting the results of the location and name results in what it is presenting based on the returned ‘=’. We can also see evidence that this is translating entries that simply say ‘Startup’ to the CSIDL ordinal (Folder path) ‘7’ (CSIDL_STARTUP), ‘Common Startup’ to the CSIDL ordinal (Folder path) ‘24’ (CSIDL_COMMON_STARTUP), ‘HKU’ to the full string ‘HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run’, and ‘HKLM’ to the full string ‘HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run’. Note: More information on CSIDL Ordinals The issue with the above approach is that it contains a logic bug. It assumes that every result returned will be that of the current user (HKCU) - HKEY Current User; however, when running this WMI command it will return results from other user SIDs such as ‘.DEFAULT’, ‘S-1-5-18’ (NT AUTHORITY\SYSTEM), and in the case of running as Admin, other users on the system. Because of this the results returned will state the run keys are always that of the current user. Further to this it will also replace the key with the location of the standard ‘Run’ key; https://www.jaiminton.com/reverse-engineering/strrat Page 68 of 124 however, if this was instead a different key such as ‘RunOnce’, it would still resolve as the ‘Run’ key location because of this logic flaw. This demonstrates an oversight by the malware author. From this we can infer that ‘startup-list reload’ is used to show the current startup (autorun) items on this host. delete When ‘delete’ is sent this command will proceed to run an instance of ‘sstydgn.sdfsldf(String)’. This will check what is being passed to it, and where it starts with either HKCU or HKLM it will attempt to delete it from registry using the native ‘reg.exe’ command. Where this doesn’t start with either of these characters the malware will attempt to delete it as if it was a file or folder on the system. This demonstrates another oversight where the malware only has support for deleting startup keys with this for the current user or local machine, and not other user hives. From this we can infer that ‘startup-list delete’ is used to remove either the current user/local machine registry run key, or a file present on the system. add When ‘add’ is sent this command will proceed to run an instance of ‘sstydgn.sdfsldf(String, boolean, boolean)’. This functions as a way to add persistence through both a registry run key, or a file written to either CSIDL_STARTUP or CSIDL_COMMON_STARTUP. https://www.jaiminton.com/reverse-engineering/strrat Page 69 of 124 This uses another method ‘sfsrgsbd.sdfsldf(int, String)’ to perform the registry additions. What’s interesting here is that rather than using ‘reg add’ native commands as was done with the ‘delete’ command, this instead uses methods defined in Java that leverage relevant Windows APIs. https://www.jaiminton.com/reverse-engineering/strrat Page 70 of 124 This difference highlights one of maybe 3 possible scenarios. The malware author intentionally chose to not leverage reg.exe to add in persistence to evade some EDR signatures. The malware author is actually instead malware authors, all of whom focus on a different part of the RAT, or it has been adapted from code “borrowed” or “stolen” over time. The malware author didn’t realise that there was an ‘add’ parameter for reg.exe. Given the code quality inconsistencies I’d say it’s likely this was made by multiple people, or it has been chopped and changed/stolen over time. From this we can infer that ‘startup-list add’ is used to add either an entry to the current user/local machine registry run key, or a file to one of 2 known startup directories on the system. Command Functionality: remote-screen This command primarily functions from within the ‘sabretb(Socket)’ class. https://www.jaiminton.com/reverse-engineering/strrat Page 71 of 124 At a glance we can see that this is importing a lot of classes to do with encryption and drawing pixels to the screen. Note: To get a clean decompilation we’ll be switching to the FernFlower decompiler built into Recaf. Taking a look at the main class executed see 2 familiar thread creations in addition to some input and output stream declarations. This time the thread creations are defined within the classes ‘fgsbsfgsb’ and ‘hghteerd’. https://www.jaiminton.com/reverse-engineering/strrat Page 72 of 124 Class ‘fgsbsfgsb’ will be ensuring ‘sdfsldf(sabretb)’ is run. public final void run() { sabretb.sdfsldf(this.sdfsldf); } Class ‘hghteerd’ will be ensuring ‘sabretb(sabretb)’ is run. public final void run() { sabretb.sabretb(this.sdfsldf); } If we compare these classes we see that ‘sdfsldf(sabretb)’ is expecting a successfully established socket so that it can send bytes which are stored from an instance of sabretb.sdfsldf(BufferedImage). We can also see reference to Remote Desktop in a debug message. https://www.jaiminton.com/reverse-engineering/strrat Page 73 of 124 Examining this method we can see that it looks to be sending a ByteArray Stream of the user’s screen down the socket in the form of a continuous JPG. Now looking at ‘sabretb(sabretb)’ we see that this is looking for events indicating whether a mouse has been moved, key pushed, mouse wheel scrolled, or mouse double clicked. https://www.jaiminton.com/reverse-engineering/strrat Page 74 of 124 These events directly cause events that are directly tied to updating the image being sent down the established socket and sends commands through the java.awt.Robot class that has been imported here. From this we can infer that ‘remote-screen’ is used to spawn a ‘VNC’ or ‘RDP’ type connection to the system and allow control of the mouse and keyboard input. Command Functionality: rev-proxy This command primarily functions from within the ‘ncnndfg(String)’ class. Examining this we can see that this looks to be establishing a new Socket connection to the configured ‘PluginsServerURL’ and ‘PluginsServerPort’ variables. From this we can begin to see this appears to function also as a facilitator for this ‘rev-proxy’ command. https://www.jaiminton.com/reverse-engineering/strrat Page 75 of 124 Some key components with this stem from the definition of ncnndfg3.sdfsldf as a new ‘fgssdg’ object, passing in the ‘ncnndfg’ object itself, before running this object, passing in a socket connection, and the object created (confusing I know). ncnndfg3.sdfsldf = new fgssdg(this); ncnndfg3.sdfsldf((Socket)object, ncnndfg3.sdfsldf); Breaking down the crux of this we need to look at the ‘fgssdg’ class, and we can see stark similarities with the ‘ncnndfg(String)’ class. https://www.jaiminton.com/reverse-engineering/strrat Page 76 of 124 The difference here is that instead of the above mentioned implemenetations this is running ‘ncnndfg.sabretb(ncnndfg, Socket, xbvcxnx)’, and examining this we find yet another invocation, this time of ‘ncnndfg2.sdfsldf(socket)’ Remaining cognizant that this is passing in an established socket and interface ‘xbvcxnx’ which references ‘sdfsldf()’, we finally can see this starts a new thread implementing ‘ngdnbn(ncnndfg, Socket, xbvcxnx)’ which we’re now well and truly familiar with thread runnable objects. Pivoting back to ncnndfg we can now begin to see the main part of this command’s functionality. https://www.jaiminton.com/reverse-engineering/strrat Page 77 of 124 https://www.jaiminton.com/reverse-engineering/strrat Page 78 of 124 Some important parts of this method occurs at lines 104-114 which is involved in receiving a CONNECT network request and sending back a 200 Connection Established message. This is only possible due to an instance of ncnndfg (ncnndfg2) being defined as object3 at line 76. https://www.jaiminton.com/reverse-engineering/strrat Page 79 of 124 Here we also see that when a socket is established a new instance of ‘ghsghnbn’ will be created at line 112 whilst invoking a public method ‘sdfsldf(Socket, Socket)’. Examining what this method entails we can see it is largely around defining 2 socket connections passed in and then creating 2 new threads, one for the object ‘mdgghtdsh’ and the other, ‘ndgdfhfh’. https://www.jaiminton.com/reverse-engineering/strrat Page 80 of 124 Taking a look at what these are used for, both once again are starting a thread using the Runnable class, and one will execute the method ‘sdfsldf(ghsghnbn)’, whilst the other executes ‘sabretb(ghsghnbn)’, both inside of ‘ghsghnbn’. Taking a look closer we can see that both of these are very similar except with some subtle differences. https://www.jaiminton.com/reverse-engineering/strrat Page 81 of 124 In the above we can see that the difference occurs with the input and output streams being used, and these are the exact same streams defined for each socket passed for ‘sdfsldf(Socket, Socket)’ as shown previously. There’s really not a lot of further investigation or code to unravel in this command, and from this we can infer that ‘rev-proxy’ is used to create a ‘reverse proxy’ or socks proxy on the host that would allow accessing an internal service/port on the host by hitting an external domain on the correct port (in this case the plugins server). Command Functionality: hrdp-new This command primarily functions from within the ‘fgfnbnc(String)’ class. We’ve touched on some of the elements of this previously, but now we’ll go into a bit more depth. Decompiling once again using FernFlower we can see that this gets reference to a hrdpinst.exe binary that will be stored within the Jar run path once downloaded, before noting the appropriate browser in use on the system (x86 or x64 version of Firefox or Chrome), and starting a new thread of ‘gmgmgmgm(fgfnbnc)’. Examining this we see ‘sdfsldf(fgfnbnc, String)’ being called which in turn runs ‘cbnfdhn.StatusUpdate(“Initializing HRDP”)’ to update the C2. In addition this will run ‘sdfsldf(fgfnbnc)’ to ensure that HRDP has been downloaded and initialised, and that a new user account has been created that can be used with this tool. https://www.jaiminton.com/reverse-engineering/strrat Page 82 of 124 The specific downloading of this tool is from within ‘ertdbdth()’ that is run within the if statement right before “HRDP Downloaded” is sent back to the C2. This gives us another wshsoft.company IOC which is used to download the binary into the previously mentioned hrdpinst.exe binary, noting the mismatched extension here. Network IOC: hxxp[://]wshsoft[.]company/multrdp[.]jpg We’ve mentioned some of this previously; however we can now see in more depth what is occurring when “hrdp-new” is sent. Of interest is a new instance of an agafhas object being created, and if we investigate this further we see a message being sent to the C2 of “HRDP-SOC” before invoking ‘sdfsldf(fgfnbnc, Socket, dfhdfndfg)’. https://www.jaiminton.com/reverse-engineering/strrat Page 83 of 124 Based on what we’re seeing we can begin to believe that this is acting as a socket to support HRDP, and looking at the invoked method we find it invokes another method ‘sdfsldf(Socket, dfhdfndfg)’ which finally kicks off another thread, this time of class ‘bmcvbmd(fgfnbnc, Socket, dfhdfndfg)’. The above new thread creation is used on yet another class that implements the runnable class and invokes ‘sabretb(fgfnbnc, Socket, dfhdfndfg)’ https://www.jaiminton.com/reverse-engineering/strrat Page 84 of 124 By examining this further we find that this looks to be reading in an inputstream and determining whether it is sending the command “CLONE”, “EXITS”, or “EXIT”. In addition to this we can see if none of these are being sent it will create a socket tunnelling port 3389 (default RDP) to the C2 to allow RDP directly to the system. https://www.jaiminton.com/reverse-engineering/strrat Page 85 of 124 Examining the clone thread we see evidence that this is being used to clone a user’s browser session via the new thread of ‘thrhhrth(fgfnbnc)’ based on an update being sent to the C2, before running an invocation of ‘dfhdfndfg.sdfsldf()’ which is defined within var2. (new Thread(new thrhhrth(var0))).start(); var2.sdfsldf(); Taking a look at ‘fgfnbnc.sabretb(fgfnbnc)’ we can see that this is looking to determine if a file exists which is an object holding the cloned Firefox profile. If this profile exists it will check to see if a Firefox.bat file has been dropped to the created user’s desktop, and if it has it will send a message that Firefox has been cloned. If it hasn’t, it will attempt to get a Firefox profile by running through ‘sbsbgrsg()’, and then from this attempt to clone the user’s Firefox profile by creating a launcher (a batch script, note the misspelling of launcher message also) which runs Firefox but uses the ‘–no-remote - profile’ parameters to specify starting with this found user’s profile. https://www.jaiminton.com/reverse-engineering/strrat Page 86 of 124 If we instead look at the ‘EXITS’ flow, we see that this runs the below: Looking into this we find that it’s all about ‘cleaning up’ and covering tracks from running HRDP. In this instance it seeks to delete the temporary created account and restore visibility of the last logged on username at the logon screen. Looking at the ‘EXIT’ flow, we see that this runs the below: var0.gsbthstgb(var0.UserName); The method takes in a String and then proceeds to load in Kernel32.dll so that it can check within sfsrgsbd() whether this is running on a 64bit OS or not. This is done so that the Wow64DisableWow64FsRedirection windows API function can be called to disable redicrections that occur on 32bit applications running on 64 bit OS’, before logging the user off and re-enabling this. https://www.jaiminton.com/reverse-engineering/strrat Page 87 of 124 Based on this it’s inferred that ‘EXIT’ is used to logoff of the RDP session established. Finally if we examine the method ‘sdfsldf(String)’ within ‘fgfnbnc’, we find that this method is being embedded in checks performed whenever a new ‘net’ command is being run from this malware, with the same occurring in ‘sabretb(String)’. https://www.jaiminton.com/reverse-engineering/strrat Page 88 of 124 What we can see here is that the malware seems to have some sort of checks in place for different “command completed successfully” messages which could be being resolved in the following languages. English Spanish French German Italian This may indicate that the intended targets of this malware or languages spoken of intended victims are that of the above. Regardless, from this we can infer that ‘hrdp-new’ is used to invoke a ‘Hidden’ RDP session which can clone user’s Firefox and Chrome browser sessions. Command Functionality: hrdp-res This command primarily functions from within the ‘fgfnbnc(String)’ class much like the previous command; however the primary difference is that this takes in a variable which acts as the defined username rather than randomly creating a new one after ‘null’ was previously passed in. Not far into the routine a variable var2 is set to the username passed in, and checks are made using net commands to see if the user exists already or not and if it is in the local administrators group. Where it is then all checks are passed and the re-initialisation of HRDP won’t occur, but the session will be allowed to run. From this we can infer that ‘hrdp-res’ is used to restore a ‘Hidden’ RDP session where a user was previously logged off using the ‘EXIT’ command. Command Functionality: chrome-pass This command primarily functions from within the ‘thtyrths()’ class. After creating a new instance of this, it has the output of ‘sdfsldf()’ appended to the message sent to the C2. If we examine this method, it first checks if it is running Windows or not, and if it isn’t a message is displayed saying it is not supported, if it is it will proceed to run ‘sabretb()’. https://www.jaiminton.com/reverse-engineering/strrat Page 89 of 124 If the output of this method is nothing then the message “No passwords Found” will be sent back, if it contains something, that will instead be returned, so let’s investigate ‘sabretb()’. This leverages the JDBC driver SQLite Wrapper to interface with the Google Chrome password SQL database. From here it proceeds to retrieve all columns from the “logins” table and extract their relevant elements. From here STRRAT proceeds to use the DPAPI CryptUnprotectData function to decrypt the user’s stored Google Chrome passwords on this system. In the event that using DPAPI fails to retrieve credentials, STRRAT falls back to running the below. https://www.jaiminton.com/reverse-engineering/strrat Page 90 of 124 Within this function we see a number of operations occurring, but probably one of the best assumptions as to why this occurs is made apparent from the below blog post. Kirby Angell - Decrypting Browser Passwords & Other Secrets As Kirby explains it, the the ‘Local State’ file which is being read in contains the DPAPI encrypted encryption key, and whereas older versions of Chromium (and hence Chrome) used solely the Login Data file and DPAPI, all passwords could be revealed using solely these and the relevant API (CryptUnprotectData), which we saw just before. Nowadays browsers need to first extract the internal key which has been encrypted from within the Local State file, and then calls CryptUnprotectData to decrypt this key. From here the key is then changed to a byte array and is used to create a secret key via AES encryption from this byte array, which is subsequently then used to decrypt the password given. https://www.jaiminton.com/reverse-engineering/strrat Page 91 of 124 From this we can infer that ‘chrome-pass’ is used to decrypt usernames and passwords stored from within the logged on user’s Google Chrome profile. Command Functionality: foxmail-pass This command primarily functions from within the ‘dsgsdfge()’ class, specifically what kicks off from the ‘sdfsldf()’ function. Looking into this further we can see that it is using a registry class ‘Foxmail.url.mailto’, presumably to get the install path of Foxmail. From this it is then looking for the Account.rec0 file stored within aan ‘Accounts’ subdirectory, and this is then being read to decode the Email and Password from within it. The actual decoding occurs from within the class ‘sdfsldf(int, String)’, and we can tell this is encoding as it is performing permutations from fixed characters rather than any type of encryption using a schema such as AES. https://www.jaiminton.com/reverse-engineering/strrat Page 92 of 124 The operations here occur a lot against an array of characters, and although we could go into each entry, it’s sometimes useful to explore OSINT to see if we can infer what is happening. Whilst researching these methods I stumbled across the following foxDecode program on Github which I believe may have been used to heavily influence how this command works. It has been cloned on the off chance it changes over time and can be found below: https://www.jaiminton.com/reverse-engineering/strrat Page 93 of 124 JPMinty FoxDecode Fork Comparing the first statement in this project we can see striking similarities in our decompiled code to that of the C Sharp program above, despite the differences in languages used. Following on from this we see almost a like-for-like identical comparison occurring, with one making comparisons in decimal, whereas the other is checking the decimal hex equivalent value. For this to be a coincidence is highly unlikely, it’s almost certainly that this code has been ripped off and ported to function as part of this Trojan, and it’s not uncommon to have malware authors steal code as a means to an end. https://www.jaiminton.com/reverse-engineering/strrat Page 94 of 124 The plus side to all of this is we have nicely annotated code and can understand what is happening… at this point I can’t not put this here. Examining ‘sdfsldf(int, String)’ and how it applies to the rest of this code we find the following: https://www.jaiminton.com/reverse-engineering/strrat Page 95 of 124 https://www.jaiminton.com/reverse-engineering/strrat Page 96 of 124 Based on this we can infer that ‘foxmail-pass’ is used to retrieve email addresses and decode passwords stored from within the installed Foxmail user profiles using ported C# code which is almost certainly plagiarised from ‘StarZHF’ and ‘Jacob Soo’. Command Functionality: outlook-pass This command primarily functions from within the ‘xncxbc()’ class, specifically what kicks off from the ‘sdfsldf()’ method. Examining this method we can see that it looks to search through some specific registry keys for the current user which are associated with Outlook. In specifics this is searching for any entry which after being converted to lowercase simply contains the key “password”, if this is not found it will continue searching, but if it is found it will add this to an array called ‘object5’. https://www.jaiminton.com/reverse-engineering/strrat Page 97 of 124 Further on from this we find that it will examine any key which contains “IMAP Password”, “POP3 Password”, “HTTP Password”, or “SMTP Password”, and will then pull out the corresponding SMTP Server, Email, and Password (after decrypting using ‘CryptUnprotectData’ which once again uses DPAPI). Based on this we can infer that ‘outlook-pass’ is used to retrieve the SMTP Server, Email, and Password values stored from within the appropriate Outlook registry keys if they exist on the system. Command Functionality: fox-pass This command primarily functions from within the ‘dncbnf(boolean)’ class, this time things are a bit different when creating an instance of this object as it uses variables ‘sabretb’, and ‘sdfsldf’ in determining what is happening when this command is run, it also has an error message to indicate the command will be targeting Firefox. https://www.jaiminton.com/reverse-engineering/strrat Page 98 of 124 Examining this class we find that upon being instantiated it will set a number of variables and run ‘this.bsgshsbs()’. This method looks to have support for both ‘Thunderbird’ and ‘Firefox’ based on examined strings; however, we need to take note that the object is being created with ‘false’ in this instance and as such will have a variable ‘dfhttegd’ set to ‘false’ that plays a key part in determining whether this is looking at Firefox or Thunderbird. In the above we can see that this is specifically looking for a ‘profiles.ini’ file in the user’s roaming directory for Firefox to be used within a new object created from ‘nddfgndt(String)’, and is specifically looking for anything that starts with the string ‘Profile’ in the list of returned objects. The gist of this is that it will be extracting the relevant Firefox profile directory to then search for the files ‘logins.json’, ‘key4.db’, and ‘cert9.db’, prior to running the method ‘sdfsldf(File, File, File)’ over these 3 files. https://www.jaiminton.com/reverse-engineering/strrat Page 99 of 124 The above clears up what this is doing. After locating the above files they will attempt to be compressed into an archive called ‘rpack.zip’ which is sent as a serialized sequence of data. This differs from the previously seen commands in that there are no attempts to decrypt or decode these files to retrieve the credentials in cleartext, but rather is exfiltrating 3 files ‘logins.json’, ‘key4.db’, ‘cert9.db’ in an attempt to clone the user’s Firefox profile. We can see these files are useful in doing so by looking at an answer given by ‘cor-el’ here on a Mozilla Support Forum, replicated below for convenience. Firefox 58+ versions use key4.db for the key file (default salt and master password). Previous Firefox versions used the key3.db file although they can use key4.db (SQLite). Support for SQLite databases (key4.db and cert9.db) exists since 2011. If you copy logins.json and key4.db to the current profile folder then Firefox should be able to find the userna Note the logins.json and key4.db should match. https://www.jaiminton.com/reverse-engineering/strrat Page 100 of 124 Based on this we can infer that ‘fox-pass’ is used to retrieve the user’s ‘logins.json’, ‘key4.db’, and ‘cert9.db’ files from their respective Firefox profile in order to later decrypt these or import these into a Firefox session to steal credentials. Command Functionality: tb-pass This command primarily functions from within the ‘dncbnf(boolean)’ class much like the ‘fox-pass’ command, only this time it is being run with a ‘true’ value rather than a ‘false’ value being passed. The sole difference between this command being run and the ‘fox-pass’ command being run is that this is instead looking for the common ‘Thunderbird’ working directories as opposed to the ‘Firefox’ ones. Examining this post on MozillaZine, a Mozilla documentation website created by the user community, we find this also contains ‘logins.json’, ‘key4.db’, and ‘cert9.db’ which can be used to recover stored passwords. Based on this we can infer that ‘tb-pass’ is used to retrieve the user’s ‘logins.json’, ‘key4.db’, and ‘cert9.db’ files from their respective Thunderbird profile in order to later decrypt these or import these into a Thunderbird session to steal credentials. Command Functionality: ie-pass This command primarily functions from within the ‘dhgdghd()’ class. Examining this class we find that this is actually one of the more simple classes. Upon being instantiated this object will launch a new powershell process and create a new object of type Windows.Security.Credentials.PasswordVault. From here it will run the RetrieveAll method to quite literally retrieve all the credentials stored in the Credential Locker. This will generally bring back hidden passwords; however, a quick pipe to RetrievePassword successfully extracts these credentials. https://www.jaiminton.com/reverse-engineering/strrat Page 101 of 124 Once again if we weren’t sure about this we could do a search and wind up on Github with some code to retrieve credentials from IE & Edge which is identical. # Content: Receive Credentials from IE & Edge # Author: Florian Hansemann | @CyberWarship | https://hansesecure.de # Date: 09/2020 [void][Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime] $vault = New-Object Windows.Security.Credentials.PasswordVault $vault.RetrieveAll() | % { $_.RetrievePassword();$_ } | select username,resource,password Based on this we can infer that ‘ie-pass’ is used to retrieve all the credentials stored in the Credential Locker used by Edge and Internet Explorer…and that malware authors rip code off from others, who’d have thought? Command Functionality: all-pass This command begins to chain a number of the above credential harvesting techniques specifically called out in ‘dhgdghd()’ (IE / Edge), ‘thtyrths()’ (Google Chrome), ‘dsgsdfge()’ (Foxmail), ‘xncxbc()’ (Outlook), before checking if the command passed was ‘save-all-pass’, in the event it was, it will send these to the C2 before further processing occurs. https://www.jaiminton.com/reverse-engineering/strrat Page 102 of 124 From the above we also see that if the command didn’t include ‘save-all-pass’, STRRAT will continue processing ‘dncbnf(boolean)’ to get both Firefox and Thunderbird related files which will be sent to the C2. Based on this we can infer that ‘all-pass’ is used to harvest credentials for IE/Edge, Google Chrome, Foxmail, and Outlook. In the event that ‘save-all-pass’ is being sent instead as the command, this will send all of these to the C2. If not, it will go out and try to retrieve Firefox and Thunderbird files needed to decrypt or import passwords. Command Functionality: save-all-pass This command is actually a part of the ‘all-pass’ command mentioned above and determines if credentials will be sent to the C2 or not. Command Functionality: chk-priv This command functions by simply running cbnfdhn.ssdgsbh() and sending back your privileges as either ‘Admin’ or ‘User’. Just when we thought commands couldn’t be more simple we find this. By examining ssdgsbh() we can see that this is used to try and write a new file to ‘C:\Windows\System32\config\dummy.log’. https://www.jaiminton.com/reverse-engineering/strrat Page 103 of 124 Because the location this file is being written to has a default Access Control List (ACL) which restricts it to Administrators, this command takes a shortcut method of trying to write a dummy file, and if it can’t do it just assumes you’re not an Administrator, cute. Based on this we can infer that ‘chk-priv’ is used to try and write a dummy file to C:\Windows\System32\config\dummy.log as a way to check user privileges. Where it’s successful it will send back ‘Privilege: Admin’, and where it fails it will instead send back ‘Privilege: User’. Command Functionality: req-priv This command primarily functions from the ‘sstydgn()’ method inside of cbnfdhn which if the method returns ‘true’ will cause this process to terminate via System.exit(0). The reason this is occurring can be uncovered easily as we dive into ‘sstydgn()’. Looking at this method we can see that it is attempting to launch PowerShell in order to use the ‘start-process’ commandlet to run STRRAT using ‘-verb runAS’. As this happens STRRAT will be attempting to use PowerShell to launch STRRAT as administrator which will generally function by sending a UAC prompt to the user asking if they want to run this. If the user confirms this or UAC is not enabled then this will return true and kill the current STRRAT process as a new one will have been spawned with Administrator rights. Based on this we can infer that ‘req-priv’ is used to use PowerShell in an attempt to run STRRAT with administrator rights/privileges. Command Functionality: rw-encrypt This command primarily functions from a newly created object of ‘sdfsldf(string)’. https://www.jaiminton.com/reverse-engineering/strrat Page 104 of 124 What’s important here is that the method is passed in an string when it is created that gets assigned to ‘dfhttegd’, this will later be used as a passphrase. There’s also a variable ‘sdfsldf’ which contains the string ‘.crimson’ and is used throughout this command being run. In summary this will take a passed string as a password, and upon being instantiated will locate the user’s Downloads, Documents, and Desktop directory and store this in an array. From here STRRAT will iterate over the array, and if a file exists at that location it will read in the bytes of that file into another array. From this it will use a passphrase stored in ‘dfhttegd’ and proceed to encrypt the bytes of the read in file one by one using AES-128 encryption. The encrypted bytes are then written back to disk at the same location, except with the ‘.crimson’ extension, and the original file is then deleted. https://www.jaiminton.com/reverse-engineering/strrat Page 105 of 124 This highlights the importance of examining malware revisions for changes and citing your sources given a number of companies copy work by other researchers or companies without giving proper credit or performing the analysis themselves. At the time of writing I have identified at least 2 posts publicly which are still stating that this RAT doesn’t implement a ransomware routine and merely changes the extension of files on disk, and from what we can see here, this is simply not the case. The posts go into no technical detail and despite showing version 1.4 and 1.5 of STRRAT in the analysis, it’s mentioned this is a fake ransomware module. From at least version 1.4 this in fact does look to have a fully functioning ransomware routine as shown here, and I strongly believe anyone who thinks otherwise is citing (or not citing) old research without analysing the samples themselves. https://www.jaiminton.com/reverse-engineering/strrat Page 106 of 124 Based on this we can infer that ‘rw-encrypt’ is used as a ransomware module to encrypt the user’s Downloads, Documents, and Desktop directory using AES-128. Command Functionality: rw-decrypt This command primarily functions from a newly created object of ‘sdfsldf(string)’ much like the ‘rw-encrypt’ command, with the difference being that the new thread being created is instead occurring via ‘dfghdmc’. Examining this we can see that this will instead kickoff a method of ‘sabretb’ inside of ‘sdfsldf’. Taking a look into this we find it is much the same as ‘rw-encrypt’, except with a difference being it is using the previously established object in ‘rw-encrypt’ and a passphrase down to decrypt the files of interest by reusing the ‘DecryptConfig’ method which we previously renamed. This method is more broadly used as a decryption method now, both for STRRAT’s configuration file, and also the ransomware decryption module. https://www.jaiminton.com/reverse-engineering/strrat Page 107 of 124 Based on this we can infer that ‘rw-decrypt’ is used as the recovery method for STRRAT’s ransomware module and is used to decrypt the user’s Downloads, Documents, and Desktop directory using AES-128. Command Functionality: show-msg This command works as the message component of the executed ransomware and is very basic in how it works. First off it will get the location of the user’s desktop and create a file called ‘crimson_info.txt’ there. From here it will take a passed string to the command and write it within that file, and finally it will execute notepad to display the contents of this file to the user. This is pretty unusual and bizarre to be honest, given most ransomware variants will encrypt a number of files and do this not only in multiple threads, but with multiple files being dropped and a message which is modular but baked into the ransomware sample. In comparison this seems to just give the functionality to either use this or not depending on what the operator wishes to do. Based on this we can infer that ‘show-msg’ is used to create and display a ransomware (or arbitrary) message to a victim by creating a text file on the user’s desktop and using notepad to open it. https://www.jaiminton.com/reverse-engineering/strrat Page 108 of 124 Command Functionality: screen-on This command kicks off a new thread of object ‘fhjtjtg()’ which has been created. Examining this we find it kicks off the method ‘bsgshsbs()’ from within ‘cbnfdhn’. Examining this we can see that it is used to move the mouse ever so slightly as to keep the computer from falling asleep (prevent screensavers). Based on this we can infer that ‘screen-on’ is used to move the mouse ever so slightly as to keep the screen on and prevent any computer screensaver. Wrapping up flow and functionality: At this point there’s not much we haven’t covered off in this particular piece of malware, we’ve well and truly reversed it and showed how we came to every conclusion along the way. The standard beaconing of STRRAT can be seen under the method ‘sbsgssdfg’ which we glossed over far earlier in this analysis piece. This sends certain information about the host that’s been infected back to the C2 in the form of a ‘ping’, which is actually a web request, and not an ICMP (ping) packet. https://www.jaiminton.com/reverse-engineering/strrat Page 109 of 124 As the cherry on top we can see one last evidence of this retrieving the user’s publicly facing IP address by making a request to ip-api[.]com which is referenced within the method ‘sbsgssdfg()’ and ‘fgssdg()’. Network IOC: ip-api[.]com/json/ Network IOC (User Agen): Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome Part 4: Threat Intelligence and Detection Engineering Detection Engineering Yara Rule To build out a Yara rule we’ll take a look at some of the most common IOCs seen in this malware as analysed above, and select a subset of these in addition to other commands seen embedded into the malware’s functionality: Network IOCs: hxxp[://]wshsoft[.]company/jre7[.]zip hxxps[://]pastebin[.]com/raw/Jdnx8jdg hxxps[://]pastebin[.]com/u/wshsoft pluginserver[.]duckdns[.]org hxxp[://]str-master[.]pw/strigoi/server/ping[.]php?lid= https://www.jaiminton.com/reverse-engineering/strrat Page 110 of 124 moregrace[.]duckdns[.]org hxxp[://]jbfrost[.]live/strigoi/server/?hwid=1&lid=m&ht=5 palaintermine[.]duckdns[.]org ip-api[.]com/json/ hxxp[://]wshsoft[.]company/multrdp[.]jpg Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537. Host IOCs: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\ntfsmgr 64578lock.file 3219lock.file Scheduled Task - "Skype" HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System /v dontdisplaylastusername = 1 STRRAT/Dropper Specific IOCs: carLambo HBrowserNativeApis config.txt loorqhustq Using the above we can create a fairly flexible Yara rule to detect this malware. /* Author: @CyberRaiju Date: 2022-05-19 Identifier: STRRAT-Identification Reference: https://www.jaiminton.com/reverse-engineering/strrat */ rule STRRAT_14 { meta: description = "Detects components or the presence of STRRat used in eCrime operations" license = "Detection Rule License 1.1 https://github.com/Neo23x0/signature-base/blob/master/LICENSE" author = "@CyberRaiju" reference = "https://www.jaiminton.com/reverse-engineering/strrat" date = "2022-05-19" hash1 = "ec48d708eb393d94b995eb7d0194bded701c456c666c7bb967ced016d9f1eff5" hash2 = "0A6D2526077276F4D0141E9B4D94F373CC1AE9D6437A02887BE96A16E2D864CF" strings: $ntwk1 = "wshsoft.company" fullword ascii $ntwk2 = "str-master.pw" fullword ascii $ntwk3 = "jbfrost.live" fullword ascii $ntwk4 = "ip-api.com" fullword ascii https://www.jaiminton.com/reverse-engineering/strrat Page 111 of 124 $ntwk5 = "strigoi" fullword ascii $host1 = "ntfsmgr" fullword ascii $host2 = "Skype" fullword ascii $host3 = "lock.file" fullword ascii $rat1 = "HBrowserNativeApis" fullword ascii $rat2 = "carLambo" fullword ascii $rat3 = "config" fullword ascii $rat4 = "loorqhustq" fullword ascii condition: filesize < 2000KB and (2 of ($ntwk*) or all of ($host*) or 2 of ($rat*)) } Performing a hunt using Hybrid Analysis reveals a number of hits on this malware, making this a useful Yara rule for finding samples. Of course this could be expanded out further, for example by adding checks for the dependencies STRRAT is known to use, but when creating these it’s always a balancing act of being broad enough to net new samples, but not get riddled with False Positives, but not too confined as to miss different variants. Snort Rule To build out a Snort rule we’ll take a look at some of the network traffic described above, specifically zoning in on the beacon STRRAT sends frequently, and look for any tcp traffic to or from a server that contains the content “ping”, a pipe, and then “STRRAT” (this is as simple as converting it to hexadecimal and looking for the content, and giving it a unique sid). This could be expanded further to detect commands being sent to/from the C2; however, this will be a task left for the reader. alert tcp any any -> any any (msg:"STRRAT C2 Beacon Detected"; content:"|70 69 6e 67 7c 53 54 52 52 41 54|"; pr In this example we’re going to use a pcap already captured previously from a system infected with a STRRAT variant provided by Brad Duncan to test the rule. After setting up a few preprocessors for stream5_global, we’re good to test the rule over our pcap. By creating a snort config with the below (stored in a file called strrat.rules). preprocessor stream5_global: track_tcp yes, \ track_udp yes, \ track_icmp no, alert tcp any any -> any any (msg:"STRRAT C2 Beacon Detected"; content:"|70 69 6e 67 7c 53 54 52 52 41 54|"; pri We can easily test this using snort on a linux VM. Specifying the pcap file and testing against our created rule.. sudo snort -A fast --pcap-single=./pcap.pcap -c ./strrat.rules -l /var/log/snort https://www.jaiminton.com/reverse-engineering/strrat Page 112 of 124 We can see this has 73 hits over the pcap, and has generated a number of alerts due to the consistent beaconing this malware presents. Sigma Rule Because STRRAT leverages a lot of native Windows utilities to enable persistence and execute commands, we can develop a fairly basic Sigma rule to detect possible infections of STRRAT. This could be expanded further to pick up on individual registry key creations from a sysmon event, or look at the behaviour of file writes; however, this will be a task left for the reader. This also hasn’t been confirmed for false positives which may need to be excluded. title: STTRAT Child Process Spawning status: experimental description: Detects suspicious child processes of Java(w) possibly associated with a STRRAT infection. author: Jai Minton (@CyberRaiju) references: https://www.jaiminton.com/reverse-engineering/strrat date: 2022/05/28 modified: 2022/05/28 tags: - attack.initial_access - attack.persistence logsource: category: process_creation product: windows level: high detection: selection: - ParentImage|endswith: - '\java.exe' https://www.jaiminton.com/reverse-engineering/strrat Page 113 of 124 - '\javaw.exe' selection_2: - Image|endswith: - '\hrdpinst.exe' - '\cmd.exe' selection_cmd: CommandLine|contains: - 'schtasks /create /sc minute /mo 30 /tn Skype' - 'reg add' - 'shutdown /r /t 0' - 'shutdown /s /t 0' - 'wmic /node:. /namespace:' - 'hrdpinst.exe' condition: selection and selection_2 and selection_cmd falsepositives: - Legitimate calls of various java applications to system binaries with specific command lines level: high Useful Windows Event Logs The following event log identifiers will be useful to track this piece of malware: Microsoft-Windows-TaskScheduler/Operational 201 (Task registered) 129 (Task Launched) Security 4688 (Process Creation) 4698 (Scheduled Task Creation) 4700 (Scheduled Task Enabled) Sysmon 1 (Process Creation) 11 (FileCreate) 12 (Registry Create and Delete) 13 (Registry Value Set) 22 (DNS Query) Threat Intelligence - The Crimson Shadow Note: Threat intelligence is a broad term here which has been used to cover getting extended telemetry on the threat this particular malware poses to organisations and people around the world, and potential victims. https://www.jaiminton.com/reverse-engineering/strrat Page 114 of 124 During analysis I was presented with an interesting opportunity to track this malware on a global scale due to the way it functions. In late 2021, over the course of a month, infections of STRRAT around the world were tracked and plotted on a map based on the infected client’s IP address and Maxmind’s GeoLite2 Free Database. This clustered data is shown below. By overlaying a heat map here we can see that although the numbers aren’t massive, the number of locations globally which had seen this malware execute were quite diverse. Further, each cluser point represents a single IP, and doesn’t take into consideration the number of hits from that particular IP. To allow this to be easily navigated I overlayed IP address information along with ASN and count. https://www.jaiminton.com/reverse-engineering/strrat Page 115 of 124 The method to turn the gathered data into such a map was to take a carefully crafted spreadsheet containing the data and plot it with Python3, pandas, and folium. The script created is show below (special thanks to umar-yusuf’s blog which helped get me started on this venture). import pandas as pd from IPython.display import display import folium from folium import plugins from folium.plugins import HeatMap import branca.colormap from collections import defaultdict import sys import time steps=5 colormap = branca.colormap.linear.YlOrRd_09.scale(0, 2).to_step(steps) gradient_map=defaultdict(dict) for i in range(steps): gradient_map[1/steps*i] = colormap.rgb_hex_str(1/steps*i) lon, lat = 10.626065, 43.035950 for ii in range(1,33): https://www.jaiminton.com/reverse-engineering/strrat Page 116 of 124 m = folium.Map([lat, lon],tiles='cartodbdark_matter', zoom_start=2) sheet='Day'+str(ii); heatmap_df = pd.read_excel(open('MapDataDaily.xls','rb'),sheet_name=sheet) count=sheet+" ("+str(len(heatmap_df))+")" title_html = '''