<—— Go back

Reverse Engineering njRAT

by

njRAT, also known as Bladabindi, is a Remote Access Trojan (RAT) which allows the adversary to control the end-user’s computer. It was first found in June 2013 with some variants traced to November 2012. It was made by a hacking organization from different countries called M38dHhM and was often used against targets in the Middle East.

Initial Recon & Metadata

First, I check the executable details using file command (ex. 1)

Results of the file command
(ex. 1 – Results of the file command)

We can see that it is PE32 (Windows) executable and a .NET assembly so we can later decompile it back into C# code.

The analysis will be performed on a sample with the following MD5 hash (8d84f5becf22d3bceb322273fa2ac133) which we can confirm using md5sum command (ex. 2).

(ex. 2 - md5sum confirms the sample's integrity)
(ex. 2 – md5sum confirms the sample’s integrity)

I also looked up the hash on VirusTotal (ex. 3). It is pretty widely recognized by most of the vendors already.

(ex. 3 - VirusTotal result)
(ex. 3 – VirusTotal result)

Next step is running strings utility so we are able to scan through the binary file and extract sequences of ASCII characters that meet certain threshold of character length. For easier analysis I redirected the output to a text file.

strings njRAT_sample.exe > njRAT_strings.txt

First thing that I noticed is „System.Net.Sockets” which is a namespace in the .NET API (ex. 4)

(ex. 4 - System.Net.Sockets inside strings output)
(ex. 4 – System.Net.Sockets inside strings output)

We can also see TcpClient class that is part of the namespace. There are also other similar methods/classess e.g.

  • IPEndPoint
  • Socket
  • SendTo
  • Receive
  • Poll

That’s a hint that the malware connects to some entity which is probably just a C2 server.

The following API elements indicate typical RAT behaviour:

1. Registry Manipulation, likely used for persistance eg. Disabling security or implementing run on startup.

  • DeleteValue – Deletes a registry key value
  • GetValue – Reads a registry value
  • SetValue – Writes to a registry key
  • OpenSubKey – Opens a registry key

2. Keylogging Capabilities

  • GetAsyncKeyState
  • GetKeyboardLayout
  • GetKeyboardState
  • MapVirtualKey

3. Screen Capture / Webcam spying

  • CopyFromScreen – Captures screenshots
  • Avicap32.dll – dynamic library used to facilitate webcam capture

4. File and Data Exfiltration

  • System.IO.FileStream – Class that enables reading/writing to and from a file
  • DownloadFile
  • DownloadData

5. Compression and Obfuscation

  • System.IO.Compression Likely used for compressing or obfuscation data
  • FromBase64String Suggests encoded payloads or configuration data

There are a lot more of these but I think its time to dive deeper into the static analysis. This is a .NET assembly so I will use ILSpy tool on linux and dnSpy on Windows to decompile the sample.

Configuration, flags, dynamic runtime variables

(ex. 5 - Configuration hardcoded into the source code)
(ex. 5 – Configuration hardcoded into the source code)

Right away it can be seen that obfuscation in case of this njRAT is not the priority. The configuration is mainly hardcoded. Here is some information that can be extracted. I will also mention a few variables that are used in the flow and their function.

CONFIGURATION

Note: The IP address has not been altered, and interacting with it may have unintended consequences.

NameDefault ValuePurpose
HH43.255.241.232This is the actual C2 address that is used for communication
P5555Port used for communication with the C2 server
EXENotepad.exeDefault value for a name – it is re-evaluated later in the flow based on the actual file name
sfSoftware\\Microsoft\\Windows\\CurrentVersion\\RunPersistence mechanism – it is used to add the malware to autorun procedure
RGf7c5ecd48555dff5f89453188d5fb470This value is a unique identifier of the malware used for mutex check (to verify if it is already running) and persistence mechanism (to add it to registry)
VNV2FyWnYxA base64 encoded string – translates to „WarZv1”. Likely a botnet name
VRim523Version
Y|’|’|Separator

FLAGS

FlagDefault ValuePurpose
taskFalseSelf-protection mechanism (e.g., process monitoring)
usbFalseUSB spreading
anti2False        Security tool termination (taskkill /F /IM …)
HDTrueHides the executable
IdrTrue        Ensures it runs from the correct directory (relocates if necessary).
IsFTrueStartup folder persistence is enabled.
IsuTrueRegistry persistence is enabled.
BDTruecontrols whether the malware enables or disables termination protection during system shutdown/logoff.
udpUsed to flag if udp attack is currently performed
CnFalseFlags C2 connection status

DYNAMIC RUNTIME VARIABLES

NameDefault ValuePurpose
antiExsample.exeThis value is used for evasion – can be set to any particular value to kill security tools
TIPTarget IP used in DoS attacks
TportTarget port
delaydelay used for rate limiting the udp packets in DoS attacks
CPart of System.Net.Sockets. TcpClient class used to define the host
DR„TEMP”default value for executable directory location

Establishing C2 communication

Establishing connection to the C2 is done through connect() function. Lets go through it step-by-step.

Step 1: Checking the existing status

(ex. 6)
(ex. 6)

The function marks the malware as disconnected initially by setting OK.Cn flag to False. It then waits 2 seconds before attempting to reconnect. (ex. 6)

In the first try block it checks if OK.C – (TcpClient) is active, if yes it cleans it up before making a new connection.

Step 2: Establishing TCP connection

Below the TcpClient object is created. It also configures buffer sizes (200KB) and timeouts (10 seconds) (ex. 7).

(ex. 7 - TcpClient configuration)
(ex. 7 – TcpClient configuration)

This code (ex. 8) establishes a connection to the C2 server using the IP address stored in OK.HH and the port stored in OK.P. The NewLateBinding.LateCall method is a VB.NET dynamic invocation technique, allowing the malware to call the Connect method at runtime without direct binding.

(ex. 8)
(ex. 8)

Step 3: Sending initial data

The Ok.Cn flag is set to true which means there is an existing connection and OK.Send sends initial information about the target that are gathered by OK.Inf function. (ex. 9)

(ex. 9)
(ex. 9)

Last thing before returning is gathering and sending data about the flags. These flags indicate what has been done and what is the configuration on this particular malware. Flags are predefined and hardcoded so the malware will know which actions to take, even without initial C2 connection. (ex. 10)

(ex. 10)
(ex. 10)

The above data includes:

  • Hostname and Port (OK.H, OK,P)
  • Directory information (OK.DR)
  • Executable name (OK.EXE)
  • All the flags that show the malware initial actions and configuration

All of the information is encoded by OK.ENB and sent to the C2 server.

Sending data to C2

The data is being sent via Sendb() function (ex. 11).

(ex. 11)
(ex. 11)

Not to overanalyse I’ll focus on the core of this function (ex. 12). First the data is formatted. MemoryStream is used as a temporary buffer to hold length and the data itself. OK.SB encodes the data to UTF-8.

(ex. 12)
(ex. 12)

The actual data transmission occurs using the method below (ex. 13).

(ex. 13)
(ex. 13)

OK.C is the TcpClient that must be already connected to the C2 server. OK.C.Client.Send will result in sending the data to the connected entity. memoryStream.ToArray() is the data itself in a byte array format.

How does njRAT listen for commands?

Listening for C2 network traffic is a core functionality of any RAT. How does njRAT achieve that? Lets look at the RC() function (ex. 14).

(ex. 14)
(ex. 14)

Everything is running in for(;;) loop indefinetely. flag is the result of existing TcpClient connection. If it isn’t true, the RC funtion won’t do anything.

num = -1L; is for tracking expected lengths of incoming data

num2 = counter to ensure the CPU is not consuming too much resources. It is iterated every loop. We can see that every 10 loops it delays the next round of looping (ex. 15).

(ex. 15 - guardrails for resourse usage)
(ex. 15 – guardrails for resourse usage)

Next, RC ensures that there is data to read with .Available, if not – it calls Poll() to wait for it (ex. 16).

(ex. 16 - checking for data availability)
(ex. 16 – checking for data availability)

Below, the data is received and processed byte by byte using the switch statement (ex. 17).

(ex. 17 - switch statement)
(ex. 17 – switch statement)
CodeByte received – meaningAction Taken
-1End of stream – connection closedBreaks loop, likely reconnects
0Null byte (\0) – End of command lengthConverts text to num (expected byte count)
defaultAny other byte – Part of the command length stringAppends to text

Interestingly, the data format for both sending and receiving follows the same structure:

[Message Length] + „\0” + [Exfiltrated Data] – in case of data leaving the host

[Message Length] + „\0” + [Command] – in case of commands for the host

Now that the length is known, the whole command can be received. It is done by allocating OK.b byte array of the earlier computed length. OK.C.Client.Receive receives the data and writes it to OK.MeM (ex. 18)

(ex. 18 - Writing data to OK.MeM MemoryStream)
(ex. 18 – Writing data to OK.MeM MemoryStream)

Command received! Next step is to pass it for processing. njRAT does it asynchronously by calling OK.im function in a new thread (ex. 19). After that it clears its memory and awaits new commands.

(ex. 19 - Passing command to OK.im and clearing memory stream)
(ex. 19 – Passing command to OK.im and clearing memory stream)

Next thing in the flow is for the command to be parsed by the command handler function – let’s take a look at how it’s done.

Command Handler: Data Exfiltration, Remote Code Execution, and More

The decision making part of this njRAT sample is surely done by the Ind() function – it is called by OK.im which like I showed, receives the data from the listener – RC () function.

First step is to take the data and get it ready for comparing (ex. 20). „array” is the buffer which is filled by spliting the data ’Strings.Split’, encoding it to UTF-8 ’OK.BS’ and using delimiter ’OK.Y’ which is just „|’|’|”

text = array [0] – this is equal to the first element in the array -> the command!

(ex. 20 - preparing the data for comparison)
(ex. 20 – preparing the data for comparison)

Due to the fact that there is a lot of available features I will be classifying them. Also there is too much code to show the logic behind every single one of these functions but I will try to show the most relevant ones.

1. System Control and Persistence

Most of these commands use Interaction.Shell API call to run the command eg. Shutdowncomputer (ex. 21)

(ex. 21 - example of how the commands are compared)
(ex. 21 – example of how the commands are compared)
CommandFunctionality
shutdowncomputerShuts down the infected system using „shutdown -s -t 00”
restartcomputerRestarts the infected system using „shutdown -r -t 00”
logoffLogs out the current user using „shutdown -l -t 00”
unUninstalls the malware (likely against forensic analysis)
upUpdates the malware by downloading a new binary and restarting
profReads/Writes registry values based on attacker-supplied parameters
IEhomeModifies the IE homepage
DisableCMD / EnableCMDAlters registry to disable or enable Command Prompt
DisableRegistry / EnableRegistryDisables or enables registry editor
DisableRestore / EnableRestoreDisables or enables system restore functionality
DisableTaskManager / EnableTaskManagerDisables or enables task manager

The „un” command is worth a little more explanation. It calls a function that:

  • Removes file attributes like „Hidden” or „Read-only” from the malware executable
(ex. 22 - setting standard file attributes)
(ex. 22 – setting standard file attributes)
  • Removes registry persistence entries
(ex. 23 - removing registry entires)
(ex. 23 – removing registry entires)
  • Removes firewall exception
(ex. 24 - netsh firewall delete ...)
(ex. 24 – netsh firewall delete …)
  • Deletes the startup copy (%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\malware.exe)
(ex. 25 - startup copy removal )
(ex. 25 – startup copy removal )
  • Finally, the malware executes self-deletion via a shell command and process termination.
(ex. 26 - self-deletion )
(ex. 26 – self-deletion )

2. Keylogging and Data Exfiltration

CommandFunctionality
klStarts the keylogger, capturing keystrokes
pasDownloads and runs a password stealer (Pass.exe) from Dropbox
CAPTakes a screenshot, compresses it and sends to the C2 server

3. Network Attacks

CommandFunctionality
udpPerforms UDP flood DoS attack to specified target IP and port
udpstpStops the attack

4. C2 Communication and Remote Execution

CommandFunctionality
pingstopKills all active pings (taskkill /F /IM PING.EXE)
OpenSiteOpens a specified website
reconnectForces the malware to reconnect to the C2 server
llTerminates the C2 connection setting OK.Cn flag to false
nwprRuns arbitrary process
rnDownloads and executes any arbitrary files

5. Disruption, Chaos, Trolling

CommandFunctionality
DisableKM/EnableKMBlocks or enables input devices eg. mouse, keyboard
TurnOffMonitor / TurnOnMonitorTurns the monitor off/on
NormalMouse / ReverseMouseSwaps mouse buttons
CursorHide / CursorShowHides or shows cursor
sendmusicplayPlays audio
OpenCD / CloseCDOpen/Closed CD drive
pianoPlays a beep sound for 300 ms
BepXPlays a beep sound with specified frequency and duration
peechTriggers Windows Text-to-Speech
ErorrMsg (yes, with the typo)Displays different kind of error msg boxes with specified flags

While these commands are hardcoded, the adversary’s capabilities extend far beyond them. With remote code execution and the un command, which allows for malware updates, the attacker maintains near-unlimited flexibility to modify, expand, or replace functionality as needed.

Now let’s take a look on one of the functionalities – keylogger.

Keylogger functionality analysis

WRK () – keylogger function that is triggered as one of the first data exfiltration functions. Here is a quick overview of how it works.

(ex. 27 - WRK main while loop )
(ex. 27 – WRK main while loop )

do While provides continuous execution, it iterates through 0-255 with the help of num2 variable.

If statement checks for pressed key with the value of num2 [GetAsyncKeyState] sets MSB to 1 if a key is pressed]. The whole statement will not be true if the CTRL key is down – probably to avoid logging CTRL+KEY shortcuts.

