一、基本概念

Java序列化:就是将内存中的Java对象转换为字节序列的过程,可以理解为对Java对象打个快照。通过序列化,可以方便将Java对象保存在内存、文件、数据库等媒介中,也便于在网络中传输和共享Java对象。

Java反序列化:就是Java序列化的逆过程,将字节序列恢复为Java对象的过程。

序列化/反序列化并不是Java语言的独有特性,像PHP、Python、Ruby等动态语言也有类似的特性。序列化/反序列化的主要目的是:

1、远程过程调用(RPC):为不同系统或不同进程之间提供Java对象数据交互;

2、缓存/持久化存储:可以将Java对象缓存或存储到本地文件、磁盘、数据库等媒介中;

3、会话tokens:用于HTTP cookies、HTML form表单参数、API 认证tokens等场景的交互数据。

在Java中,序列化/反序列化操作主要由 java.io.ObjectOutputStream.writeObject(Object) 方法和 java.io.ObjectInputStream.readObject()方法实现;在用户代码中,可以通过重写上述方法实现自定义操作。

Java序列化数据格式

参考文档:https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html

Java对象经过序列化后得到的数据是个二进制流,以固定的魔数(0xaced)和版本(0x0005)开始;在渗透测试过程中,可以以此来识别应用系统中反序列化的入口点。(0xaced 0005的base64编码以rO0AB开始,通常在Web应用系统中传输的Java序列化数据会经过base64编码)。

Java序列化数据示例:

00000000: aced 0005 7400 0d48 656c 6c6f 2c20 776f  ....t..Hello, wo
00000010: 726c 6421                                rld!

在Github上提供了Java对象序列化dump工具,可以对Java对象序列化后的数据进行解析,具体请参考:https://github.com/NickstaDB/SerializationDumper。例如,将上述二进制数据解析后的结果如下:

二、漏洞原理

Java反序列化漏洞产生的原因在于Java应用程序接收来自用户的序列化数据并尝试对其进行反序列化;如果攻击者通过构造恶意输入,让反序列化过程产生非预期的对象,将可能导致各种后果,严重时可能造成远程代码执行。

Java序列化/反序列化代码demo

下面代码演示将一段字符串经序列化保存到本地文件中,然后再从文件中恢复序列化的字符串。

package orz.vuln.poc;import java.io.FileOutputStream;
import java.io.ObjectOutputStream;//将String对象序列化后保存到data.ser文件中
public class Serialization {public static void main(String[] args) throws Exception {String text = "Hello, world!";FileOutputStream fos = new FileOutputStream("D:/data.ser");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(text);oos.close();fos.close();}
}

序列化后的数据:

package orz.vuln.poc;import java.io.FileInputStream;
import java.io.ObjectInputStream;//将data.ser文件中的数据反序列化为Java对象:
public class Deserialization {public static void main(String[] args) throws Exception {FileInputStream fis = new FileInputStream("D:/data.ser");ObjectInputStream ois = new ObjectInputStream(fis);String text = (String) ois.readObject();fis.close();ois.close();System.out.println(text);}
}

执行结果:

在这里,可以通过修改本地文件数据控制反序列化后的字符串的值;例如,将data.ser修改如下:

00000000: aced 0005 7400 0845 7669 6c54 6578 74    ....t..EvilText

执行反序列化代码,结果:

更进一步Java序列化/反序列化

在实际开发中,更多是通过实现Serializable接口并重写readObject()方法对自定义类对象进行反序列化,以完成更多操作。如下代码示例,我们通过自定义Test类,实现了Serializable接口,并重写readObject()方法,在readObject()方法中,我们自定义输出字符串“Oops…”和弹出计算器操作。

package orz.vuln.poc;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;public class DemoCode {public static void main(String[] args) throws Exception {Test test = new Test("calc.exe");FileOutputStream fos = new FileOutputStream("D:/object.ser");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(test);oos.close();fos.close();FileInputStream fis = new FileInputStream("D:/object.ser");ObjectInputStream ois = new ObjectInputStream(fis);Test test2 = (Test) ois.readObject();ois.close();}
}class Test implements Serializable {private String cmd;public Test(String cmd) {this.cmd = cmd;}//重写readObject()方法private void readObject(java.io.ObjectInputStream in) throws Exception {in.defaultReadObject();System.out.println("Oops...");java.lang.Runtime.getRuntime().exec(cmd);//触发代码执行,模拟调用链}
}

