0x00 序列化与反序列化
什么是序列化和反序列化
序列化是一个用于将对象状态转换为字节流的过程,可以将其保存到磁盘文件中或通过网络发送到任何其他程序;从字节流创建对象的相反的过程称为反序列化。
为什么要序列化和反序列化
类的对象会随着程序的终止而被垃圾收集器销毁。如果要在不重新创建对象的情况下调用该类,就需要通过序列化将数据转换为字节流进行存储或者传输,在合适的地方通过对字节流反序列化继续调用该类。而创建的字节流是与平台无关的,在一个平台上序列化的对象可以在不同的平台上反序列化。
如何进行序列化和反序列化
通过ObjectOutputStream
类的writeObject(Object obj)
方法可以实现序列化。
通过ObjectInputStream
类的readObject(Object obj)
方法可以实现发序列化。
一个类的对象要想序列化成功,需要满足两个条件:
- 该类必须实现
java.io.Serializable
接口。
- 该类必须实现
- 该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。
下面使用一个Demo来演示该过程。
一个满足上述序列化条件的任意类
1 | class Student implements Serializable { |
序列化Demo
1 | import java.io.*; |
通过上面的序列化Demo,将序列化后的字节流保存在了object.ser
文件中。
查看该文件,可以看到序列化特征头AC ED 00 05
然后写一个反序列化Demo,将上面的字节流文件还原为对象。
1 | import java.io.*; |
运行后输出
1 | Student@b815859 |
0x01 反序列化漏洞
在java反序列化的过程中,会调用反序列化类的readObject()
方法,如果该方法书写不当,将会产生反序列化漏洞。
我们对上面的Student
类稍加修改,重写其readObject()
方法。
1 | class Student implements Serializable { |
使用之前的代码,对该类重新进行序列化反序列化后,将会运行readObject
方法里的命令,弹出计算器。
此时在序列化时将cmd
赋值为任意命令,便可以执行任意命令。
当然,这仅仅是一个测试的Demo,真实的代码中可能并不会出现如此低级的问题,但在真实环境中,可以通过一些列的调用代码链,最终达到上述Demo所实现的执行任意命令的效果。下面引入一个实例: Apache Commons Collections反序列化漏洞。
0x02 Apache Commons Collections反序列化漏洞
Apache Commons Collections 是一个扩展了Java标准库里的Collection结构的第三方基础库。它包含有很多jar工具包,提供了很多强有力的数据结构类型并且实现了各种集合工具类。 WebLogic、WebSphere、JBoss、Jenkins、OpenNMS等均使用了该第三方库。
在2015年11月6日FoxGlove Security安全团队的@breenmachine公布了Apache Commons Collections配合java反序列化漏洞实现远程命令执行的真实案例,使用了该库的各大java Web Server都受到影响。
首先搭建漏洞环境,在web.xml
中添加以下配置获取受影响的commons-collections
版本。
1 | <dependency> |
Commons Collections
中实现了对Java标准数据结构Map接口的一个扩展类TransformedMap
。 该类可以在一个元素被加入到集合内时,自动对该元素进行特定的修饰变换, 具体的变换逻辑由Transformer类定义 。
查看Transformer
接口类的具体实现,其问题出现在InvokerTransformer
类。
查看InvokerTransformer
类实现的transform
方法, 该方法中采用了反射的方法进行函数调用,其中的参数均为可控参数,因为可控制该方法实现任意代码执行。
那么现在可以通过 可以通过TransformedMap.decorate()
方法,获得一个TransformedMap
的实例。 当该实例内的key 或者 value发生变化时,就会触发相应的Transformer的transform()方法,执行任意命令。
现在进行Demo测试。
1 | public class POC_Test implements Serializable{ |
成功弹出计算器
现在想要在反序列化中进行利用,需要在readObject
方法中对Map进行其value
值的改变,我们修改上面的Student
类,使其满足我们这一美好的愿望。
1 | class Student implements Serializable { |
然后构造利用poc
1 | public class SerTest { |
成功请求到url
但是对于这样我们理想的Student
类还是不够通用,那么有没有具备这么理想的条件,即在readObject
方法中有对Map
类型进行setVlalue
操作的理想类,而且又能够通用的类呢?
回答是肯定的,这个类就是AnnotationInvocationHandler
。其位置在sun.reflect.annotation.AnnotationInvocationHandler
。
这样一来,Commons Collections Java反序列化漏洞的通用Poc便出来了
1 | public class POC_Test implements Serializable{ |
0x03 ysoserial
ysoserial
是集合了各种java反序列化payload的一个java反序列化工具。项目地址 https://github.com/frohoff/ysoserial
使用ysoserial
可以快速构建上面的payload
1 | java -jar ysoserial-0.0.6-SNAPSHOT-BETA-all.jar CommonsCollections1 "curl 127.0.0.1/ysoserial_test" |xxd |
成功执行命令
0x04 参考链接
https://www.cnblogs.com/lsdb/p/9830363.html
https://www.cnblogs.com/he1m4n6a/p/10131566.html