反序列化基础知识

Java接口

接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。

除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。

接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

Animal.java 文件代码:

/* 文件名 : Animal.java */

interface Animal {

public void eat();

public void travel();

}

MammalInt.java 文件代码:

/* 文件名 : MammalInt.java */

public class MammalInt implements Animal{

public void eat(){

System.out.println("Mammal eats");

}

public void travel(){

System.out.println("Mammal travels");

}

public int noOfLegs(){

return 0;

}

public static void main(String args[]){

MammalInt m = new MammalInt();

m.eat();

m.travel();

}

}

Java 序列化/反序列化

在Java中实现对象反序列化非常简单,实现java.io.Serializable(内部序列化)java.io.Externalizable(外部序列化)接口即可被序列化,其中java.io.Externalizable接口只是实现了java.io.Serializable接口。

反序列化类对象时有如下限制:

  1. 被反序列化的类必须存在。
  2. serialVersionUID值必须一致。

除此之外,反序列化类对象是不会调用该类构造方法的,因为在反序列化创建类实例时使用了sun.reflect.ReflectionFactory.newConstructorForSerialization创建了一个反序列化专用的Constructor(反射构造方法对象),使用这个特殊的Constructor可以绕过构造方法创建类实例

序列化/反序列化方法

ObjectInputStream、ObjectOutputStream两个类。

java.io.ObjectOutputStream类最核心的方法是writeObject方法,即序列化类对象。

java.io.ObjectInputStream类最核心的功能是readObject方法,即反序列化类对象。

所以,只需借助ObjectInputStreamObjectOutputStream类我们就可 以实现类的序列化和反序列化功能了。

java.io.Serializable接口

这是一个空接口,我们不需要实现java.io.Serializable的任何方法:

public interface Serializable {

}

实现java.io.Serializable接口仅仅只用于标识这个类可序列化

实现了java.io.Serializable接口的类原则上都需要生产一个serialVersionUID常量,反序列化时如果双方的serialVersionUID不一致会导致InvalidClassException 异常。如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID值。

java.io.Externalizable接口

java.io.Externalizablejava.io.Serializable几乎一样,只是java.io.Externalizable接口定义了writeExternalreadExternal方法需要序列化和反序列化的类实现,其余的和java.io.Serializable并无差别。

java.io.Externalizable.java:

copypublic interface Externalizable extends java.io.Serializable {

void writeExternal(ObjectOutput out) throws IOException;

void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

}

自定义序列化(writeObject)和反序列化(readObject)

实现了java.io.Serializable接口的类,还可以定义如下方法(反序列化魔术方法),这些方法将会在类序列化或反序列化过程中调用:

  1. private void writeObject(ObjectOutputStream oos),自定义序列化。
  2. private void readObject(ObjectInputStream ois),自定义反序列化。
  3. private void readObjectNoData()
  4. protected Object writeReplace(),写入时替换对象。
  5. protected Object readResolve()

序列化时可自定义的方法示例代码:

copypublic class DeserializationTest implements Serializable {

/**

* 自定义反序列化类对象

*

* @param ois 反序列化输入流对象

* @throws IOException IO异常

* @throws ClassNotFoundException 类未找到异常

*/

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {

System.out.println("readObject...");

// 调用ObjectInputStream默认反序列化方法

ois.defaultReadObject();

// 省去调用自定义反序列化逻辑...

}

/**

* 自定义序列化类对象

*

* @param oos 序列化输出流对象

* @throws IOException IO异常

*/

private void writeObject(ObjectOutputStream oos) throws IOException {

oos.defaultWriteObject();

System.out.println("writeObject...");

// 省去调用自定义序列化逻辑...

}

private void readObjectNoData() {

System.out.println("readObjectNoData...");

}

/**

* 写入时替换对象

*

* @return 替换后的对象

*/

protected Object writeReplace() {

System.out.println("writeReplace....");

return null;

}

protected Object readResolve() {

System.out.println("readResolve....");

return null;

}

}