执行结果:

调用堆栈如下:

DemoCode [Java Application]  orz.vuln.poc.DemoCode at localhost:53445    Thread [main] (Suspended (entry into method exec in Runtime))   Runtime.exec(String) line: 345  Test.readObject(ObjectInputStream) line: 38 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  Method.invoke(Object, Object...) line: 601  ObjectStreamClass.invokeReadObject(Object, ObjectInputStream) line: 1004    ObjectInputStream.readSerialData(Object, ObjectStreamClass) line: 1891  ObjectInputStream.readOrdinaryObject(boolean) line: 1796    ObjectInputStream.readObject0(boolean) line: 1348   ObjectInputStream.readObject() line: 370    DemoCode.main(String[]) line: 22    D:\Tools\Java\jdk1.7.0_21\jre\bin\javaw.exe (2021年3月17日 下午5:13:24)

从上述结果可以看出,反序列化将调用重写的readObject()方法,执行了自定义的字符串输出和弹出计算器。如果重写的readObject()方法中可以构造出代码执行利用链,将存在远程代码执行漏洞。当然,在实际开发过程中不可能像上述代码一样直接在readObject()方法内部写上java.lang.Runtime.getRuntime().exec(cmd)这种代码;但是也差不太多,只是实际调用链比较复杂,通过控制反序列化的输入数据,结合Java反射调用机制,寻找可构建远程代码执行的调用链,动态调用java.lang.Runtime.getRuntime().exec()完成代码执行。

下面可以放一个JDK7u21反序列化漏洞的调用堆栈做个对比,只是调用过程更加复杂化:

orz.vuln.poc.JDK7u21Exploit at localhost:53452   Thread [main] (Suspended (entry into method exec in Runtime))   owns: TemplatesImpl  (id=46)   Runtime.exec(String) line: 345  EvilCodes.<init>() line: 17   NativeConstructorAccessorImpl.newInstance0(Constructor, Object[]) line: not available [native method]   NativeConstructorAccessorImpl.newInstance(Object[]) line: 57    DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 45    Constructor<T>.newInstance(Object...) line: 525   Class<T>.newInstance0() line: 374 Class<T>.newInstance() line: 327  TemplatesImpl.getTransletInstance() line: 380   TemplatesImpl.newTransformer() line: 410    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  Method.invoke(Object, Object...) line: 601  AnnotationInvocationHandler.equalsImpl(Object) line: 197    AnnotationInvocationHandler.invoke(Object, Method, Object[]) line: 59   $Proxy0.equals(Object) line: not available  LinkedHashMap<K,V>(HashMap<K,V>).put(K, V) line: 475    LinkedHashSet<E>(HashSet<E>).readObject(ObjectInputStream) line: 309    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  Method.invoke(Object, Object...) line: 601  ObjectStreamClass.invokeReadObject(Object, ObjectInputStream) line: 1004    ObjectInputStream.readSerialData(Object, ObjectStreamClass) line: 1891  ObjectInputStream.readOrdinaryObject(boolean) line: 1796    ObjectInputStream.readObject0(boolean) line: 1348   ObjectInputStream.readObject() line: 370    JDK7u21Exploit.main(String[]) line: 91

三、总结

Java反序列化漏洞的根源在于ObjectInputStream.readObject()方法在进行反序列化时并没有对生成的对象类型做检测和限制,并且当这种反序列化漏洞存在于一些公共类库中时,将造成重大影响。例如Apache Commons Collections中实现的一些类可以被反序列化用来实现任意代码执行。而在WebLogic、WebSphere、JBoss、Jenkins、OpenNMS这些应用的反序列化漏洞能够得以利用,就是因为这些应用中使用了Apache Commons Collections类库。这就好像在开启了ASLR地址随机化防御的系统中,出现了一个加载地址固定的共享库,或者类似于C语言中使用的链接库,当这些库存在漏洞时,将对使用了这些库的应用造成重大影响。

来自 https://www.freebuf.com/articles/web/266523.html

