Research by: Niv Asraf
In the last two months, Check Point researchers encountered a new large-scale phishing campaign that recently targeted more than 40 prominent companies across multiple industries, in Colombia. The attackers’ objective was to discreetly install the notorious “Remcos” malware on victims’ computers. Remcos, a sophisticated “Swiss Army Knife” RAT, grants attackers full control over the infected computer and can be used in a variety of attacks. Common consequences of a Remcos infection include data theft, follow-up infections, and account takeover. In our report, we delve into the attack intricacies and highlight the stealthy techniques employed by the malicious actors.
Figure 1: Attack flow chart.
- Fraudulent Email:
The attackers initiated the campaign by sending deceptive emails allegedly from trusted entities, including reputable financial institutions and corporations operating within Colombia. These malicious emails were crafted to appear genuine, often containing urgent notifications, reports of overdue debts, or enticing offers.
Figure 2: Example of a phishing email.
- Email Contains an Archive File:
The phishing email contains an attachment that appears to be a harmless archive file, such as ZIP, RAR or TGZ. The attachment label states that it contains important documents, invoices, or other enticing information to encourage the recipients to open it.
- Highly Obfuscated BAT File with PowerShell Commands:
The archive file contains a highly obfuscated Batch (BAT) file. Upon execution, the BAT file runs PowerShell commands which are also heavily obfuscated. This multi-layer obfuscation makes it difficult for security solutions to detect and analyze the malicious payload.
- Loading .NET Modules:
After the PowerShell commands are deciphered, they load two .NET modules into memory. These modules are essential for the subsequent stages of the attack.
- First .NET Module: Evasion and Unhooking:
The first .NET module’s primary purpose is to evade detection and unhook any security mechanisms present in the targeted system. By removing or bypassing security hooks, the attackers increase the malware’s chances of remaining undetected and enable it to operate stealthily.
- Second .NET Module: Loading “LoadPE” and Remcos:
The second .NET module dynamically loads another component called “LoadPE” from the file resources. “LoadPE” is responsible for reflective loading, a technique that allows the loading of a Portable Executable (PE) file (in this case, the Remcos malware) directly into memory without the need for it to be stored on the disk.
- Reflective Loading with “LoadPE”:
Using the “LoadPE” component, the attackers load the final payload, the Remcos malware, directly from their resources into the memory. This reflective loading technique further enhances the malware’s ability to evade traditional antivirus and endpoint security solutions, as it bypasses standard file-based detection mechanisms.
- The Final Payload: Remcos – Swiss Army Knife RAT:
With the successful loading of the Remcos malware into memory, the attack is now complete. Remcos, a potent Remote Administration Tool (RAT), grants the attackers full control over the compromised system. It serves as a Swiss Army Knife for the attackers, allowing them to execute a wide range of malicious activities, including unauthorized access, data exfiltration, keylogging, remote surveillance, and more.
In the following sections, we examine the technical aspects of the observed issues. We focus on the malware’s evasion techniques and the deobfuscation process we employed to uncover the true nature of the BAT and .NET modules.
Our analysis starts with the malicious BAT file from attack chain stage 3 above.
Figure 3: Obfuscated BAT File.
After deobfuscating parts of the BAT file code with a Python script, the only thing we’re interested in is the last two lines of code:
Figure 4:The last two lines of deobfuscated BAT file.
The first line is responsible for copying the PowerShell executable to the current folder, abusing a double extension in the filename in order to hide the true file type.
And the second line of code looks like a heavily obfuscated PowerShell code.
After we organized and deobfuscated the PowerShell code, this is what we got:
Figure 5: Deobfuscated PowerShell code.
There are two functions here:
- “Zoskj” is responsible for decrypting the payload using AES CBC mode.
- “oPueH” uses GZIP to decompress it.
The flow is to first decode the Base64, and then decrypt it using AES. The last step is to decompress it.
AES key: Bh25J//GchqJk6Loyw9E05onwOgPl+4pjflSE6q18Hk=
AES IV: dQVwOVWNZWJ4TULVM0QMqQ==
Finally, after resolving the two .NET executables, they are both loaded in the memory:
Figure 6: Load 2 .NET executables to the memory
We wanted to see why the attackers split the payload into two .NET executables and if there is a meaning to the order in which they are loaded.
Looking at the first .NET executable, we can see that it is highly obfuscated and almost unreadable.
Figure 7: First .NET obfuscated executable.
While this obfuscation is unknown, we can still use “de4dot” to make it a little bit more readable and then perform further deobfuscation.
de4dot is an open source (GPLv3) .NET deobfuscator and unpacker written in C#.
Figure 8: First .NET obfuscated executable after using de4dot.
The prominent pattern we observed involves deliberately enlarging the size of the code making it more complicated by extensively using Math.Abs/Min methods and adding numerous parentheses. Fortunately, we do not need to perform actual calculations; the values inside these methods directly serve as the final parameters passed into the “smethods_*” functions.
The first interesting thing we noticed here is the unknown strings (outlined in red in Figure 8) that are always passed into “smethod_0”. From this we understand that it is probably a string decryption function.
Figure 9: Decrypt the unknown string function.
Looking at the function itself, we can see that only the string_0 and int_1 arguments are being used in the “for” loop, which is the only part of the code that is relevant here.
Basically, the function takes each “char” from the strings, turns it into an int and subtracts from it the int_1 argument, then converts the resulting value to char and appends it to the “stringBuilder”.
We created our own string decryption method in Python:
Figure 10: String decryption method in Python.
In the Figure 10 example, the return value is “ntdll.dll”.
So now, we can decrypt all unknown strings.
In addition, before the “Main” function executes, we see a lot of dynamically resolved functions assigned to delegated pointer variables to use in the code.
If we decrypt those strings, we can understand what the functions are, and rename the obfuscated delegated names.
Figure 11: Example of the “CloseHandle” function pointer being assigned.
After resolving and renaming, we get these function variables:
Figure 12: Decrypted delegated function pointers.
Now that we decrypted all the pointers, we can reverse-engineer the other methods and understand the flow of the main function.
Let’s analyze the function that receives the decrypted string “ntdll.dll”.
Figure 13: Choose the right ntdll based on IsWow64Process.
Looking at the first chunk of code, we can see two encrypted strings which translate to:
“C:WindowsSystem32” and “C:WindowsSysWOW64”
We also see a delegated function pointer that we resolved earlier, IsWow64Process.
This checks whether the process runs under wow64, so we can use the right ntdll to read from the disk.
Figure 14: Unhooking DLL.
Although this function is still obfuscated, we can analyze and understand the code’s purpose, which is unhooking DLLs that are received as an argument to the function.
This is what happens here:
- Get a handle to the already-hooked library.
- Map a fresh copy of the relevant DLL into memory.
- Replace the .text section of the hooked DLL with the new one from the disk.
Figure 15: Unhooking.
VirtualProtect is used to change the .text section protection, using memcpy to copy the new unhooked section, and finally return to the old protection.
Now we can safely change the function name to UnhookModule.
This is the last major function of this executable:
Figure 16: Patching functions in memory with code that returns an error code.
This function takes a few arguments: Dll Name, Function Name, and a Byte Sequence.
It is responsible for patching functions in memory with code that returns an error code: 0x80070057 “The parameter is incorrect”.
To summarize, this is the first .NET Main Functionality:
- Unhooking kernel32.dll
- Unhooking ntdll.dll
- Patching the amsi.dll AmsiScanBuffer function to return “The parameter is incorrect” code (0x80070057)
- Patching the ntdll.dll EtwEventWrite function to return “The parameter is incorrect” code (0x80070057)
The second .NET is also heavily obfuscated but now the code size is much smaller. In addition, now that we understand the way the obfuscation works, it is much easier to understand its content.
Figure 17: Reversed and deobfuscated second .NET module.
To summarize, this is the second .NET Main Functionality:
- Check if there is a debugger.
- Use PowerShell to wait for the process to end and then delete the main module file.
- Load two additional files from the resources:
- Remcos malware
- LoadPE .NET executable
At the end of the Main function, the final payload, Remcos, is assigned to the “array” variable and then is passed as an argument to another invoked .NET executable, the “LoadPE” exe, which is responsible for getting an executable as an argument and loading it using reflective loading.
As we mentioned earlier in this report, reflective loading is used to dynamically load a library or executable directly into memory without relying on the standard operating system mechanisms for loading files from the disk.
In malware, reflective loading is often employed as a stealthy way to execute malicious code without writing any files to the disk. This makes it harder for traditional security tools to detect the presence of the malware as there are no files that can be scanned or monitored. Reflective loading also makes it harder to identify and analyze the malicious code.
The third LoadPE .NET executable is not obfuscated at all, which means we can easily reverse-engineer and understand what it’s used for.
These are its functions:
Figure 18: LoadPE .NET functions.
The final payload, the Remcos malware, stores its encrypted configuration file, called “SETTING”, in the resources.
We can easily see the configuration in memory:
Figure 19: Remcos configuration in memory.
Summary of the Remcos configuration:
Assigned name: “Vps”
Copy file: “remcos.exe”
Startup value: “Remcos”
Keylog file: “vpslogs.dat”
Screenshot file: “Screenshots”
Audio folder: “MicRecords”
Copy folder: “Remcos”
Keylog folder: “vp”
Keylog file max size: “100000”
We wanted to see if our assumptions were correct, so we entered the word “password” and also ”xxxx” and “123123”, then checked the keylogging file. As you can see, we were right.
Figure 20: Keylogging in action.
Our analysis offers a glimpse into the intricate world of evasion techniques and deobfuscation procedures employed by attackers. By deciphering the hidden functionalities of the malicious BAT and .NET modules, we were able to shed light on the attack flow’s complexity. Understanding these technical intricacies is essential for enhancing cybersecurity defenses and devising effective countermeasures to protect against such advanced phishing campaigns.
Check Point customers remain protected from the threats described in this research.
Check Point’s Threat Emulation provides comprehensive coverage of attack tactics, file types, and operating systems and has developed and deployed a signature to detect and protect customers against threats described in this research.