JLable解析html的安全问题

JLabel 的内容可以输入 HTML 格式,例如下方的 Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package me.n1ar4;

import javax.swing.*;

public class Main {
private static void createAndShowGUI() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String inputFromUser = "<html><h1>hello</h1><h2>world</h2></html>";
JLabel label = new JLabel(inputFromUser);
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(Main::createAndShowGUI);
}
}

可以查看源码里面的注释,这里面简要说明了html里面支持的标签,其中object标签可以加载对象,可以调用newInstance(),要求对象必须有无参构造函数,同时可以设置参数,参数类型必须为String

image-20230911170041389

在可以加载html的条件下,会初始话对象并调用setter,这里存在一个符合条件的sink

需要满足版本要求batik-swing<=1.15

org.apache.batik.swing.JSVGCanvas#setURI 该方法用于设置一个 SVG URI 并加载

1
2
3
4
5
6
7
8
9
10
11
public void setURI(String newURI) {
String oldValue = this.uri;
this.uri = newURI;
if (this.uri != null) {
this.loadSVGDocument(this.uri);
} else {
this.setSVGDocument((SVGDocument)null);
}

this.pcs.firePropertyChange("URI", oldValue, this.uri);
}

这里可以通过加载恶意Jar和js来rce,参考漏洞CVE-2022-41704,CVE-2022-42890

关于ObjectInputValidation

在 Java 序列化过程中,对象可以通过网络发送或持久化到磁盘上。在接收或恢复这些对象时,为了确保数据的完整性和安全性,需要对对象进行验证,以防止恶意攻击或数据损坏

ObjectInputValidation 接口定义了一个名为 validateObject() 的方法,该方法在对象反序列化过程中被调用。通过实现这个接口并提供相应的验证逻辑,开发人员可以定义对象的验证规则

当对象被反序列化时,Java 虚拟机会在反序列化完成之前调用 validateObject() 方法。如果对象未通过验证,validateObject() 方法将抛出一个 InvalidObjectException 异常,从而阻止对象被完全恢复

通过使用 ObjectInputValidation 接口,开发人员可以确保反序列化过程中对象的有效性,从而提高应用程序的安全性和可靠性

在 ObjectInputStream 中可以看到 doCallBacks 方法,其中包含了 obj.validateObject 方法。这是 Java 原生反序列化中的一个流程

image-20230911163430543

接着会触发validateObject()方法

image-20230911163503535

而这里要利用的正是JComponent的validateObject()方法,

image-20230911163807626

这里调用到了updateComponentTreeUI,其中的参数可以传入一个JLable

image-20230911163924613

继续跟进

image-20230911172059075

如果是JComponent就可以继续进入updateUI

image-20230911172154082

最终进入javax.swing.plaf.basic.BasicHTML#updateRenderer中,解析html代码可以触发漏洞

image-20230911172519541

总体的调用栈如下

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
setURI:525, JSVGCanvas (org.apache.batik.swing)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect) [2]
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:71, Trampoline (sun.reflect.misc)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect) [1]
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:275, MethodUtil (sun.reflect.misc)
setParameters:157, ObjectView (javax.swing.text.html)
createComponent:100, ObjectView (javax.swing.text.html)
setComponentParent:291, ComponentView (javax.swing.text)
run:263, ComponentView$1 (javax.swing.text)
dispatch$$$capture:311, InvocationEvent (java.awt.event)
dispatch:-1, InvocationEvent (java.awt.event)
- 异步堆栈跟踪
<init>:284, InvocationEvent (java.awt.event)
<init>:171, InvocationEvent (java.awt.event)
invokeLater:1295, EventQueue (java.awt)
invokeLater:1295, SwingUtilities (javax.swing)
setParent:276, ComponentView (javax.swing.text)
replace:217, CompositeView (javax.swing.text)
loadChildren:114, CompositeView (javax.swing.text)
loadChildren:701, FlowView$LogicalView (javax.swing.text)
setParent:139, CompositeView (javax.swing.text)
loadChildren:139, FlowView (javax.swing.text)
setParent:139, CompositeView (javax.swing.text)
setParent:289, FlowView (javax.swing.text)
setParent:75, ParagraphView (javax.swing.text.html)
replace:217, CompositeView (javax.swing.text)
replace:181, BoxView (javax.swing.text)
loadChildren:114, CompositeView (javax.swing.text)
setParent:139, CompositeView (javax.swing.text)
setParent:72, BlockView (javax.swing.text.html)
setParent:1327, HTMLEditorKit$HTMLFactory$BodyBlockView (javax.swing.text.html)
replace:217, CompositeView (javax.swing.text)
replace:181, BoxView (javax.swing.text)
loadChildren:114, CompositeView (javax.swing.text)
setParent:139, CompositeView (javax.swing.text)
setParent:72, BlockView (javax.swing.text.html)
<init>:410, BasicHTML$Renderer (javax.swing.plaf.basic)
createHTMLView:68, BasicHTML (javax.swing.plaf.basic)
updateRenderer:208, BasicHTML (javax.swing.plaf.basic)
installComponents:382, BasicLabelUI (javax.swing.plaf.basic)
installUI:344, BasicLabelUI (javax.swing.plaf.basic)
setUI:660, JComponent (javax.swing)
setUI:261, JLabel (javax.swing)
updateUI:275, JLabel (javax.swing)
updateComponentTreeUI0:1238, SwingUtilities (javax.swing)
updateComponentTreeUI:1229, SwingUtilities (javax.swing)
validateObject:5414, JComponent$ReadObjectCallback (javax.swing)
run:2723, ObjectInputStream$ValidationList$1 (java.io)
run:2721, ObjectInputStream$ValidationList$1 (java.io)
doPrivileged:-2, AccessController (java.security)
doCallbacks:2719, ObjectInputStream$ValidationList (java.io)
readObject:515, ObjectInputStream (java.io)
readObject:466, ObjectInputStream (java.io)
deserialize:20, SerUtil (me.n1ar4.exploit)
main:24, JarRCE (me.n1ar4.exploit)

