Cobalt Strike 3.3 – Now with less PowerShell.exe

May 18, 2016

The fourth release in the Cobalt Strike 3.x series is now available. There’s some really good stuff here. I think you’ll like it.

Unmanaged PowerShell

How do you get your PowerShell scripts on target, run them, and get output back? This is the PowerShell weaponization problem. It’s unintuitively painful to solve in an OPSEC-friendly way (unless your whole platform is PowerShell).

Cobalt Strike tackled this problem in its September 2014 release. Beacon’s PowerShell weaponization allows operators to import scripts, run cmdlets from these scripts, and interact with other PowerShell functionality. Beacon’s method is lightweight. It doesn’t touch disk or require an external network connection. It has a downside though: it relies on powershell.exe.

In December 2014, Lee Christensen came out with an Unmanaged PowerShell proof-of-concept [blog post]. Unmanaged PowerShell is a way to run PowerShell scripts without powershell.exe. Lee’s code loads the .NET CLR, reflectively loads a .NET class through that CLR, and uses that .NET class to call APIs in the System.management.automation namespace to evaluate arbitrary PowerShell expressions. It’s a pretty neat piece of code.

This release integrates Lee’s work with Beacon. The powerpick [cmdlet+args] command (named after Justin Warner’s early adaptation of Lee’s POC) will spawn a process, inject the Unmanaged PowerShell magic into it, and run the requested command.

I’ve also added psinject [pid] [arch] [command] to Beacon as well. This command will inject the Unmanaged PowerShell DLL into a specific process and run the command you request. This is ideal for long-running jobs or injecting PowerShell-based agents (e.g., Empire) into a specific process.

I took a lot of care to make powerpick and psinject behave the same way as Beacon’s existing powershell command (where possible). All three commands are friendly to long-running jobs and they will return output as it’s available. All three commands can also use functions from scripts brought into Beacon with the powershell-import command.

More One-Liners for Beacon Delivery

One of my favorite Cobalt Strike features is PowerShell Web Delivery. This feature generates a PowerShell script, hosts it, and gives back a one-liner that you can use to download and execute a Beacon payload. These one-liners have many uses: they seed access in assume breach engagements, they help turn an RDP access or command execution vulnerability into a session, and they’re great for backdoors.

Cobalt Strike 3.3 extends this feature. The PowerShell Web Delivery dialog is now Scripted Web Delivery with one-liners to download and run payloads through bitsadmin, powershell, python, and regsvr32. Each of these options is a different way to run a Cobalt Strike payload.

The bitsadmin option downloads and runs an executable. The python option will download and run a Python script that injects Beacon into the current python process. The regsvr32 option uses a combination of an SCT file with VB Script and a VBA macro to inject Beacon into memory. The regsvr32 option is based on research by Casey Smith and I really didn’t appreciate the power of this until I played with it more.

Search and Filter Tables with Ctrl+F

This release adds Ctrl+F to tables. This feature allows you to filter the current table on a column-by-column basis. Even when this feature is active, updates to the table will still show in real-time, if they match your criteria.

The feature is built with special search syntax for different column types. For example, you can specify CIDR notation or address ranges to filter host columns. You can use ranges of numbers to filter number columns. And, you can use wildcard characters in string columns.


*phew*. That’s a lot. Would you believe there’s more? Check out the release notes to see a full list of what’s new in Cobalt Strike 3.3. Licensed users may use the update program to get the latest. A 21-day Cobalt Strike trial is also available.


  1. Well-timed release of these features. Recently attended a defender’s talk that made fun of Cobalt Strike and how easy it has been to catch. Hopefully users of your platform will recognize the need for these techniques for stealth and for control bypass. For example, powerpick was intended to also be a way to wiggle (i.e., lockpick) into a system protected with AppLocker. regsvr32 is another method intended to bypass app whitelisting. bitsadmin may appear to sysadmins that a Windows host is merely updating, which bypasses software firewalls (all whitelist it by default for obvious reasons) — but bitsadmin can also be used to download executables or exfiltrate data. Welcome these excellent additions!

  2. Congrats for releasing new CS !

    I know this is out of topic but today I tried and failed at bypassuac from within beacon on Windows 10 machine (had local admin RID 500 access but in medium integrity level). CS version was 3.2. Is it possible to bypass UAC in this scenario using CS 3.3 beacon ? I don’t have access to CS 3.3 at the moment (and thus am posting this).

    Thanks in advance

    • I’d give 3.3 a try. I significantly reworked Bypass UAC in 3.3 for this exact reason. The causes of failure were… interesting.

      1. Prior to 3.3, Beacon executed the Bypass UAC attack from an x86 context. To deal with x64 Windows, I would disable the WOW64 file system redirection. This step fails in some contexts though. For example, I’ve seen this step fail when Beacon lives in an x86 powershell.exe context with an x64 powershell.exe parent. The remediation here was to port the Bypass UAC attack to a Beacon post-exploitation job module. Beacon’s post-exploitation job launcher transparently deploys x64 modules on x64 systems.

      Bonus: The UAC attack now provides feedback.

      2. Cobalt Strike uses a different DLL artifact for UAC bypass on Windows 10 versus other versions of Windows. The alternate UAC artifact has the constraint that it cannot block DllMain. This will cause the attack to fail on Windows 10. Easy enough, right? On Windows 10 the GetVersionEx function lies about the Windows version if it’s called from a process that is not manifested for Windows 8.1 or Windows 10. This leads to very inconsistent results. If Beacon is run via a PowerShell one-liner, it will report itself as Windows 10. If Beacon is run via an executable, it will report itself as Windows 8.1. This broke my logic to choose the right artifact and led to a situation where this attack would fail on Windows 10 as well. I mitigated this in 3.3.

      The above are fresh in my head as I was able to zero in on these conditions very recently (8pm last night).

      • I just tested the scenario with CS 3.3 and confirm that it works fine on Win10 (i.e. got high mandatory level) !
        Great job!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s