初探Java反序列化漏洞
一、基本概念
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反序列化漏洞相关推荐
- java反序列化漏洞的一些gadget
目录 0x00 URLDNS 0x01 Commons Collections 0x02 RMI的codebase任意代码执行 0x03 JNDI 0x04 LDAP 0x05 JDK7u21 首先说 ...
- java 反序列化漏洞 利用思路简介
目录 序列化的过程 readObject方法 反射链 完成反序列漏洞实践 结论 之前听别人讲解反序列化的漏洞听的晕乎乎的,刚脆就趁着周末研究一下反序列化漏洞,并且搭建实战环境实际操作了一把,明白了之后 ...
- java 反序列化漏洞简介
目录 一.Java的序列化与反序列化 二.对java序列化的理解 三.反序列化的漏洞原理概述 四.关于反射链 一.Java的序列化与反序列化 在这里我们直接自己定义一个类,然后对这个类的对象(一个实例 ...
- java序列化_技术干货 | JAVA反序列化漏洞
目录 反序列化漏洞 序列化和反序列化 JAVA WEB中的序列化和反序列化 对象序列化和反序列范例 JAVA中执行系统命令 重写readObject()方法 Apache Commons Collec ...
- common-collections中Java反序列化漏洞导致的RCE原理分析
2019独角兽企业重金招聘Python工程师标准>>> common-collections中Java反序列化漏洞导致的RCE原理分析 隐形人真忙 · 2015/11/11 22:4 ...
- linux反序列化漏洞,思科多个产品Java反序列化漏洞(CVE-2015-6420)
思科多个产品Java反序列化漏洞(CVE-2015-6420) 发布日期:2015-12-15 更新日期:2015-12-17 受影响系统: Cisco Unified Computing Cisco ...
- 修而未复:说说WebLogic那修不完的Java反序列化漏洞
编者说明:这篇文章初稿写在Oracle CPU补丁发布之后,考虑到文章内容的影响,并未在当时发布,WebLogic 的 Java 反序列化漏洞,已经修复了多次,最终的修复仍然未彻底解决问题. 背景 当 ...
- 带你掌握java反序列化漏洞及其检测
摘要:在本文中将先介绍java反序列化漏洞的原理,然后在此基础上介绍安全工具如何检测.扫描此类漏洞. 本文分享自华为云社区<java反序列化漏洞及其检测>,作者: alpha1e0. 1 ...
- shrio反序列漏洞修复_Apache Shiro Java 反序列化漏洞分析
Author: rungobier(知道创宇404安全实验室) Date: 2016-08-03 0x00 概述 Apache Shiro 在 Java 的权限及安全验证框架中占用重要的一席之地,在它 ...
最新文章
- java1.7环境,jdk1.7编译环境
- 【目标检测】Fast RCNN算法详解
- Android编译系统分析四:实战-新增一个产品
- python在线投票系统 统计票数_python投票统计程序,统计序列中各个数值的份数,字典的应用。...
- 两个oracle数据库外网同步,利用DBLink+JOB实现两个Oracle数据库之间的数据同步
- 如何用手机打开dcm格式图片_实现原始Dicom自动转换BIDS格式 ——Heudiconv
- python记录(5)- find() 与 rfind()
- 绘制曲线 matlab,matlab绘制曲线图文
- 0xC0000005: 读取位置 xxx时发生访问冲突
- java mail eml_使用JavaMail解析EML文件
- pd调节规律_一文看懂pd控制器的参数整定
- 数说故事“AI虚拟偶像研究室”第二期虚拟偶像数据分析研究报告
- 联想拯救者R720双系统如何进bios
- 一加ace2v和2区别对比 一加ace2和一加ace2v哪个好
- hive 以beeline的模式启动
- 项目管理修炼之道之把握项目的节奏
- Android源码编译(基于Ubuntu18.0.4)
- Neutron 理解 (6): 如何实现虚拟三层网络
- 中考表格计算机函数求和方法,2016信息技术中考电子表格处理模块
- 无线网络适配器点击启用显示已启用但是还是灰色的