经过调试后可以发现,序列话时也会走入这个流程,其原因是JLable重写了writeObject,其中会调用到installUI

image-20230911173038724

调用栈如下

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
setURI:525, JSVGCanvas (org.apache.batik.swing)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:71, Trampoline (sun.reflect.misc)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:275, MethodUtil (sun.reflect.misc)
setParameters:157, ObjectView (javax.swing.text.html)
createComponent:100, ObjectView (javax.swing.text.html)
setComponentParent:291, ComponentView (javax.swing.text)
run:263, ComponentView$1 (javax.swing.text)
dispatch$$$capture:311, InvocationEvent (java.awt.event)
dispatch:-1, InvocationEvent (java.awt.event)
- 异步堆栈跟踪
<init>:284, InvocationEvent (java.awt.event)
<init>:171, InvocationEvent (java.awt.event)
invokeLater:1295, EventQueue (java.awt)
invokeLater:1295, SwingUtilities (javax.swing)
setParent:276, ComponentView (javax.swing.text)
replace:217, CompositeView (javax.swing.text)
loadChildren:114, CompositeView (javax.swing.text)
loadChildren:701, FlowView$LogicalView (javax.swing.text)
setParent:139, CompositeView (javax.swing.text)
loadChildren:139, FlowView (javax.swing.text)
setParent:139, CompositeView (javax.swing.text)
setParent:289, FlowView (javax.swing.text)
setParent:75, ParagraphView (javax.swing.text.html)
replace:217, CompositeView (javax.swing.text)
replace:181, BoxView (javax.swing.text)
loadChildren:114, CompositeView (javax.swing.text)
setParent:139, CompositeView (javax.swing.text)
setParent:72, BlockView (javax.swing.text.html)
setParent:1327, HTMLEditorKit$HTMLFactory$BodyBlockView (javax.swing.text.html)
replace:217, CompositeView (javax.swing.text)
replace:181, BoxView (javax.swing.text)
loadChildren:114, CompositeView (javax.swing.text)
setParent:139, CompositeView (javax.swing.text)
setParent:72, BlockView (javax.swing.text.html)
<init>:410, BasicHTML$Renderer (javax.swing.plaf.basic)
createHTMLView:68, BasicHTML (javax.swing.plaf.basic)
updateRenderer:208, BasicHTML (javax.swing.plaf.basic)
installComponents:382, BasicLabelUI (javax.swing.plaf.basic)
installUI:344, BasicLabelUI (javax.swing.plaf.basic)
writeObject:915, JLabel (javax.swing)
invoke0:-2, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeWriteObject:1155, ObjectStreamClass (java.io)
writeSerialData:1496, ObjectOutputStream (java.io)
writeOrdinaryObject:1432, ObjectOutputStream (java.io)
writeObject0:1178, ObjectOutputStream (java.io)
writeObject:348, ObjectOutputStream (java.io)
serialize:12, SerUtil (me.n1ar4.exploit)
main:22, JarRCE (me.n1ar4.exploit)

Reference

https://mp.weixin.qq.com/s/-Rdkv1WmYrjNWhZZK3pj6w