7. Other Topics

The Event Log

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 Attacks -> Web Drive-by -> 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, "");


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:

A scripted dialog.

A scripted dialog.