The key in it’s value format is assigned to „Keys k” which then is processed by Fix() function (ex. 28).

(ex. 27 - Fix function )
(ex. 27 – Fix function )

Fix() seems to be a way of checking if the key pressed is one of the special characters that it would like to ignore/alter for logging purpose.

  • Backspace & Delete -> [BACKSPACE] & [DELETE}
  • Ignoring certain key completely eg. Shift (160,161), Ctrl (162,163), F1 – F12 (112-123), Home key (35) and more
  • Enter -> [ENTER] followed by carriage return
  • TAB -> [TAP] probably to log if user changed text field

Last two steps of Fix() are to check if any of the characters suppose to be uppercased and converting it to unicode before returning.

Coming back to the WRK() function briefly just to jump to the AV() function (ex. 28). We can see that Logs is being populated with both AV results as well as with the „text” itself. The AV() function plays a crucial role in tracking user activity by identifying the application in which the victim is typing, extracting relevant metadata for logging.

(ex. 28 - AV function )
(ex. 28 – AV function )

AV gathers information using API and logs it in a format that might be expressed by an example like: 24/01/19 chrome Facebook – Google Chrome

Lastly WRK saves all of the collected and formatted data to „Logs” for future use.

(ex. 28 - passing data to Logs )
(ex. 28 – passing data to Logs )

