Blog

Technical Analysis of DarkVNC

BY eSentire Threat Response Unit (TRU)

February 12, 2024 | 11 MINS READ

Attacks/Breaches

Threat Intelligence

Threat Response Unit

TRU Positive/Bulletin

Want to learn more on how to achieve Cyber Resilience?

TALK TO AN EXPERT

DarkVNC is a hidden utility based on the Virtual Network Computing (VNC) technology, initially promoted on an Exploit forum in 2016. The primary distinction between hVNC and VNC lies in their intended usage and the degree of transparency: VNC can serve as a legitimate tool for remote desktop sharing, while hVNC is associated with stealthy or potentially malicious activities, often operating without the user’s knowledge or consent.

DarkVNC has been identified as being in use by threat actors associated with IcedID. We have also observed where DarkVNC was dropped by StellarInjector and served as the next stage for a SolarMarker infection. DarkVNC was first advertised on Exploiton November 24, 2016 (Figure 1).

Figure 1: DarkVNC advertisement

The tool received active updates from 2016 to 2017:

Figure 2: DarkVNC update

In April 2021, the seller mentioned under one of the threads that they no longer take new clients (Figure 3).

Figure 3: Comment from the DarkVNC seller

Technical Analysis

This analysis will focus on a DarkVNC payload that utilizes 'vncdll64.dll' as its export module name. This indicates that the payload is created to export its functionalities or resources using the 'vncdll64.dll' identifier.

Specifically, the payload is crafted to offer hidden VNC capabilities, which malicious programs can exploit to remotely control a machine. These functionalities are made accessible through the 'VNCDLL64.DLL' file."

Figure 4: 'vncdll64.dll' identifier in Malcat

Searching for the DLL reference, we stumble across an interesting GitHub page that is located under “Buhtrap Source Code”. Upon compiling the source code, it will create the DLLs, one of which is VNCDLL64.DLL (64-bit VNC module).

According to the description, the DLL integrates into one of the active user's processes. When a new session is initiated, this DLL generates a concealed user desktop environment in which it launches explorer.exe. As a result, the client connecting to the session gains access to an identical replica of the currently active user's desktop.

To obtain the mutex value, DarkVNC performs numerous steps of calculations. First, it obtains the computer name of the host. Then the code computes a 32-bit value based on the given computer name using bitwise operations and rotations.

It processes each character of the name, applies a series of XOR and circular shift operations (Figure 2), and finally adds 6 to the resultant value. The code will exit if it fails to create the mutex when it does not already exist.

Figure 5: Mutex calculation

DarkVNC uses simple XOR for string encryption. The XOR decryption function takes three parameters: a pointer to the string to be decrypted, encrypted string, and the size of the encrypted string. For each character in the string, the function performs an XOR operation with the character at a2 (Figure 3).

Figure 6: XOR string decryption

DarkVNC generates a unique ID based on the system's tick count, a measure of the system's uptime in milliseconds. The function enters a loop that iterates 8 times, corresponding to the 8 characters of the unique identifier.

In each iteration, it computes a new value v1 by XORing GetTickCount_var_div_3 (Figure 7) with the current value of GetTickCount(), modulo 75 (0x4B), and then adds 48. This calculation seems designed to generate a number within certain ASCII ranges.

The function then checks if v1 falls within the ASCII ranges for digits, uppercase letters, or lowercase letters. If v1 is within these ranges, it is added to the v4 array, and the counter is incremented.

The function then waits for 10 milliseconds before the next iteration.

Figure 7: Unique ID generation

This is the Python code to reproduce the unique ID generation function:

import time

def mw_unique_id_gen():
    unique_id = bytearray(9)  
    counter = 0

    while counter < 8:
        # Simulating the GetTickCount() function
        tick_count = int(time.time() * 1000) // 3

        # Simulating the process of generating a character
        v1 = (tick_count ^ int(time.time() * 1000)) % 0x4B + 48

        # Check if the character is within the valid ASCII range
        if (0x30 <= v1 <= 0x39) or (0x41 <= v1 <= 0x5A) or (0x61 <= v1 <= 0x7A):
            unique_id[counter] = v1
            counter += 1
        time.sleep(0.01)  # Sleep for 10 milliseconds

    unique_id[8] = 0  
    return unique_id.decode()

