为什么这个漏洞影响如此之大,却依然让人防不胜防?
2.2 什么是序列化、反序列化?
序列化: 将内存对象转化为可以存储以及传输的二进制字节、xml、json、yaml 等格式。
反序列化: 将虚化列存储的二进制字节、xml、json、yaml 等格式的信息重新还原转化为对象实例。
数据格式 | 序列化后的信息样例 |
---|---|
二进制 |
在这里插入图片描述 |
|
| xml
|
|
| json
| {“name”:“ACGkaka”,“age”:20} |
| yaml
| !!com.demo.user.Person {age: 20, name: ACGkaka}\n |
补充:Java 对象序列化为二进制
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/\*\*
\* Java 对象序列化为二进制
\*/
public class Test {
public static void main1(String[] args) {
Person obj = new Person("ACGkaka", 20);
try {
FileOutputStream fileOut = new FileOutputStream("D:\\object.bin");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(obj);
out.close();
fileOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.3 序列化/反序列化库
如果想将对象序列化为二进制格式(或者反序列化为对象),直接使用 JDK
自带的 ObjectOutputStream
的 readObject
、writeObject
方法即可。如果想与其他格式(xml、json、yaml)相互转换,一般需要引入 jackson
、snakeyaml
等其他开源组件,使用开源组件中提供的库方法。
库名称 | 序列化支持的格式 |
---|---|
jdk | 二进制、xml |
xstream | xml、json |
jackson | xml、json |
fastjson | json |
gson | json |
json-io | json |
flexson | json |
snakeyaml | yaml |
2.4 反序列化漏洞
我们需要明确的一点是:Java 的序列化和反序列化本身并不存在问题,但如果 Java 应用对用户的输入,即不可信数据做了反序列化处理,那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,而非预期的对象在产生过程中就有可能带来任意代码执行的后果。
所以,这个问题的根源在于类 ObjectInputStream 反序列化时,没有对生成的对象类型做限制。正因如此,Java 提供的标准库及大量第三方公共类库成为反序列化漏洞利用的关键。
三、漏洞复现:攻击链1
3.1 依赖版本
JDK版本: 1.8.0_60
commons-collections版本: 3.2.1(从 3.2.2 开始增加了安全校验,需要手动设置 System.setProperty(“org.apache.commons.collections.enableUnsafeSerialization”, “true”);)
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
3.2 代码复现
import com.alibaba.fastjson2.JSON;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalu