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.
NOTE: 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 sleepy.py to generate the needed Sleep commands expected by the agscript console. Instead of writing the Sleep functions, striker.py 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.
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.
beaconlogtracker.py 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:
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.
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.
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.
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:
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.
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 (https://github.com/xforcered/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)
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 (https://twitter.com/jsecurity101) to add context to the detection story of this technique, seen below in the Detection Opportunities section.
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.
Launch a beacon running in context with the necessary permissions (i.e., high integrity process running as administrator)
Locate the PID of LSASS
Wait …. 🙂
Convert the CredBandit output into a usable dump
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 cleanupMiniDump.sh 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:
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:
This minidump file is rebuilt using the script cleanupMiniDump.sh. 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 (https://github.com/outflanknl/FindObjects-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!
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 (https://twitter.com/jsecurity101) 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
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.
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
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.
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
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.
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.
$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 => "stage.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 => "b1.host,b2.host", # Comma separated list of beacon hosts
althost => "alt.host", # 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@example.com:8080" # Proxy host settings
This aggressor script will create a listener that looks like this in the GUI.
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.
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.
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.
I use simple bash script that is basically a wrapper to the AWS CLI to provision the needed AWS Lightsail resources (you could use terraform or ansible as well)
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.
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.
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.
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.
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.
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!