长亭百川云 - 文章详情

[新年特刊-初二篇]CS插件开发

Security丨Art

49

2024-07-13

开章废话

cs的插件在日常的工作中相对来说并不常用,因为cs基本只能当炮灰马上线的工具,主要是用cs过内存特征也太费劲了(菜狗难受),我相信在每一个渗透狗的心中,每个能给cs木马过内存特征过卡巴的大佬都是渗透狗的大爹。所以基本上更多的操作自己也不会选择使用cs,所以只是总结一下算是查漏补缺吧

废话结束,正文开始

语法基础

sleep按作者的说法是java平台下实现的的perl脚本语言。

java \-jar sleep.jar #打开console

官方的语法在这里(http://sleep.dashnine.org/manual/),有过python或其他语言基础的写的时候看一下再看下其他师傅写的脚本基本上没啥问题,稍微提几个注意的点

  • 在console中用x可以计算表达式(x 3+4),用?可以得到表达式判断结果

  • Sleep需要的语句之间需要有空格

  • Sleep 的变量可以是java对象的引用

  • 使用前无需声明变量。当变量不存在时,Sleep 使用 $null(空标量)赋值

  • @号创建数组,%号创建字典,Sleep支持多维数组

  • $null 等于数字 0。作为字符串 $null 等于空字符串 ""。作为对象,$null 与 Java 值 null 相同。

  • Perl支持8进制、16进制、2进制(0b),但Sleep只支持8进制(0开头)和16进制(0x开头)

  • 字符串变量组合用双引号和$xx $ ,eg.$flavor = "mint chocolate chip"; println("I love $flavor $+ !!!");

  • 数字用计算符号比较(==,>,<,..),字符串用eq、ne等等比较,is用来比较引用

  • 函数用sub声明

  • 循环支持while、for、foreach

  • 可以使用throw抛出异常,也可以使用try catch处理异常,&getStackTrace 函数返回异常发生时的调用堆栈,&warn 函数将错误消息传达给 Sleep。可以用assert关键字断言

  • 使用inline定义内联子例程的宏,可以使用 &pushl 在内联函数中创建一个新的本地作用域。然后,您可以放心地在本地范围内声明变量。在内联子例程完成之前,您必须使用 &popl 处理局部作用域。

inline swap  
{  
   pushl($a \=> $1, $b \=> $2);  
  
   local('$temp');  
   $temp \= $b;  
   $b \= $a;  
   $a \= $temp;  
  
   popl();  
}
  • Sleep可以使用匿名函数
\[{ println("Hello $1 $+ !"); } : "World!"\];

或使用lamba表达式

$closure \= lambda({  
              println("\\$x is $x");  
           }, $x \=> 33);  
  
\[$closure\];   
  
$closure\['$x'\] \= "test!";  
\[$closure\];  
  
println("Accessing a value: " . $closure\['$x'\]);
  • Sleep支持正则匹配

  • ^String 等同于 [Class forName: "java.lang.String"]

  • Sleep 可以从 Java 类路径中当前不存在的 jar 文件中动态导入包

  • Sleep 可以将闭包转换为响应某些接口的匿名 Java 对象。这个对象是一个代理实例。解释器在将它们传递给 Java 时自动将闭包编组到代理实例。此功能目前仅适用于接口。对代理实例的 Java 方法调用会导致对闭包的调用。参数 $0 设置为方法名称。来自 Java 的参数被转换为标量 $1、$2 等。这一特性将在后续插件编写过程中频繁使用

  • Sleep实现了文件IO、文件系统IO、网络IO和consoleIO、ThreadsIO

CS接口

一些cs插件开发的文章开头通用这里都介绍过了,看过的师傅可以直接往后划,看过之后对cs接口实现的功能有一个大概的印象,具体到调用函数时直接搜索函数名称查下参数就好

cs函数的实现本质是对java代理实例的调用,第一个参数$0默认为方法名称,我们传入的参数$1,$2....是java方法所需的参数。

通用

  • 快捷键
bind Ctrl+H {  
   show\_message("Hello World!");  
}
  • 目录
popup pgraph {  
   menu "&Layout" {  
      item "&Circle"    { graph\_layout($1, "circle"); }  
      item "&Stack"     { graph\_layout($1, "stack"); }  
      menu "&Tree" {  
         item "&Bottom" { graph\_layout($1, "tree-bottom"); }  
         item "&Left"   { graph\_layout($1, "tree-left"); }  
         item "&Right"  { graph\_layout($1, "tree-right"); }  
         item "&Top"    { graph\_layout($1, "tree-top"); }  
      }  
      separator();  
      item "&None" { graph\_layout($1, "none"); }  
   }  
}
  • 自定义输出
set EVENT\_SBAR\_LEFT {  
   return "\[" . tstamp(ticks()) . "\] " . mynick();  
}  
   
set EVENT\_SBAR\_RIGHT {  
   return "\[lag: $1 $+ \]";  
}
  • 事件
on ready {  
   show\_message("Ready for action!");  
}  
  
on \* {  
   local('$handle $event $args');  
   
   $event \= shift(@\_);  
   $args  \= join(" ", @\_);  
   
   $handle \= openf(">>eventspy.txt");  
   writeb($handle, "\[ $+ $event $+ \] $args");  
   closef($handle);  
}

数据接口

使用data_query函数可以查看数据类型,使用data_key列出来自Cobalt Strike的数据模型的可查询键

,这边可以看下官方实例就可以看出cs的target数据模型就是Sleep字典数组

listener api

  • listeners :函数获取所有的listener,

  • listener_local:返回当前server的listener

  • listener_create_ext:启动listener

  • openPayloadHelper :打开一个对话框,列出所有可用的侦听器

  • stager:导出绑定了cs payload的stager

  • artifact_stager:可以导出绑定了cs payload的ps脚本、EXE、或dll

  • stager_bind_tcp:绑定tcp的stager

  • beacon_stage_tcp:向stager_bind_tcp传递payload

  • artifact_general:接收shellcode并产生payload

  • stager_bind_pipe :stager仅支持x86

  • beacon_stage_pipe:向 stager_bind_pipe传递payload

  • payload:将payload导出为可运行二进制文件

beacon

Cobalt Strike 为每个 Beacon 分配一个会话 ID。这个 ID 是一个随机数。Cobalt Strike 将任务和元数据与每个 Beacon ID 相关联

  • beacons查询所有当前 Beacon 会话的元数据

  • beacon_info查询特定 Beacon 会话的元数据

  • alias 设置别名

  • beacon_initial 事件在 Beacon 第一次报告元数据时触发

  • beacon_initial_empty 与首次呼叫 home 的 DNS Beacon交互

  • btask:向用户确认操作

  • beacon_host_script:托管大型脚本

  • bdllspawn 函数生成一个临时进程,将我们的漏洞利用 DLL 注入其中,并将我们导出的payload作为参数传递

  • beacon_remote_exec_method_register:尝试远程执行命令

  • bupload_raw函数将工件数据上传到目标。此函数使用**\target\ADMIN$\filename.exe**通过仅限管理员的共享直接将 EXE 写入远程目标

  • brun运行**wmic /node:"target" process call create "\target\ADMIN$\filename.exe"**以在远程目标上执行文件

  • bpowerpick:生成一个进程,注入 Unmanaged PowerShell并执行

事件

beacon\_checkin beacon准入确认发往console时触发  
beacon\_error beacon错误发布到console时触发  
beacon\_indicator  
beacon\_initial beacon第一次报告元数据时触发  
beacon\_initial\_empty 与首次呼叫 home 的 DNS Beacon交互时触发  
beacon\_input beacon传入信息发布到console时触发  
beacon\_mode 更改beacon模式时触发  
beacon\_output 输出发布到console时触发  
beacon\_output\_alt 当(备用)输出发布到 Beacon 的控制台时触发  
beacon\_output\_jobs当job输出发送到 Beacon 的控制台时触发。  
beacon\_output\_ls 当 ls 输出发送到 Beacon 的控制台时触发  
beacon\_output\_ps当 ps 输出发送到 Beacon 的控制台时触发  
beacon\_tasked 当task输出到console时触发  
beacons 当server发送有关我们所有信标的最新信息时触发。这大约每秒发生一次  
disconnect  cs客户端与cs服务端断开时触发  
event\_action当用户在事件日志中执行操作时触发  
event\_beacon\_initial当初始信标消息发布到事件日志时触发  
event\_join当用户连接到server时触发  
event\_newsite当新站点消息发布到事件日志时触发  
event\_notify当来自server的消息发布到事件日志时触发  
event\_nouser当前 Cobalt Strike 客户端尝试与未连接到server的用户交互时触发  
event\_private当private消息发布到事件日志时触发  
event\_public当public消息发布到事件日志时触发  
heartbeat\_\* 每隔\*时间触发一次  
keylogger\_hit当通过克隆站点击键记录器向 Web 服务器报告新结果时触发  
keystrokes当 Cobalt Strike 收到击键时触发  
profiler\_hit当有新的结果报告给 System Profiler 时触发  
ready当此 Cobalt Strike 客户端连接到server并准备好行动时触发  
screenshots当 Cobalt Strike 收到屏幕截图时触发  
sendmail\_\*发送钓鱼邮件过程中触发  
ssh\_\*同beacon,但session为ssh  
web\_hit 服务器有web访问时触发

其他函数

hasbootstraphint 是否有引导函数  
is64 是否是64位平台  
isactive 是否活动  
isadmin是否为管理员  
isssh 是否是  
show\_message向用户提示消息  
show\_error提示用户错误。  
dialog创建一个对话框  
drow\_file 文件输入对话框  
drow\_text 文本输入对话框  
drow\_combobox 选择栏对话框  
dialog\_show 显示对话框  
dbutton\_action 关闭对话框并调用对话框回调函数

更多函数见

https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics\_aggressor-scripts/as-resources\_functions.htm#dbutton\_action

实例分析

最后简单看一个实例,调用某程序上传到目标上并执行某命令,算是比较常见的需求了

https://github.com/422926799/csplugin/blob/master/%E5%8F%96%E8%AF%81/qz.cna  
  
sub recentqueryfunc{  
    $path \= script\_resource("openfilehistory.exe");  
    bupload($3\['bid'\], $path);  
    bshell($3\['bid'\], "openfilehistory.exe $3\['username'\]");  
}  
  
  
sub recentquery{  
    $dialog \= dialog("最近使用痕迹查询", %(username \=> "Administrator", bid \=> $id), &recentqueryfunc);  
    dialog\_description($dialog, "要查询的用户名输入");  
    drow\_text($dialog, "username", "USERNAME:");  
    dbutton\_action($dialog, "run");  
    dialog\_show($dialog);  
}  
  
popup beacon\_bottom {  
    menu "windows取证"{  
        $bid \= $1;   
        item "最近使用痕迹"{  
            foreach $id ($bid){  
                recentquery($id)  
            }  
        }  
}  
}

这里的bid就是我们的beacon id,原因是cs hook了不同的对象弹出并提供了参数变量

具体看这个表格

Hook

Where

Arguments

aggressor

Cobalt Strike Menu

attacks

Attacks Menu

beacon

[session]

$1 = selected beacon IDs (array)

beacon_top

[session]

$1 = selected beacon IDs (array)

beacon_bottom

[session]

$1 = selected beacon IDs (array)

credentials

Credential Browser

$1 = selected credential rows (array of hashes)

filebrowser

[file in file browser]

$1 = beacon ID, $2 = folder, $3 = selected files (array)

help

Help Menu

listeners

Listeners table

$1 = selected listener names (array)

pgraph

[pivot graph]

processbrowser

Process Browser

$1 = Beacon ID, $2 = selected processes (array)

processbrowser_multi

Multi-Session Process Browser

$1 = selected processes (array)

reporting

Reporting Menu

ssh

[SSH session]

$1 = selected session IDs (array)

targets

[host]

$1 = selected hosts (array)

targets_other

[host]

$1 = selected hosts (array)

view

View Menu

可以看到通过recentquery弹出对话框输入要查询的用户名后,调用回调函数recentqueryfunc,回调函数参数如下

$1是对对话框的引用。$2是按钮名称。$3是一个字典,将每一行的名称映射到它的值,所以在$3变量的字典中找到bid键的值,将文件上传到beacon上并执行

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2