当我们对DeserializationTest类进行序列化操作时,会自动调用(反射调用)该类的writeObject(ObjectOutputStream oos)方法,对其进行反序列化操作时也会自动调用该类的readObject(ObjectInputStream)方法,也就是说我们可以通过在待序列化或反序列化的类中定义readObjectwriteObject方法,来实现自定义的序列化和反序列化操作,当然前提是,被序列化的类必须有此方法,并且方法的修饰符必须是private

对比Python,PHP,Java反序列化

  • https://t.zsxq.com/yNvrjMf

PHP反序列化

PHP的序列化是开发者不能参与的,开发者调用serialize函数后,序列化的数据就已经完成了,你得到的是一个完整的对象,你并不能在序列化数据流里新增某一个内容, 你如果想插入新的内容,只有将其保存在一个属性中。也就是说PHP的序列化、反序列化是一个纯内部的过程, 而其__sleep__wakeup魔术方法的目的就是在序列化、反序列化的前后执行一些操作。

PHP的反序列化漏洞,很少是由__wakeup这个方法触发的,通常触发在析构函数__destruct里。其实大部分PHP反序列化漏洞,都并不是由反序列化导致的,只是通过反序列化可以控制对象的属性,进而在后续的代码中进行危险操作。

所以PHP反序列化漏洞又被称为“对象注入”

Java反序列化

Java在序列化时一个对象, 将会调用这个对象中的writeobject方法,参数类型是objectoutputstream,开发者可以将任何内容写入这个stream中;反序列化时,会调用readobject,开发者也可以从中读取出前面写入的内容,并进行处理。

比如:


package org.vulhub.Ser; import java.io.IOException;

public class Person implements java.io.Serializable {

public String name;

public int age;

Person(String name, int age) {

this.name = name;

this.age = age;

}

private void writeObject(java.io.ObjectOutputStream s) throws IOException {

s.defaultWriteObject();

s.writeObject("This is a object");

}

private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {

s.defaultReadObject();

String message = (String) s.readObject();

System.out.println(message);

}

}

在执行完s.defaultWriteObject();之后s.writeObject("This is a object");这行代码向stream里面又写入了一个字符串"This is a object",使用工具SerializationDumper查看此时生成的序列化数据(此处代码太长就不看了)

可见,我们写入的字符串This is a object被放在objectAnnotation的位置

反序列化的时候可以读取这个字符串并且输出:

Python反序列化

Python反序列化和ava、PHP有个显著的区别,就是Python的反序列化过程实际上是在执行一个基于栈的虚拟机。我们可以向栈上增、删对象,也可以执行一些指令,比如函数的执行等,甚至可以用这个虚拟机执行一个完整的应用程序。

看这篇文章:https://xz.aliyun.com/t/7436

所以,Python的反序列化可以立即导致任意函数、命令执行漏洞,与需要gadget的PHP和Java相比更加危险。

Java-ysoserial审计环境搭建

​
https://www.shuzhiduo.com/A/MyJxmM1p5n/

https://bkfish.gitee.io/2020/05/29/java%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%85%A5%E9%97%A83-ysoserial%E8%B0%83%E8%AF%95%E5%92%8C%E6%9E%84%E9%80%A0URLDNS%E7%9A%84pop%E9%93%BE/

​

踩坑:

  • ysoserial不支持1.6,我用的JDK是1.7版本,不然run不起来

是提取的JDK有问题(我是直接解压exe然后跑,果然有问题),建议从虚拟机安装之后把文件夹拖出来,而且建议使用jdk1.8,不然源码不一样

  • 因为是maven项目,pom.xml文件里面有些依赖下载不下来可以去https://mvnrepository.com/这个里面找到jar和pom文件手动放到本地仓库,比如
<dependency>

<groupId>de.odysseus.juel</groupId>

<artifactId>juel-impl</artifactId>

<version>2.2.7</version>

</dependency>

所对应的就是repository\de\odysseus\juel\juel-impl\2.2.7\juel-impl-2.2.7.pom(jar)

调试JDK源码 https://blog.youkuaiyun.com/daerzei/article/details/79717717

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值