Dissecting REMCOS RAT: An in- depth analysis of a widespread 2024 malware, Part One

Part one: Introduction to REMCOS and diving into its initialization procedure

11 min readMalware analysis
Dissecting REMCOS RAT: An in-depth analysis of a widespread 2024 malware, Part One

In the first article in this multipart series, malware researchers on the Elastic Security Labs team give a short introduction about the REMCOS threat and dive into the first half of its execution flow, from loading its configuration to cleaning the infected machine web browsers.

Introduction

Elastic Security Labs continues its examination of high-impact threats, focusing on the internal complexities of REMCOS version 4.9.3 Pro (November 26, 2023).

Developed by Breaking-Security, REMCOS is a piece of software that began life as a red teaming tool but has since been adopted by threats of all kinds targeting practically every sector.

When we performed our analysis in mid-January, it was the most prevalent malware family reported by ANY.RUN. Furthermore, it remains under active development, as evidenced by the recent announcement of version 4.9.4's release by the company on March 9, 2024.

All the samples we analyzed were derived from the same REMCOS 4.9.3 Pro x86 build. The software is coded in C++ with intensive use of the std::string class for its string and byte-related operations.

REMCOS is packed with a wide range of functionality, including evasion techniques, privilege escalation, process injection, recording capabilities, etc.

This article series provides an extensive analysis of the following:

  • Execution and capabilities
  • Detection and hunting strategies using Elastic’s ES|QL queries
  • Recovery of approximately 80% of its configuration fields
  • Recovery of about 90% of its C2 commands
  • Sample virtual addresses under each IDA Pro screenshot
  • And more!

REMCOS execution diagram REMCOS execution diagram

For any questions or feedback, feel free to reach out to us on social media @elasticseclabs or in the Elastic Community Slack.

Loading the configuration

The REMCOS configuration is stored in an encrypted blob within a resource named SETTINGS. This name appears consistent across different versions of REMCOS.

REMCOS config stored in encrypted SETTINGS resource REMCOS config stored in encrypted SETTINGS resource

The malware begins by loading the encrypted configuration blob from its resource section.

0x41B4A8 REMCOS loads its encrypted configuration from resources 0x41B4A8 REMCOS loads its encrypted configuration from resources

To load the encrypted configuration, we use the following Python script and the Lief module.

import lief

def read_encrypted_configuration(path: pathlib.Path) -> bytes | None:
	if not (pe := lief.parse(path)):
    		return None

	for first_level_child in pe.resources.childs:
    		if first_level_child.id != 10:
        		continue

    	for second_level_child in first_level_child.childs:
        		if second_level_child.name == "SETTINGS":
            			return bytes(second_level_child.childs[0].content)

We can confirm that version 4.9.3 maintains the same structure and decryption scheme as previously described by Fortinet researchers:

Fortinet reported structure and decryption scheme Fortinet reported structure and decryption scheme

We refer to the “encrypted configuration” as the structure that contains the decryption key and the encrypted data blob, which appears as follows:

struct ctf::EncryptedConfiguration
{
uint8_t key_size;
uint8_t key[key_size];
uint8_t data
};

The configuration is still decrypted using the RC4 algorithm, as seen in the following screenshot.

0x40F3C3 REMCOS decrypts its configuration using RC4 0x40F3C3 REMCOS decrypts its configuration using RC4

To decrypt the configuration, we employ the following algorithm.

def decrypt_encrypted_configuration(
	encrypted_configuration: bytes,
) -> tuple[bytes, bytes]:
	key_size = int.from_bytes(encrypted_configuration[:1], "little")
	key = encrypted_configuration[1 : 1 + key_size]
	return key, ARC4.ARC4Cipher(key).decrypt(encrypted_configuration[key_size + 1 :])

The configuration is used to initialize a global vector that we call g_configuration_vector by splitting it with the string \x7c\x1f\x1e\x1e\x7c as a delimiter.

0x40EA16 Configuration string is split to initialize g_configuration_vector 0x40EA16 Configuration string is split to initialize g_configuration_vector

We provide a detailed explanation of the configuration later in this series.

UAC Bypass

When the enable_uac_bypass_flag (index 0x2e) is enabled in the configuration, REMCOS attempts a UAC bypass using a known COM-based technique.

0x40EC4C Calling the UAC Bypass feature when enabled in the configuration 0x40EC4C Calling the UAC Bypass feature when enabled in the configuration

