详解Java反序列化漏洞( 二 )

//unserialize.javapackage com.n0tai1.java.serialize;import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectInputStream;import com.n0tai1.java.serialize.Student;public class unserialize{public static void main(String[] args) throws IOException,ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(newFileInputStream("I:\project\Java\JavaSePro\src\flag.txt")); Object obj = ois.readObject();System.out.println(obj);ois.close(); }}现在已经知道如何序列化和反序列化了,我们把刚刚写的弹计算器代码序列化处理一下
package com.n0tai1.java.serialize;import com.n0tai1.java.serialize.ExecTest; import java.io.FileOutputStream;import java.io.ObjectOutputStream;public class Serializable{public static void main(String[] args) throws Exception {ExecTest s = new ExecTest();s.ExecTest();ObjectOutputStream oos = new ObjectOutputStream(newFileOutputStream("I:\project\Java\JavaSePro\src\serialize.txt")); oos.writeObject(s);oos.flush();oos.close(); }}package com.n0tai1.java.serialize;import java.io.Serializable;public class ExecTest implements Serializable {public void ExecTest() throws Exception{} }Class c = Class.forName("java.lang.Runtime");Object obj = c.getMethod("getRuntime", null).invoke(null); String[] n0tai1 = {"calc.exe"}; c.getMethod("exec",String.class).invoke(obj,n0tai1);//unserialize.javapackage com.n0tai1.java.serialize;import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectInputStream;import com.n0tai1.java.serialize.ExecTest;public class unserialize{public static void main(String[] args) throws IOException,ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(newFileInputStream("I:\project\Java\JavaSePro\src\serialize.txt")); Object obj = ois.readObject();System.out.println(obj);ois.close(); }}但是这样测试后发现,反序列操作后,不能弹出计算器吗,因为Runtime类并没有实现 Serializable接口
commons-collections3.1源码分析
漏洞组件
:https://mvnrepository.com/artifact/commons-collections/commons-collections/3.1
参考链接
:https://security.tencent.com/index.php/blog/msg/97
我们直接入正题

详解Java反序列化漏洞

文章插图
 
我们可以通过
Map tansformedMap = TransformedMap.decorate(map,keyTransformer,valueTransformer)来获得一个TransformedMap类的实例进而调用到TransformedMap的构造方法
详解Java反序列化漏洞

文章插图
 
这里会调用到super(map),会调用到基类的有参构造
详解Java反序列化漏洞

文章插图
 
继续调用基类有参构造
详解Java反序列化漏洞

文章插图
 
TransformedMap.decorate会对map类的数据结构进行转化
TransformedMap.decorate方法,预期是对Map类的数据结构进行转化,该方法有三个参数 。第一个参数为待转化的Map对象第二个参数为Map对象内的key要经过的转化方法(可为单个方法,也可为链,也可为空)第三个参数为Map对象内的value要经过的转化方法我们看今天的第一个主角ChainedTransformer.class,我们可以创建一个Transformer类型的数组,构造出ChainedTransformer,当触发的时候ChainedTransformer可以将闲散的数据组合
详解Java反序列化漏洞

文章插图
 
我们看今天的第二个主角InvokerTransformer.class,我们可以给创建一个Transformer类型的数组, 然后对InvokerTransformer进行实例化
详解Java反序列化漏洞

文章插图
 
可以看到:
InvokerTransformer的transform中出现了 getMethod().invoke() 这种形式的代码,我们 如果可以控制传参,就可以RCE
那我们如何调用到InvokerTransformer和ChainedTransformer的transform呢?
这里我们需要用到:
AbstractInputCheckedMapDecorator下MapEntry下的setValue
详解Java反序列化漏洞

文章插图
 

详解Java反序列化漏洞

文章插图
 

详解Java反序列化漏洞

文章插图
 
只要让iTransformers[i]为InvokerTransformer这个类的对象就可以调用到InvokerTransformer的transform
那我们如何触发呢? 在进行反序列化的时候我们会调用ObjectInputStream类的readObject()方法,如果反序列化类被重写


推荐阅读