I think that’s enough of source code analysis. To discover a little more about the C2 or maybe the creator I decided to do some OSINT

OSINT FINDINGS

Censys shows that the IP is static, provided by „Best IDC” with location in Bangkok, Thailand (ex. 29). Most likely this is a rented VPS server running Windows OS.
 

(ex. 29 - Censys results )
(ex. 29 – Censys results )

There are also multiple services open including FTP, HTTP, WINRM.

The FTP is in fact live but it doesn’t accept anonymous login (ex. 30).

(ex. 30 - Trying to connect to FTP using anonymous account )
(ex. 30 – Trying to connect to FTP using anonymous account )

There is an HTTP site being hosted under the malicious IP

(ex. 31 - HTTP site hosted on the same IP as C2 )
(ex. 31 – HTTP site hosted on the same IP as C2 )

The rough translation is:

Top up, change password (Support)

Contact admin

Download (Download)

FullClient

Both „contact admin” and „Fanpage” lead to a facebook page called „AmazonZ Revolution” (ex. 32) with some gaming content. Download points to google drive hosting a compressed archive called „AmazonZ Full.rar”

(ex. 32 - Facebook fanpage )
(ex. 32 – Facebook fanpage )

Surprisingly the IP is not flagged heavily as malicious on VirusTotal (ex. 33).

