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.

elog("system shutdown initiated");


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");


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.

prompt_text("What is your name?", "Joe Smith", {
   show_message("Please $1 $+ , pleased to meet you");

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");
$dialog = dialog("Host File", %(uri => "/download/file.ext", port => 80, mimetype => "automatic"), &callback);
dialog_description($dialog, "Host a file through Cobalt Strike's web server");
drow_file($dialog, "file", "File:");
drow_text($dialog, "uri",  "Local URI:");
drow_text($dialog, "host", "Local Host:", 20);
drow_text($dialog, "port", "Local Port:");
drow_combobox($dialog, "mimetype", "Mime Type:", @("automatic", "application/octet-stream", 
                       "text/html", "text/plain")); 
dbutton_action($dialog, "Launch");
dbutton_help($dialog, "https://www.cobaltstrike.com/help-host-file");

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.

Here's the dialog:

figure 75 - A scripted dialog.