Java反序列化

定义

深入理解JAVA反序列化漏洞

  • 序列化 :把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)。(不太懂,我得再想想)

POP Gadgets

防御

  • 如何发现反序列化漏洞

    1. 从流量中发现序列化的痕迹,关键字:ac ed 00 05,rO0AB
    2. Java RMI 的传输 100% 基于反序列化,Java RMI 的默认端口是1099端口
    3. 从源码入手,可以被序列化的类一定实现了Serializable接口
    4. 观察反序列化时的readObject()方法是否重写,重写中是否有设计不合理,可以被利用之处
  • 防范

    1. String obj2=(String)ois.readObject();这种方法并不能奏效,应为强制转换为string之前readObject()函数就已经运行完毕
    2. 类白名单校验:在 ObjectInputStream 中 resolveClass 里只是进行了 class 是否能被 load ,自定义 ObjectInputStream , 重载 resolveClass 的方法,对 className 进行白名单校验
    3. 禁止 JVM 执行外部命令 Runtime.exec