定义
- 序列化 :把Java对象转换为字节序列的过程便于保存在内存、文件、数据库中,ObjectOutputStream类的writeObject()方法可以实现序列化。
- 反序列化:是指把字节序列恢复为Java对象的过程,ObjectInputStream类的readObject()方法用于反序列化。
序列化与反序列化是让Java对象脱离Java运行环境的一种手段,可以有效的实现多平台之间的通信、对象持久化存储。主要应用在以下场景:
HTTP:多平台之间的通信,管理等
RMI:远程方法调用(Remote Method Invocation),让在某个java虚拟机上的对象像调用本地对象一样调用另一个java虚拟机中的对象上的方法。RMI的传输100%基于反序列化,默认端口是1099。
JMX:Java Management Extensions,让程序有被管理的功能,中间件软件WebLogic的管理页面就是基于JMX开发的,而JBoss则整个系统都基于JMX构架。
JDNI(Java Naming and Directory Interface):提供了查找和访问各种命名和目录服务的通用、统一的接口,支持的对象有DNS、LDAP、 CORBA 对象服务、RMI 等。简单的来说就是RMI注册的服务可以让 JNDI 应用程序来访问,调用。
漏洞历史
-
15年的Apache Commons Collections 反序列化远程命令执行漏洞,其当初影响范围包括:WebSphere、JBoss、Jenkins、WebLogic 和 OpenNMSd等。
-
2016年Spring RMI反序列化漏洞今年比较出名的:Jackson,FastJson
漏洞成因
-
POP(property-oriented programming): 控制对象属性然后用它们去影响代码的运行流程。POP gadget就像是高级的ROP,POP组件是在文件中写入数据。
-
反序列化的exp并不会直接发送代码让服务器去执行,只是发送
服务器已知的类的属性
,然后去操纵那些已经存在的代码以处理这些恶意属性。
入口点
-
序列化对象以
ac ed
开始,是magic number。接下来是00 05
,为版本号。接下来应该是0x70到0x7E之间的数,用于描述内容元素的类型,详情见Object Serialization Stream Protocol -
很多IDS靠
0xAC ED 00 05
为特征码来判断序列化数据流,但是这几个字节仅出现在最初的序列化传输流里面。 -
最显著的特征是在数据流里面会有java的类名,如
java.rmi.dgc.Lease
,有的形式可能是Ljava/rmi/dgc/VMID;’
。除了类名,还有一些常见的字符串,如sr
可能会代表一个对象(TC_OBJECT),紧跟着对应的类描述(TC_CLASSDESC)。xp
代表类注释的结束(TC_ENDBLOCKDATA),并且此类没有super class(TC_NULL)。(不太懂,我得再想想)
- 序列化对象读取工具:SerializationDumper
POP Gadgets
防御
-
如何发现反序列化漏洞
- 从流量中发现序列化的痕迹,关键字:ac ed 00 05,rO0AB
- Java RMI 的传输 100% 基于反序列化,Java RMI 的默认端口是1099端口
- 从源码入手,可以被序列化的类一定实现了Serializable接口
- 观察反序列化时的readObject()方法是否重写,重写中是否有设计不合理,可以被利用之处
-
防范
String obj2=(String)ois.readObject();
这种方法并不能奏效,应为强制转换为string
之前readObject()函数就已经运行完毕- 类白名单校验:在 ObjectInputStream 中 resolveClass 里只是进行了 class 是否能被 load ,自定义 ObjectInputStream , 重载 resolveClass 的方法,对 className 进行白名单校验
- 禁止 JVM 执行外部命令 Runtime.exec