Beforehand, the REMCOS masquerades its process in an effort to avoid detection.

0x40766D UAC Bypass is wrapped between process masquerading and un-masquerading 0x40766D UAC Bypass is wrapped between process masquerading and un-masquerading

REMCOS modifies the PEB structure of the current process by replacing the image path and command line with the explorer.exe string while saving the original information in global variables for later use.

0x40742E Process PEB image path and command line set to explorer.exe 0x40742E Process PEB image path and command line set to explorer.exe

The well-known technique exploits the CoGetObject API to pass the Elevation:Administrator!new: moniker, along with the CMSTPLUA CLSID and ICMLuaUtil IID, to instantiate an elevated COM interface. REMCOS then uses the ShellExec() method of the interface to launch a new process with administrator privileges, and exit.

0x407607 calling ShellExec from an elevated COM interface 0x407607 calling ShellExec from an elevated COM interface from ucmCMLuaUtilShellExecMethod

0x4074FD instantiating an elevated COM interface 0x4074FD Instantiating an elevated COM interface from ucmAllocateElevatedObject

This technique was previously documented in an Elastic Security Labs article from 2023: Exploring Windows UAC Bypasses: Techniques and Detection Strategies.

Below is a recent screenshot of the detection of this exploit using the Elastic Defend agent.

UAC bypass exploit detection by the Elastic Defend agent disabling UAC UAC bypass exploit detection by the Elastic Defend agent

Disabling UAC

When the disable_uac_flag is enabled in the configuration (index 0x27), REMCOS disables UAC in the registry by setting the HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\SystemEnableLUA value to 0 using the reg.exe Windows binary."

0x40EC76 Calling the UAC disable feature when enabled in the configuration 0x40EC76 Calling the UAC disable feature when enabled in the configuration

0x407755 Setting the EnableLUA registry key to 0 0x407755 Setting the EnableLUA registry key to 0

Install and persistence

When enable_install_flag (index 0x3) is activated in the configuration, REMCOS will install itself on the host machine.

0x40ED8A Calling install feature when the flag is enabled in configuration 0x40ED8A Calling install feature when the flag is enabled in configuration

The installation path is constructed using the following configuration values:

  • install_parent_directory (index 0x9)
  • install_directory (0x30)
  • install_filename (0xA)

The malware binary is copied to {install_parent_directory}/{install_directory}/{install_filename}. In this example, it is %ProgramData%\Remcos\remcos.exe.

Sample detected in its installation directory Sample detected in its installation directory

If the enable_persistence_directory_and_binary_hiding_flag (index 0xC) is enabled in the configuration, the install folder and the malware binary are set to super hidden (even if the user enables showing hidden files or folders the file is kept hidden by Windows to protect files with system attributes) and read-only by applying read-only, hidden, and system attributes to them.

0x40CFC3 REMCOS applies read-only and super hidden attributes to its install folder and files 0x40CFC3 REMCOS applies read-only and super hidden attributes to its install folder and files

Install files set as read-only and super hidden Install files set as read-only and super-hidden

After installation, REMCOS establishes persistence in the registry depending on which of the following flags are enabled in the configuration:

  • enable_hkcu_run_persistence_flag (index 0x4) HKCU\Software\Microsoft\Windows\CurrentVersion\Run\
  • enable_hklm_run_persistence_flag (index 0x5) HKLM\Software\Microsoft\Windows\CurrentVersion\Run\
  • enable_hklm_policies_explorer_run_flag (index 0x8) HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run\

0x40CD0D REMCOS establishing persistence registry keys 0x40CD0D REMCOS establishing persistence registry keys

The malware is then relaunched from the installation folder using ShellExecuteW, followed by termination of the initial process.

0x40D04B Relaunch of the REMCOS process after installation 0x40D04B Relaunch of the REMCOS process after installation

Process injection

When the enable_process_injection_flag (index 0xD) is enabled in the configuration, REMCOS injects itself into either a specified or a Windows process chosen from an hardcoded list to evade detection.

0x40EEB3 Calling process injection feature if enabled in the configuration 0x40EEB3 Calling process injection feature if enabled in the configuration

REMCOS running injected into iexplore.exe REMCOS running injected into iexplore.exe

The enable_process_injection_flag can be either a boolean or the name of a target process. When set to true (1), the injected process is chosen in a “best effort” manner from the following options:

  • iexplorer.exe
  • ieinstal.exe
  • ielowutil.exe

