JAVA反序列化的学习

JAVA反序列化的学习

反序列化漏洞的概念

首先了解什么是序列化和反序列化

序列化:将实体对象按照一定的格式写入到有序字节流的过程
反序列化:将字节流恢复为对象的过程称为对象的反序列化

为什么会需要序列化

当互联网上的两个进程进行远程通信的时候,是可以发送各种类型的数据,如视频、图片、音频等,这些数据都是通过二进制序列的形式在网络中进行传送的。所以当两个Java进程进行通信时,就需
要通过Java的序列化将发送的Java对象转化为字节流,传输完成后,再通过反序列化从字节流中恢复成Java对象

对象序列化的用途

  1. 将对象的字节序列永久保存到硬盘中
  2. 在网络中传送对象的字节序列

在Web服务器中的Session对象中,如果用户量大的话,Session的数量将可能导致内存崩溃,Web容器会将一些session先序列化到硬盘中,如果要用,在讲硬盘中的对象还原

JAVA 中的序列化和反序列化

  • 在Java中,只有实现了Serializable和Externalizable的对象才可以被序列化和反序列化
  • java.io.ObjectOutputStream代表对象输出流,调用它的writeObject()方法可以对指定的对象进行序列化,将得到的字节序列写入到目标输出流
  • java.io.ObjectOutputStream代表对象输入流,调用它的readObject()方法从输入流中读取字节序列,反序列化得到对象
  • 如果要自定义类的反序列化方式,需要在被反序列化的类中重写readObject()方法
序列化的简单实现
  1. 创建一个对象输出流,用文件输出流将其实例化
  2. 调用对象输出流的writeObject()方法,将对象序列化
  3. 调用对象输入流将序列化的字节还原成对象

代码如下

package java_fanxuliehau;
import java.io.*;
class Name implements Serializable{  // 创建一个用于序列化和反序列化的对象
	private String zxcv;
	public String getName() {
		return zxcv;
	}
	public void setName(String zxcv) {
		this.zxcv = zxcv;
	}
}
// xlh()函数序列化过程;fxlh()是反序列过程
class XLH{
	public void fxlh() throws IOException{
		FileOutputStream  fos = new FileOutputStream("xxx.txt");  // 创建一个文件输出流
		ObjectOutputStream oos = new ObjectOutputStream(fos);  // 实例化对象输出流的对象
		Name name = new Name();
		name.setName("zxcv");
		oos.writeObject(name);  // 将name对象进行序列化,保存到xxx.txt中
		oos.close();
		System.out.println("Name对象已经序列化成功了");
	}
	public void xlh() throws IOException, ClassNotFoundException{
		FileInputStream fis = new FileInputStream("xxx.txt");  // 创建一个文件输入流
		ObjectInputStream ois = new ObjectInputStream(fis);  // 实例化文件输入流对象
		Name name = (Name)ois.readObject();  // 从xxx.txt中将字节序列转换成Name对象
		System.out.println("Name对象反序列化成功了!");
		System.out.println(name.getName());
		ois.close();
	}
}

public class object{
	public static void main(String[] argv) throws IOException, ClassNotFoundException {
		XLH xlh = new XLH();
		xlh.xlh();
		xlh.fxlh();
	}

}

通过运行结果,可以看到,反序列化的输出了Name对象序列化之前的被赋予的zxcv的值。证明了序列化到反序列化的过程,数据是不变的。在序列化中理论上会生成xxx.txt文件保存Name对象的字节序列,但是在测试的时候,并没有生成xxx.txt文件,还不清楚原因
在这里插入图片描述
在Java中执行系统命令的函数是Runtime.getRuntime().exec()
重写Name类的readObject()方法,实现调用计算机的功能

class Name implements Serializable{
	private String zxcv;
	public String getName() {
		return zxcv;
	}
	public void setName(String zxcv) {
		this.zxcv = zxcv;
	}
	private  void readObject(ObjectInputStream in) throws InterruptedException, IOException, ClassNotFoundException {
        //先调用默认的readObject()方法
        in.defaultReadObject();
 
        //重写,执行系统命令calc.exe
       Runtime.getRuntime().exec("calc.exe");
 
    }
}

执行后,会调用windows中的计算机程序
在这里插入图片描述

Apache Commons Collection反序列化的思路

  • Apache Commons Collections中的InvokerTransformer接口实现了反射链(大意应该是一些列的连锁反应),通过反射机制来执行任意命令

  • Apache Commons Collections也实现了一个TransformedMap类,实例化需要Map和Transformer作为参数传入

  • TransformMap中的任意项的Key或者Value被修改,相应的Transformer的transform()方法就会被调用

  • AnnotationInvocationHandler这个类可序列化,且该类有一个成员变量是Map类型,并且在重写readObjetc()方法中,会修改成员变量的值

现在整理一下思路:在对AnnotationInvocationHandler 类进行实例化的时候,传入TransformedMap对象作为这个类的成员变量。AnnotationInvocationHandler 这个类反序列化的时候,触发了readObject()函数导致修改了成员变量TransformedMap的值,然后TransformMap中的值被修改后会触发InvokerTransformer()中的transform()方法,然后这个方法通过反射链再去执行例如调用计算器之类的函数Runtime.getRuntime().exec(“calc.exe”);

参考文章:https://xie1997.blog.csdn.net/article/details/84504405
                  https://blog.csdn.net/xlgen157387/article/details/79840134

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值