初探Java反序列化漏洞相关推荐

  1. java反序列化漏洞的一些gadget

    目录 0x00 URLDNS 0x01 Commons Collections 0x02 RMI的codebase任意代码执行 0x03 JNDI 0x04 LDAP 0x05 JDK7u21 首先说 ...

  2. java 反序列化漏洞 利用思路简介

    目录 序列化的过程 readObject方法 反射链 完成反序列漏洞实践 结论 之前听别人讲解反序列化的漏洞听的晕乎乎的,刚脆就趁着周末研究一下反序列化漏洞,并且搭建实战环境实际操作了一把,明白了之后 ...

  3. java 反序列化漏洞简介

    目录 一.Java的序列化与反序列化 二.对java序列化的理解 三.反序列化的漏洞原理概述 四.关于反射链 一.Java的序列化与反序列化 在这里我们直接自己定义一个类,然后对这个类的对象(一个实例 ...

  4. java序列化_技术干货 | JAVA反序列化漏洞

    目录 反序列化漏洞 序列化和反序列化 JAVA WEB中的序列化和反序列化 对象序列化和反序列范例 JAVA中执行系统命令 重写readObject()方法 Apache Commons Collec ...

  5. common-collections中Java反序列化漏洞导致的RCE原理分析

    2019独角兽企业重金招聘Python工程师标准>>> common-collections中Java反序列化漏洞导致的RCE原理分析 隐形人真忙 · 2015/11/11 22:4 ...

  6. linux反序列化漏洞,思科多个产品Java反序列化漏洞(CVE-2015-6420)

    思科多个产品Java反序列化漏洞(CVE-2015-6420) 发布日期:2015-12-15 更新日期:2015-12-17 受影响系统: Cisco Unified Computing Cisco ...

  7. 修而未复:说说WebLogic那修不完的Java反序列化漏洞

    编者说明:这篇文章初稿写在Oracle CPU补丁发布之后,考虑到文章内容的影响,并未在当时发布,WebLogic 的 Java 反序列化漏洞,已经修复了多次,最终的修复仍然未彻底解决问题. 背景 当 ...

  8. 带你掌握java反序列化漏洞及其检测

    摘要:在本文中将先介绍java反序列化漏洞的原理,然后在此基础上介绍安全工具如何检测.扫描此类漏洞. 本文分享自华为云社区<java反序列化漏洞及其检测>,作者: alpha1e0. 1 ...

  9. shrio反序列漏洞修复_Apache Shiro Java 反序列化漏洞分析

    Author: rungobier(知道创宇404安全实验室) Date: 2016-08-03 0x00 概述 Apache Shiro 在 Java 的权限及安全验证框架中占用重要的一席之地,在它 ...

最新文章

  1. java1.7环境,jdk1.7编译环境
  2. 【目标检测】Fast RCNN算法详解
  3. Android编译系统分析四:实战-新增一个产品
  4. python在线投票系统 统计票数_python投票统计程序,统计序列中各个数值的份数,字典的应用。...
  5. 两个oracle数据库外网同步,利用DBLink+JOB实现两个Oracle数据库之间的数据同步
  6. 如何用手机打开dcm格式图片_实现原始Dicom自动转换BIDS格式 ——Heudiconv
  7. python记录(5)- find() 与 rfind()
  8. 绘制曲线 matlab,matlab绘制曲线图文
  9. 0xC0000005: 读取位置 xxx时发生访问冲突
  10. java mail eml_使用JavaMail解析EML文件
  11. pd调节规律_一文看懂pd控制器的参数整定
  12. 数说故事“AI虚拟偶像研究室”第二期虚拟偶像数据分析研究报告
  13. 联想拯救者R720双系统如何进bios
  14. 一加ace2v和2区别对比 一加ace2和一加ace2v哪个好
  15. hive 以beeline的模式启动
  16. 项目管理修炼之道之把握项目的节奏
  17. Android源码编译(基于Ubuntu18.0.4)
  18. Neutron 理解 (6): 如何实现虚拟三层网络
  19. 中考表格计算机函数求和方法,2016信息技术中考电子表格处理模块
  20. 无线网络适配器点击启用显示已启用但是还是灰色的

热门文章

  1. 微星主板 Ubuntu20.04安装以及配置
  2. 在MNIST数据集上训练一个手写数字识别模型
  3. word长篇文档排版技巧教学视频
  4. 基于JSP+SSH的在线租车汽车租赁系统
  5. 马克思主义哲学(哲学概论)
  6. 第五章 系统方法---------基于业务驱动的企业安全架构(翻译,原作者John Sherwood)----仅学习使用
  7. 谈谈Web端性能测试
  8. Scrum敏捷价值观与原则
  9. 关于高压线路如何防山火
  10. 硬盘分区怎么分?新手该如何操作?