赞
踩
序列化
序列化:将对象转换为字节序列。
反序列化:把字节序列回复为原先的对象。
Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
整个过程都是 Java 虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象。
序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。
其中类 ObjectInputStream 和 ObjectOutputStream 是高层次的数据流,它们包含反序列化和序列化对象的方法。
ObjectOutputStream 类中:通过使用 writeObject(Object object) 方法,将对象以二进制格式进行写入。
ObjectInputStream 类中:通过使用 readObject()方法,从输入流中读取二进制流,转换成对象。
package test; import java.io.*; public class Serialize { public static void main(String args[])throws Exception{ //定义obj对象 // String obj="hello world!"; MyObject myObject=new MyObject(); myObject.name="hello world!"; //创建一个包含对象进行反序列化信息的”object”数据文件 FileOutputStream fos=new FileOutputStream("object"); ObjectOutputStream os=new ObjectOutputStream(fos); //writeObject()方法将obj对象写入object文件 os.writeObject(myObject); os.close(); //从文件中反序列化obj对象 FileInputStream fis=new FileInputStream("object"); ObjectInputStream ois=new ObjectInputStream(fis); //恢复对象 MyObject obj2=(MyObject)ois.readObject(); System.out.print(obj2); ois.close(); } } class MyObject implements Serializable {//只有实现了Serializable接口的类的对象才可以被序列化 public String name; //重写readObject()方法 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{ //执行默认的readObject()方法 in.defaultReadObject(); //执行打开计算器程序命令 Runtime.getRuntime().exec("cmd.exe /c start dir"); } }
从上面代码中可以看出,myObject实例化的对象被序列化进object文件,再被读取并反序列化,执行了重写后的readObject方法,显示 my name is lcx 并弹出了计算器。
java类对象要实现反序列化,该类必须实现 java.io.Serializable接口,并且一般会调用readObect方法,该方法的实现容易引发漏洞。除了readObect,有时也会用到readUnshared方法,与readObect不同的是,此方法不允许后续的readObect/readUnshared调用此次反序列化得到的对象。
反序列化漏洞就是,暴露或间接暴露反序列化 API ,导致用户可以操作传入数据,攻击者可以精心构造反序列化对象并执行恶意代码。
分析源码:webgoat-server-8.1.0\BOOT-INF\lib\insecure-deserialization-8.1.0.jar!\org\owasp\webgoat\deserialization\InsecureDeserializationTask.class
后端拿到传入的token之后进行了一个特殊符号替换,然后进行了base64解码,解码过后进行了readObject()反序列化操作,最后判断一下这个对象是不是VulnerableTaskHolder的实例。所以,我们反序列化的对象也就确定了,那就是VulnerableTaskHolder类的实例。
VulnerableTaskHolder类的实现:
源码分析:webgoat-server-8.1.0\BOOT-INF\lib\insecure-deserialization-8.1.0.jar!\org\dummy\insecure\framework\VulnerableTaskHolder.class
关注readObject:
可以看到这里直接利用Runtime.getRuntime().exec()执行了taskAction,而taskAction是在构造函数里被赋值的,所以我们可以通过控制taskAction来控制执行的命令。
在rg\dummy\insecure\framework新建一个文件,文件内内容taskAction对象,属性填攻击语句,这里用的ping -n 6 127.0.0.1命令来让他延迟5秒.
这是参考网上的资料,Java太菜,没有实现。
可以是使用ysoserial工具帮我们生成payload。
ysoserial下载地址:https://github.com/frohoff/ysoserial/releases
ysoserial工具使用介绍
java -Dhibernate5 -cp hibernate-core-5.4.9.Final.jar;ysoserial-all.jar ysoserial.GeneratePayload Hibernate1 calc.exe >payload1.bin
hibernate-core-5.4.9.Final.jar和ysoserial-all.jar要在同一级目录下,hibernate-core-5.4.9.Final.jar在WEBGoat\BOOT-INF\lib\目录下,直接复制出来即可。
注:-Dhibernate5对应我们要使用的hibernate-core-5.4.28.Final.jar主键,ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.GeneratePayload是用来生成payload,Hibernate1是ysoserial程序的一个加密模块。
calc.exe >payload1.bin是将calc.exe执行程序写入到payload1.bin文件
生成出来的payload1.bin是序列化后内容没有进行base64编码,所以还需要对payload1.bin进行编码。
import base64
# 读取二进制文件内容
with open('payload1.bin', 'rb') as f:
content = f.read()
# 对二进制内容进行 Base64 编码
encoded = base64.b64encode(content)
# 将编码后的内容写入文本文件
with open('payload.txt', 'wb') as f:
f.write(encoded)
把生成好的payload复制到输入框里提交,就会执行运行计算器。
从这个案例可以发现,存在反序列化漏洞站点,我们可以进行代码执行,在实际利用中通常会构造反弹shell的payload来获得网站权限。
Java反序列漏洞案例分析
反序列化操作一般在导入模版文件、网络通信、数据传输、日志格式化存储、对象数据落磁盘或DB存储等业务场景,在代码审计时可重点关注一些反序列化操作函数并判断输入是否可控,如
ObjectInputStream.readObject 、
ObjectInputStream.readUnshared 、
XMLDecoder.readObject 、
Yaml.load、
XStream.fromXML 、
ObjectMapper.readValue 、
JSON.parseObject,还有一些第三方库提供的反序列化操作接口,实际上,基本不会存在一个系统从外部直接读取什么对象序列化之后传输,可能存在比如说有对象被序列化后作为cookie的一部分传了进去,那我们可以构造cookie达到利用的目的。
白盒:
找接收外部输入的序列化对象的接收点(比如ObjectInputStream对象的初始化参数来自外部请求输入参数则基本可以确定存在反序列化漏洞了),也是反序列化的触发点。找对反序列化的函数调用(比如反序列化时的readObject()方法是否重写,重写中是否有设计不合理,可以被利用之处),看是不是有危险库,有的话利用相关方法搞一搞。
黑盒:
抓交互流量数据,java序列化数据的特征大多以标记(ac ed 00 05 00 05是版本号 base64编码为rO0AB)开头。Java RMI 的传输 100% 基于反序列化,Java RMI 的默认端口是1099端口。
Java序列化传输方式,用burp抓包会在hex编码中找到特征码ac ed 00 05,数据显示也会比较奇怪混杂大量字符和空白,这就是序列化传递的一种流量特征,我们或许可以用工具ysoserial生成payload,改包向服务器发送请求。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。