Before we analyze this RAT in-depth, we will show an overview of its behavior as a diagram. This can help to understand its inner working at a more high-level view:
To analyze this sample, we will open it with dnSpy to decompile and possibly debug it.
We will first begin at the entry point of this RAT and analyze its executed code before we jump into all possible modules this RAT possesses. To jump to the entry point we can right-click on the class menu on the left and select Go to Entry Point:
Doing so will lead us to the first called function called uLnqUtvIwAOVXLU. To make things more understandable we have pasted it below. It starts by sleeping for 2 seconds before calling hlIinikmNYFRC.gwgzcfkYmyQKIgW(). If this function returns False, then the RAT exists, which means that this function is probably going to do some environment checks. Let’s start by examining what the RAT is checking.
The content of the function can be seen below. The RAT is trying to create a new Mutex. The name of the Mutex can be found in the variable hlIinikmNYFRC.HREdkIUrRAzFBOcfZ and is 2e3fb6d0. This makes a great IOC.
If the Mutex is already created, the result will be False, but if the Creation of The Mutex is successful, the result will be True. In conclusion the entry point is checking if the Mutex already exists, i.e. if the system was already infected with this RAT.
If the Mutex check is passed, the RAT will call hlIinikmNYFRC.ATCCkfeyJnyt() and pass an enum. This is just a wrapper to call SetThreadExecutionState. According to the Microsoft docs this function is doing the following:
“Enables an application to inform the system that it is in use, thereby preventing the system from entering sleep or turning off the display while the application is running.”
Lastly, the entry point starts a new thread and passes control to hlIinikmNYFRC.fqLxpecOTiCgE
This function starts with an infinite loop and is basically responsible for getting the commands and interpreting them. If the connection is not setup or is disconnected it will be reset. Here we also learn the C2 address used by this RAT:
At this point, there is an interesting observation. If the connection to the C2 fails, a secondary C2 address will be used. However, this fallback address is the same as the primary one. So, either the author of the malware forgot to change the failback address or this version of the RAT is just some alpha/beta version.
We will not analyze the socket handling in-depth here but instead take a further look at all the information the RAT sends to its operator and the function that handles the received commands.
If the RAT is creating a new connection or reconnecting it sends some general information about the host to its C2. We will not go through each function line by line but rather summarize what information is collected and sent back:
- User Domain Name
- Processor count
- OS full name
- Is user admin?
- Version of the RAT (the analyzed RAT has the version v0.3.8)
- List of installed antivirus products using a WMI query
- Last write time of RAT on disk
- Path of the RAT on disk
Before we explain all available modules, we will first look at the preprocessing of the received data.
Before any module is executed, a further function is called, and the input is split. The function GYZswDqNcBskynCV() is responsible for sending the string “received” to its C2 and to sleep for 1 second. Next, we split the input by a hardcoded delimiter that is “|NW|”. The first value in this list is the key or rather the module that should be run. All further data will be used as parameters for the chosen module. We will now explain all modules in-depth.
This module is further divided into multiple options. The RAT can execute binaries directly in-memory or first write the data to disk and execute it from there. If the passed file was a PowerShell script, the typical arguments are used. Lastly, if array is true, then the RAT will delete itself.
This module is pretty similar to the previous one, except that the operator passes an URL, and the RAT downloads the file itself and executes it.
Here the operator can load further plugins into this .NET binary and hence extend the functionality.
This module does what the name suggests. It closes the Mutex and the TcpClient and then exits.
Calling this module also first closes the Mutex and TcpClient and then creates a batch file in the %temp% directory.
After the batch file has been started the program kills itself.
This module deletes the RAT and closes the Mutex and TcpClient.
Executes the provided ps1 File.
Here the content of a passed URL is downloaded. However, it appears nothing happens if the request was successful.
To verify that this is not just some bugged decompilation, I checked my results with ILSpy. The result is more or less the same. Either this method is not finished or it is just used to verify that there is a connection (maybe for sandbox testing?).
This function does what it says, it kills a lot of stuff.
First, it iterates over all processes and applies some checks to the name of the process. If the FileName attribute of the process satisfies one of the below checks and the window of the process is not visible, then the next block is entered:
- the path contains “wscript.exe”
- the path contains the User Profile Path (i.e. C:\Users\<USER>)
- the path contains the Common Application Data Path (i.e. C:\ProgramData).
Now, if these checks are true, then the process is killed, the program is deleted and the program is removed from the Run and RunOnce registry key located at the following paths:
After the iteration through all processes, the RAT sends the number of killed processes to its C2.
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36
You can find a complete Yara rule here -> SECUINFRA Falcon Team Git