Just another analysis of the njRAT malware – A step-by-step approach

Summary

njRAT (Bladabindi) is a .NET RAT (Remote Access Trojan) that allows attackers to take control of an infected machine. This malware has been used by APT actors in targeted attacks in Colombia (https://www.welivesecurity.com/2021/01/12/operation-spalax-targeted-malware-attacks-colombia/), by SideCopy (https://blog.talosintelligence.com/2021/07/sidecopy.html) and has been distributed via phishing emails (https://labs.k7computing.com/index.php/malspam-campaigns-download-njrat-from-paste-sites/). The version number in our analysis is 0.6.4 and the campaign ID is “splitgateukrayna”. The following commands have been implemented: “proc”, “rss”, “rs”, “rsc”, “kl”, “inf”, “prof”, “rn”, “inv”, “ret”, “CAP”, “P”, “un”, “up”, “RG”. njRAT can also act as a keylogger because it records the pressed keys in a file which can be exfiltrated using the “kl” command. The rest of the commands will be explained in great detail in the Technical analysis section.

Analyst: @GeeksCyber

Technical analysis

Disclaimer: We’re aware that there are some njRAT builders available that can be used to generate executables however, we’re not interested in these tools, and we’ve performed the analysis with zero knowledge from those.

SHA256: 833f86074592648c0a758098e34ab605a2b922d94dbab7141e2ce87acec03c35

The analysis has been performed using dnSpy.

The malware tries to open a mutex called “49e91d08e684b1770e0cefa60401157a” using the OpenExisting method. If the mutex already exists, the process exits:

Figure 1

A new mutex named “49e91d08e684b1770e0cefa60401157a” is created by calling the Mutex constructor:

Figure 2

The path for the executable file that started the application is compared with “%AppData%\services64.exe”. The malware authors implemented a function called “CompDir”, which compares the name of the files and the name of the directories:

Figure 3
Figure 4

If the above file exists (“services64.exe”), it’s deleted using the Delete function:

Figure 5

The initial executable file is copied to “%AppData%\services64.exe”. The new file is executed using the Start method, and the current process exits:

Figure 6

The binary sets the environment variable “SEE_MASK_NOZONECHECKS” to 1, which removes the open file security warnings:

Figure 7

A new program-based exception is added to Windows Firewall using netsh (the program being the newly created executable):

Figure 8

A new entry called “49e91d08e684b1770e0cefa60401157a” is added to the Run registry key. This represents a persistence mechanism, and the malware will run whenever the current user logs on:

Figure 9
Figure 10

There is a 2nd persistence mechanism that is not enabled in the malware. It would copy the executable to the Startup folder, as shown below:

Figure 11

The RAT initializes a new instance of the Thread class by specifying the ThreadStart method:

Figure 12

A new TcpClient object is created by the executable. The malware establishes a connection to the C2 server 44gang44.duckdns[.]org (dynamic DNS service) on port 2222:

Figure 13

The volume serial number for the C drive is extracted using the GetVolumeInformation API:

Figure 14

The file retrieves the computer name and user name using the GetComputerName and GetUserName functions:

Figure 15
Figure 16

The last write time of the executable is obtained from the LastWriteTime property, as highlighted in figure 17:

Figure 17

The full operating system name is retrieved from the OSFullName property:

Figure 18

njRAT determines the architecture of the system by checking the existence of the “Program Files (x86)” directory (it only exists on 64-bit systems):

Figure 19

The capGetDriverDescriptionA API is utilized to check for the existence of a Webcam:

Figure 20

GetForegroundWindow is used to get a handle to the foreground window (the window with which the user is currently working). The GetWindowText function copies the text of the foreground window’s title bar into a buffer. GetWindowThreadProcessId is used to retrieve the thread’s identifier that created the foreground window, along with the process’ identifier that created the window. The result of the function is represented by the MainWindowTitle property of the process extracted before, which is Base64 encoded:

Figure 21

The malware creates the “HKEY_CURRENT_USER\Software\49e91d08e684b1770e0cefa60401157a” registry key:

Figure 22

The buffer that contains the following information is sent to the C2 server:

  • Base64 of Campaign ID + volume serial number
  • Computer name
  • User name
  • Last write time of the malicious file
  • Operating system name + system’s architecture
  • Whether a Webcam is detected
  • njRAT Version
  • Base64 of the main window title of the process
Figure 23

The C2 response is copied into a buffer using the Receive method:

Figure 24

The C2 server was emulated using FakeNet. The binary expects a response that contains instructions separated by the “|’|’|” separator. Multiple commands are implemented by njRAT, as we’ll describe later on:

Figure 25

Keylogger functionalities

Every pressed key is compared with multiple function/special keys:

Figure 26

If the keys aren’t function/special keys, they’re mapped from virtual-key code into a scan code or character value by calling the MapVirtualKey function. GetKeyboardLayout is utilized to retrieve the active input locale identifier. The ToUnicodeEx API is utilized to translate the virtual-key code and keyboard state to the corresponding Unicode character:

Figure 27

The GetAsyncKeyState API is utilized to determine whether a key is up or down:

Figure 28

The window title of the process where the input is detected is also included in the logs file:

Figure 29

The binary creates a file called “services64.exe.tmp” in the same directory, where the keylogger data is stored. The WriteAllText method is utilized to populate the file:

Figure 30

An example of a log file is displayed in figure 31:

Figure 31

Now we describe the commands implemented by njRAT.

“proc” command

Case 1 – “proc|’|’|~” (OK.Y == |’|’|) – retrieve information about the current process and the other running processes

The current process ID is retrieved and sent to the C2 server by calling the GetCurrentProcess function. The number of processes running on the host is also transmitted to the C2 server:

Figure 32

The malware extracts the description of the files using the FileVersionInfo.FileDescription property, and then encodes it using the Base64 algorithm. For each process, a string that contains the process ID, the full path to the process, and the encoded file description (if available), is constructed:

Figure 33

In the case of Windows processes, the execution flow is different however, the scope is the same:

Figure 34

The buffer that contains the concatenation of the strings computed above is exfiltrated to the C2 server:

Figure 35

Case 2 – “proc|’|’|k|’|’|<Process ID>” – kill a process

The process that corresponds to the process ID transmitted by the C2 server is stopped by calling the Kill method. If successful, the malware sends a custom message to the server, otherwise it sends an exception message:

Figure 36

Case 3 – “proc|’|’|kd|’|’|<Process ID>” – kill a list of processes and delete the module files

Firstly, the binary repeats the same procedure from above. It also extracts the full path to the process:

Figure 37

The RAT tries to delete the file that corresponds to the above process. If successful, it sends a confirmation message to the C2 server:

Figure 38

Case 4 – “proc|’|’|re|’|’|<Process ID>” – restart a process

The binary repeats the same procedure from above. It also extracts the full path to the process:

Figure 39

njRAT executes the file extracted above. If successful, it sends a confirmation message to the C2 server:

Figure 40

“rss” command – start a hidden command prompt and redirect the StandardOutput and StandardError to the C2 server

The malware creates a “cmd.exe” process object and sets to true multiple values that indicate the following: the error output should be written to StandardError, the input should be read from StandardInput, and the output should be written to StandardOutput. The method that will handle the OutputDataReceived and ErrorDataReceived events of the newly created process is set to a function called “RS”. The method that will handle the Process.Exited events is set to a function called “ex”. The new process is started, and it begins read operations on the redirected StandardOutput and StandardError streams of the application:

Figure 41

The RAT retrieves a late-bound value called “Data”, which represents the StandardError/StandardOutput of the cmd.exe process that is Base64 encoded and sent to the C2 server:

Figure 42

The output of the cmd.exe process can be seen in the network traffic:

Figure 43

Figure 44 displays the cmd.exe process as the child of the initial process (Process Hacker tool):

Figure 44

In the case of a Process.Exited event, the “ex” function just sends the string “rsc” to the C2:

Figure 45

“rs|’|’|<Base64 command>” command – send a command to be executed by the hidden command prompt

The C2 server can specify a command that is decoded using the Base64 algorithm, which is given as input to the cmd.exe process created earlier:

Figure 46

It’s important to mention that the malware performs sanity checks and sends an exception message to the C2 if any error occurs in any case:

Figure 47

“rsc” command – kill the hidden command prompt created earlier

The command prompt process created earlier is killed by the RAT:

Figure 48

“kl” command – exfiltrate the keylogger’s log file

The content of the Logs variable, which is the output of the keylogger described above, is Base64 encoded and exfiltrated to the C2 server:

Figure 49

“inf” command – retrieve information about the volume serial number and malware configuration (C2 server, process name, etc.)

The file checks the “HKCU\Software\49e91d08e684b1770e0cefa60401157a\vn” registry value, which doesn’t exist at this time. The binary extracts again the volume serial number for the C drive and combines it with the following information: C2 server, C2 port number, the AppData folder, the name of the executable, and the process name. The resulting string is transmitted to the C2:

Figure 50

“prof” command

Case 1 – “prof|’|’|~|’|’|<RegistryValue>|’|’|<Data>” – create a registry value in a specific registry key

The malware creates a value under “HKEY_CURRENT_USER\Software\49e91d08e684b1770e0cefa60401157a” and writes some data to it:

Figure 51

Case 2 – “prof|’|’|!|’|’|<RegistryValue>|’|’|<Data>”- create a registry value in a specific registry key and retrieve the “!” registry value

The binary repeats the same operation from above:

Figure 52

The RAT is looking to extract a value called “!” from the same registry key. The value’s content is sent to the C2 server:

Figure 53
Figure 54

Case 3 – “prof|’|’|@|’|’|<RegistryValue>” – delete a registry value from a specific registry key

njRAT deletes the specified value from the same registry key, as highlighted in figure 55:

Figure 55

“rn” command

Case 1 – “rn|’|’|<Extension>|’|’|<URL>” – download and run a file from the URL

The executable downloads the resource specified by the URL and stores the result as a Byte array by calling the DownloadData method:

Figure 56

The array computed above will be stored in a file that is created in the TEMP directory. The file name is randomly generated and consists of 10 lowercase letters:

Figure 57
Figure 58

The new file is executed by calling the Start function, and a confirmation message is transmitted to the C2:

Figure 59

Case 2 – “rn|’|’|<Extension>|’|’|<Base64 (Gzip compressed executable)>” – decode, decompress, and execute the executable

The file decodes the Base64 encoded content and then decompresses it using the ZIP function (depending on the flag, this function could also be used to Gzip compress content):

Figure 60
Figure 61

As in the first case, the content will be written to a file in the TEMP directory, and a confirmation message is sent to the C2 server.

“inv|’|’|<RegistryValue>|’|’|<String1>|’|’|<String2>” command – njRAT has plugins that can be downloaded, saved in registry keys, and then executed

The RAT checks the existence of the RegistryValue value under “HKCU\Software\49e91d08e684b1770e0cefa60401157a”:

Figure 62

Whether the above value doesn’t exist and array[3] has a length of 1, the malware sends a message to the C2 and finishes the command:

Figure 63

Whether the above value exists, its content is decoded using Base64, and a different message is forwarded to the C2 server:

Figure 64

From our analysis, this file is supposed to be a plugin of njRAT. The assembly is loaded via a function call to Assembly.Load and all the modules that are part of it are extracted using the GetModules method. The binary extracts the types defined in each module and expects some of them to have a name that ends with “.A” (a class called “A” should be defined). For each of these types found, the process creates an instance of it using the system activator:

Figure 65
Figure 66

The binary calls the LateSet method multiple times in order to execute multiple late-bound field write calls. Basically, variables such as “h”, “p”, “osk”, “off” are set to OK.H (C2 domain), OK.P (C2 port number), array[2] (this is provided by the C2) and “true”. The malware calls the plugin’s function called “start”:

Figure 67

Whether the registry value mentioned above doesn’t exist and array[3] has a length greater than 1, array[3] is Base64 decoded, and then Gzip decompressed:

Figure 68

The RegistryValue value is created under “HKEY_CURRENT_USER\Software\49e91d08e684b1770e0cefa60401157a”. The content from above that was decompressed is encoded using Base64 and stored in this value:

Figure 69

The same steps starting with loading the assembly (above figure 65) are executed one more time.

“ret|’|’|<RegistryValue>|’|’|<String>” command – similar to the “inv” command, this command can be used to execute a malicious assembly found in a registry key or transmitted by the C2 server

The process checks the existence of the RegistryValue value under “HKCU\Software\49e91d08e684b1770e0cefa60401157a”:

Figure 70

Whether the above value doesn’t exist and array[2] has a length of 1, the malware sends a message to the C2 and finishes the command:

Figure 71

Whether the above value exists, its content is decoded using Base64, and a different message is forwarded to the C2 server:

Figure 72

The same execution flow as above figure 65 is followed (starting with Assembly.Load etc.). A variable called “GT” is retrieved by calling the LateGet method; it is encoded using the Base64 algorithm and exfiltrated to the C2 server:

Figure 73

Whether the registry value mentioned above doesn’t exist and array[2] has a length greater than 1, array[2] is Base64 decoded, and then Gzip decompressed:

Figure 74

The RegistryValue value is created under “HKEY_CURRENT_USER\Software\49e91d08e684b1770e0cefa60401157a”. The content from above that was decompressed is encoded using Base64 and stored in this value:

Figure 75

The same steps starting with loading the assembly (above figure 65) are executed again.

“CAP|’|’|<Width>|’|’|<Height>” command – take screenshots

The RAT creates a new Bitmap object used to create a new Graphics object by calling the Graphics.FromImage function. The CopyFromScreen method is utilized to perform a bit-block transfer of color data from the screen to the Graphics object:

Figure 76

The binary initializes a new instance of the Rectangle class with a specific position and size and then draws the cursor on the Graphics object within the bounds:

Figure 77

This command is used to take screenshots. GetThumbnailImage is utilized to obtain a thumbnail for the bitmap image, which is saved in the jpeg format using the Image.Save function. The malware computes the MD5 hash of the image:

Figure 78
Figure 79

The JFIF file is exfiltrated to the C2 server byte-by-byte:

Figure 80

“P” command – “Ping”

The process just sends the “P” letter to the C2:

Figure 81

“un” command

Case 1 – “un|’|’|~” – completely uninstall the RAT

The NtSetInformationProcess API is used to set the process as “normal” (it can be killed without crashing the OS and resulting in a BSOD, 0x1d = 29 = BreakOnTermination). The binary deletes the value created for persistence at “HKCU\Software\Microsoft\Windows\CurrentVersion\Run\49e91d08e684b1770e0cefa60401157a”:

Figure 82
Figure 83

njRAT deletes the configured program exception from Windows Firewall. The “HKCU\Software\49e91d08e684b1770e0cefa60401157a” registry key is deleted, and the initial executable file is deleted as well:

Figure 84

Case 2 – “un|’|’|!” – kill the current process

The malicious process repeats the NtSetInformationProcess API call from above and exits:

Figure 85

Case 3 – “un|’|’|@” – restart the current process

The binary repeats the NtSetInformationProcess API call from above and spawns the initial executable:

Figure 86

“up” command

Case 1 – “up|’|’|<URL>” – similar to the “rn” command, it’s used to update the RAT

DownloadData is utilized to download an executable from a URL specified by the C2 server:

Figure 87

The malicious process creates a registry value at “HKCU\di” and saves the downloaded content in a randomly generated file name located in the TEMP directory:

Figure 88

The malware sends a message to the C2 server regarding the update confirmation. The newly created executable is run with the “UP:” parameter that contains the current process ID. When the “HKCU\di” value is equal to “!”, then the malware executes the uninstall operation:

Figure 89

Case 2 – “up|’|’|<Base64 (Gzip compressed executable)>” – similar to the “rn” command, it’s used to update the RAT

The RAT decodes the Base64 encoded content and then decompresses it using the ZIP function:

Figure 90

The execution flow that starts with creating the “HKCU\di” key is followed one more time.

“RG” command

Case 1 – “RG|’|’|~|’|’|<RegistryKey>” – enumerate the registry key

The process opens the specified registry key using the GetKey function:

Figure 91
Figure 92

The executable constructs a string based on the registry key from above, which will be exfiltrated later on:

Figure 93

The GetSubKeyNames and GetValueNames methods are used to retrieve an array of strings that contains the subkey names and the value names associated with the key. The concatenation of the arrays is transmitted to the C2:

Figure 94

Case 2 – “RG|’|’|!|’|’|<RegistryKey>|’|’|<RegistryValue>|’|’|<Data>|’|’|<Type>” – create and set a registry value

The SetValue function is utilized to create a value under the specified registry key, which contains data provided above:

Figure 95

Case 3 – “RG|’|’|@|’|’|<RegistryKey>|’|’|<RegistryValue>” – delete a registry value

The DeleteValue method is used to delete the specified value from the registry key:

Figure 96

Case 4 – “RG|’|’|#|’|’|<RegistryKey>|’|’|<SubKey>” – create a sub key

CreateSubKey is used to create a new subkey, as shown in figure 97:

Figure 97

Case 5 – “RG|’|’|$|’|’|<RegistryKey>|’|’|<SubKey>” – delete a sub key and any child sub keys recursively

DeleteSubKeyTree is utilized to delete the subkey and any child subkeys recursively:

Figure 98

References

MSDN: https://docs.microsoft.com/en-us/dotnet/api/, https://docs.microsoft.com/en-us/windows/win32/api/

dnSpy: https://github.com/dnSpy/dnSpy

Fakenet: https://github.com/fireeye/flare-fakenet-ng

VirusTotal: https://www.virustotal.com/gui/file/833f86074592648c0a758098e34ab605a2b922d94dbab7141e2ce87acec03c35

Any.run: https://app.any.run/tasks/78913e0b-1419-4571-8611-ac3372ffd578/

ESET: https://www.welivesecurity.com/2021/01/12/operation-spalax-targeted-malware-attacks-colombia/

Talos: https://blog.talosintelligence.com/2021/07/sidecopy.html

K7Computing: https://labs.k7computing.com/index.php/malspam-campaigns-download-njrat-from-paste-sites/

INDICATORS OF COMPROMISE

C2 domain: 44gang44.duckdns[.]org:2222

SHA256: 833f86074592648c0a758098e34ab605a2b922d94dbab7141e2ce87acec03c35

Registry keys and values:

  • HKCU\Software\49e91d08e684b1770e0cefa60401157a
  • HKCU\Software\Microsoft\Windows\CurrentVersion\Run\49e91d08e684b1770e0cefa60401157a
  • HKCU\di

Files:

  • C:\Users\<User>\AppData\Roaming\services64.exe
  • C:\Users\<User>\AppData\Roaming\services64.exe.tmp

Mutex: 49e91d08e684b1770e0cefa60401157a