(ex. 33 - VirusTotal results on the IP)
(ex. 33 – VirusTotal results on the IP)

In the ThreatFox database the IP is correctly identified with botnet_cc threat type with 100% confidence (ex. 34).

(ex. 34 - ThreatFox results on the IP)
(ex. 34 – ThreatFox results on the IP)

There isn’t much more noteworthy information to cover here, aside from a deeper analysis of the zipped package from Google Drive – which is a topic for another post. For now, let’s move on to the summary.

Summary & MITRE ATT&CK Mapping

Sample Overview

  • MD5 Hash: 8d84f5becf22d3bceb322273fa2ac133
  • Type: .NET-based Remote Access Trojan (RAT)
  • C2 Server: 43.255.241.232
  • Port: 5555
  • Hardcoded Botnet Name: „WarZv1” (Base64-encoded)
Key findings
  • Sends system information (OS details, hostname, directory info, persistence settings).
  • Listens for commands from the C2 server (RC() function).
  • Uses structured message format ([Message Length] + \0 + [Data]).

Keylogging and Data Exfiltration

  • Logs keystrokes via GetAsyncKeyState(), storing them in Logs.
  • Captures foreground window titles (AV() function) to track which app is active.
  • Can take screenshots (CAP command), checks for duplicates via MD5 hashing.