# Generate the unique ID
unique_id = mw_unique_id_gen()
print("Unique ID:", unique_id)

Next, the payload retrieves the computer name, the username, and volume information; if it fails to get the computer name and the username, it defaults to the “N0NE” string. The gathered information is then concatenated into the format “USR-ComputerName(Username)_ VolumeSerialNumber -UniqueID"; the code functionality is shown in Figure 8. The concatenated string is then gets sent to the C2 server.

Figure 8: Snippet of the code responsible for gathering computer name, username and volume information

Next, the payload starts the communication with the VNC server with “VncStartServer” in a separate thread, it then creates a socket, attempts to connect to the specified address, sets socket timeout options, sends out the data, and receives a response, as shown in the code in Figure 9.

Figure 9: Function responsible for creating socket connection

Upon successful initialization, the infected machine sends out a similar string to C2 server as the one mentioned above with “USR“ but instead this one contains “BOT”.

The function in Figure 10 searches for specific windows: “Progman” (Program Manager), “SHELLDLL_DefView”, and “SysListView32” (FolderView). These are components of the Windows desktop. “SHELLDLL_DefView” is a child of the “Progman” and is used to implement the desktop’s visual elements. “SysListView32” is a standard Windows class used for list view controls.

In the context of the desktop, it's used to display the actual icons. "Progman" is the top-level window that represents the desktop, it’s essentially the background window upon which other elements like icons are placed. The function then calls FindWindowExA to find windows based on class names and titles.

It then modifies the style of these windows to add WS_VISIBLE using SetWindowLongA, this is done to ensure that the windows are visible. The -16 parameter corresponds to GWL_STYLE, which sets window styles.

Figure 10: Windows search

The function below determines the integrity level of a current process. Higher integrity levels (like “System” or “High”) indicate processes with more privileges, while lower ones (like “Medium” or “Low”) have fewer privileges (Figure 11).

Figure 11: Function to retrieve integrity level of the process

The payload then checks whether the integrity level is equal to or greater than 0x3000. This value (0x3000) represents a threshold integrity level (possibly ‘High’).

If the integrity level is equal to or greater than 0x3000, the malware searches for the explorer.exe process and retrieves its process ID (PID), as shown in Figure 12. It then attempts to open explorer.exe (identified by the PID) with extensive access rights. These rights include querying, terminating, and creating a new process.

Figure 12: Retrieving the process ID for explorer.exe

If the integrity level of the explorer.exe process is found to be less than 0x3000, it proceeds to call OpenProcessToken for that process handle, attempting to obtain a token handle (TokenHandle). The function retrieves the system Windows directory path, depending on whether TokenHandle is obtained, and appends "\explorer.exe" to the system Windows directory.

Next, the function duplicates the token handle obtained from explorer.exe using DuplicateTokenEx. The duplicated token is used to create a new process and perform process injection with the security context of the duplicated token (Figure 13).

Figure 13: Token impersonation and process injection

The function processes various outputs such as 'help', 'cmd', 'monitor_off/on', 'mouse_off/on', 'kbd_off/on', 'block_input/unblock_input', 'del_exe', and 'exit' (Figure 11). It uses hooks (SetWindowsHookExA) for monitoring input events, including keyboard, mouse, and monitor actions. The commands like 'monitor_off/on', 'mouse_off/on', and 'kbd_off/on' indicate the ability to control the state of these devices.

This functionality and the communication of device statuses to a remote server suggest that the server can remotely control or observe the mouse and keyboard and monitor events on the infected machine. For example, commands to turn off the mouse, keyboard, or monitor could prevent local user interaction during remote operation.