0x40F6AD Process injection target process selected from hardcoded options 0x40F6AD Process injection target process selected from hardcoded options

Note: there is only one injection method available in REMCOS, when we talk about process injection we are specifically referring to the method outlined here

REMCOS uses a classic ZwMapViewOfSection + SetThreadContext + ResumeThread technique for process injection. This involves copying itself into the injected binary via shared memory, mapped using ZwMapViewOfSection and then hijacking its execution flow to the REMCOS entry point using SetThreadContext and ResumeThread methods.

It starts by creating the target process in suspended mode using the CreateProcessW API and retrieving its thread context using the GetThreadContext API.

0x418217 Creation of target process suspended mode 0x418217 Creation of target process suspended mode

Then, it creates a shared memory using the ZwCreateSection API and maps it into the target process using the ZwMapViewOfSection API, along with the handle to the remote process.

0x418293 Creating of the shared memory 0x418293 Creating of the shared memory

0x41834C Mapping of the shared memory in the target process 0x41834C Mapping of the shared memory in the target process

The binary is next loaded into the remote process by copying its header and sections into shared memory.

0x41836F Mapping the PE in the shared memory using memmove 0x41836F Mapping the PE in the shared memory using memmove

Relocations are applied if necessary. Then, the PEB ImageBaseAddress is fixed using the WriteProcessMemory API. Subsequently, the thread context is set with a new entry point pointing to the REMCOS entry point, and process execution resumes.

0x41840B Hijacking process entry point to REMCOS entry point and resuming the process 0x41840B Hijacking process entry point to REMCOS entry point and resuming the process

Below is the detection of this process injection technique by our agent:

Process injection alert Process injection alert

Process injection process tree Process injection process tree

Setting up logging mode

REMCOS has three logging mode values that can be selected with the logging_mode (index 0x28) field of the configuration:

  • 0: No logging
  • 1: Start minimized in tray icon
  • 2: Console logging

0x40EFA3 Logging mode configured from settings 0x40EFA3 Logging mode configured from settings

Setting this field to 2 enables the console, even when process injection is enabled, and exposes additional information.

REMCOS console displayed while injected into iexplore.exe REMCOS console displayed while injected into iexplore.exe

Cleaning browsers

When the enable_browser_cleaning_on_startup_flag (index 0x2B) is enabled, REMCOS will delete cookies and login information from the installed web browsers on the host.

0x40F1CC Calling browser cleaning feature when enabled in the configuration 0x40F1CC Calling browser cleaning feature when enabled in the configuration

According to the official documentation the goal of this capability is to increase the system security against password theft:

Documentation about cleaning cookies and logins Documentation about cleaning cookies and logins

Currently, the supported browsers are Internet Explorer, Firefox, and Chrome.

0x40C00C Supported browsers for cleaning features 0x40C00C Supported browsers for cleaning feature

The cleaning process involves deleting cookies and login files from browsers' known directory paths using the FindFirstFileA, FindNextFileA, and DeleteFileA APIs:

0x40BD37 Cleaning Firefox cookies 1/2 0x40BD37 Cleaning Firefox cookies 1/2

0x40BD37 Cleaning Firefox cookies 2/2 0x40BD37 Cleaning Firefox cookies 2/2

When the job is completed, REMCOS prints a message to the console.

REMCOS printing success message after cleaning browsers REMCOS printing success message after cleaning browsers

It's worth mentioning two related fields in the configuration:

  • enable_browser_cleaning_only_for_the_first_run_flag (index 0x2C)
  • browser_cleaning_sleep_time_in_minutes (index 0x2D)

The browser_cleaning_sleep_time_in_minutes configuration value determines how much time REMCOS will sleep before performing the job.

0x40C162 Sleeping before performing browser cleaning job 0x40C162 Sleeping before performing browser cleaning job

When enable_browser_cleaning_only_for_the_first_run_flag is enabled, the cleaning will occur only at the first run of REMCOS. Afterward, the HKCU/SOFTWARE/{mutex}/FR registry value is set.

On subsequent runs, the function directly returns if the value exists and is set in the registry.

0x40C162 Not performing cleaning job if FR registry key is set 0x40C162 Not performing cleaning job if FR registry key is set

That’s the end of the first article. The second part will cover the second half of REMCOS' execution flow, starting from its watchdog to the first communication with its C2.