Evasion and Persistence

  • Uses registry modifications for persistence
  • Writes itself to HKCU\Software\Microsoft\Windows\CurrentVersion\Run.
  • Creates a mutex (f7c5ecd48555dff5f89453188d5fb470) to prevent multiple instances.
  • Attempts self-protection by blocking Task Manager, Process Explorer, Process Hacker.
  • Tries to kill security processes via taskkill /F /IM <process>.
  • Can delete itself (un command) by removing registry keys, firewall exceptions, and executing a self-delete batch script.

Remote Command Execution

  • Executes arbitrary shell commands (Interaction.Shell() API).
  • Can download and run executables (rn command).

System Disruption

  • Multiple disruptive functionalities eg. blocking input.

 DoS Capabilities

  • Can launch a UDP flood attack (udp command) on specified targets.
MITRE ATT&CK
TacticTechnique
ExecutionT1059 – Command and Scripting Interpreter
PersistenceT1547 – Boot or Logon Autostart Execution
Privilege EscalationT1548 – Abuse Elevation Control Mechanism
Credential AccessT1056 – Keylogging
DiscoveryT1082 – System Information Discovery
Lateral MovementT1091 – Replication through removable media
CollectionT1113 – Screen Capture
Command & ControlT1071 – Application Layer Protocols
ExfiltrationT1041 – Exfiltration Over C2 Channel
ImpactT1498 – Network DoS
Defense EvasionT1070 – Indicator Removal, T1562 – Disable Security Tools

Final Thoughts

This njRAT sample demonstrates classic remote administration and botnet capabilities, prioritizing data theft, persistence, and system disruption. While it lacks advanced obfuscation techniques seen in more sophisticated malware, it remains a serious threat – particularly when deployed against unprotected systems. Its ability to evade detection, disable security tools, and establish long-term access makes it a viable tool for cybercriminals targeting exposed or poorly secured environments.

<—— Go back