We can reference this documentation for block_input and unblock_input commands. The block_input command effectively prevents the entry of actual and simulated input events from any threads except the one executing the command into the system's input queue. DarkVNC might use the block_input command as part of its strategy to control a victim's system without detection or interference.

Execute "del_exe” is responsible for constructing a path to a .dat file using the %TEMP% environment variable and appends "\bd7f6aa8.dat" (contains path to the DarkVNC executable) to it. It attempts to open this file using CreateFileW. If the file is successfully opened, it reads data from it. It then attempts to delete the file using DeleteFileW.

The file is successfully deleted it prints out " was deleted !", otherwise "something went wrong !" or if the file cannot be found – "can't find any exe !". “cmd” output is responsible for starting the command prompt window.

Figure 14: List of outputs

Next, DarkVNC performs the following steps:

Based on the above mentioned, the function checks various aspects of the Chrome installation and environment, such as the presence of the binary, read and write access to the user data directory, and whether the "chrome.exe" process is running. It returns the results of these checks in a formatted string (Figure 15).

This information can be used for various purposes, such as tailoring its actions to the specific Chrome version, ensuring it can read and potentially manipulate Chrome's data, and interacting with the user's active Chrome session.

Figure 15: Check results appended to the formatted strings

The function below (Figure 16) is responsible for disabling default browser check in Firefox. The function modifies user.js file to write “user_pref("browser.shell.checkDefaultBrowser", false);” to it, which disables the default browser check. This is likely done to ensure smooth and uninterrupted operation of the hVNC.

Figure 16: Disabling default browser prompts

The function in Figure 17 serves as a multipurpose handler for displaying various prompt messages. It includes logic for displaying message boxes that are related to handling browser profiles. The specific actions are determined by the a2 parameter, which acts as a command code to trigger different behaviors.

Custom profiles can be used to create a controlled browsing environment, separate from the user's regular browser settings; saving and managing browser profiles can be used to maintain persistence or data extraction.

The action commands and messages:

Figure 17: Message prompts

We wrote the script to extract the IPs from DarkVNC binaries. You can access it here.

Detection Rules

You can access Yara rule here.

Recommendations from eSentire's Threat Response Unit (TRU):

We recommend implementing the following controls to help secure your organization against DarkVNC malware: 

While the TTPs used by threat actor(s) grow in sophistication, they lead to a certain level of difficulties at which critical business decisions must be made. Preventing the various attack technique and tactics utilized by the modern threat actor requires actively monitoring the threat landscape, developing, and deploying endpoint detections, and the ability to investigate logs & network data during active intrusions. 

eSentire TRU is a world-class team of threat researchers who develop new detections enriched by original threat intelligence and leverage new machine learning models that correlate multi-signal data and automate rapid response to advanced threats.  

To learn what it means to have an elite team of Threat Hunters and researchers that works for you, connect with an eSentire Security Specialist now. 

Indicators of Compromise

You can access the Indicators of Compromise here.

References

MITRE ATT&CK

MITRE ATT&CK Tactic ID MITRE ATT&CK Technique
Initial Access T1189 Drive-by Compromise
User Execution T1204.002 Malicious File
Execution T1059.001 Command and Scripting Interpreter: PowerShell
Privilege Escalation T1055 Process Injection
Defense Evasion T1055

T1027.010

Process Injection

Command Obfuscation

Exfiltration T1041 Exfiltration Over C2 Channel
Discovery T1082

T1057

System Information Discovery

Process Discovery

eSentire Unit
eSentire Threat Response Unit (TRU)

The eSentire Threat Response Unit (TRU) is an industry-leading threat research team committed to helping your organization become more resilient. TRU is an elite team of threat hunters and researchers that supports our 24/7 Security Operations Centers (SOCs), builds threat detection models across the eSentire XDR Cloud Platform, and works as an extension of your security team to continuously improve our Managed Detection and Response service. By providing complete visibility across your attack surface and performing global threat sweeps and proactive hypothesis-driven threat hunts augmented by original threat research, we are laser-focused on defending your organization against known and unknown threats.

Read the Latest from eSentire