Java反序列化和PHP反序列化的区别


反序列化存在的意义是为了数据传输,类是无法直接进行传输的。通过序列化后转换为字符串格式或者JSON格式进行传输

序列化与反序列化

  • seriallization 序列化 : 将对象转化为便于传输的格式, 常见的序列化格式:二进制格式,字节数组,json字符串,xml字符串。

  • deseriallization 反序列化:将序列化的数据恢复为对象的过程。

PHP反序列化漏洞

PHP反序列化

  • serialize()将对象序列化成字符串。

  • unserialize()将字符串反序列化回对象。

序列化

  • 对象转换成字符串

  • 方便传输

反序列化

  • 字符串转换成对象

  • O:object

<?php
    //创建类
    class Stu{
    
    
        public $name;
        public $age;
        public $sex;
    }
	
	//创建对象
    $stu1 = new Stu();
    $stu1->name = "wuhu";
    $stu1->age = 18;
    $stu1->sex = true;
    var_dump($stu1);
    echo "<hr />";
    echo serialize($stu1);

?>

image-20230915193800754

类中的魔术方法,在特定情况下会自动调用。即使魔术方法在类中没有被定义,也是真实存在的。

两个下划线:

  • __construct():在创建对象时自动调用。
  • __destruct()::在销毁对象时自动调用。
  • __wakeup()unserialize()时会自动调用这个函数
  • __sleep()serialize()时会自动调用这个函数

以_开头的函数,是PHP中的魔术方法,是为了更快的响应。__wakeup()和__sleep()方法在互联网上会被频繁调用。

反序列化漏洞不能通过黑盒测试来查找漏洞。只能通过白盒测试,也就是代码审计

反序列化漏洞攻击者是不可控的,因为功能代码全是开发者自己写的。

<?php

    class animal{
    
    
        public $name;
        public $age;

        public function __sleep(){
    
    
            if(@$_GET['cmd']=="abc"){
    
    
                a();
            }
        }

    }

    $an1=new animal;

    $an1->name="dog";
    $an1->age=3;

    //var_dump($an1);

    @serialize($an1);

?>

image-20230915095903605

什么是反序列化漏洞?

序列化和反序列化本身是为了实现数据在网络上完整高效的传输,但是由于反序列化过程中,对象的魔术方法会自动调用,魔术方法本身调用了别的方法,最终呈现一种链式调用,直到执行任意的代码或者命令。并且危险函数的参数可控

修改序列化后的数据,目的是什么?

为了满足一定的条件以后实现链式调用。

Java反序列化漏洞

序列化

ObjectOutputStream --> writeObject()

反序列化:

ObjectInputStream --> readObject() 

实验

Person类

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class Person implements Serializable {
    
    
    public int age;
    public String name;

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    
    
        Runtime.getRuntime().exec("calc");
        // 默认的反序列化操作
        in.defaultReadObject();
    }
}

注意:想让某个类执行序列化或者反序列化必须实现Serializable接口。

Test类

import java.io.*;

public class Test {
    
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    
        Person p=new Person();
        p.age=18;
        p.name="wuhu";
		
        //将Person这个类的对象序列化后存放到wuhu.bin文件中
        //没有指定路径就表示存放到当前路径中
        serialize(p,"wuhu.bin");


        System.out.println("反序列化结果:" + deserialize("xiu.bin"));
    }
	
    //序列化
    public static void serialize(Object obj, String filePath) throws IOException {
    
    
        try (FileOutputStream fileOut = new FileOutputStream(filePath);
             ObjectOutputStream objectOut = new ObjectOutputStream(fileOut)) {
    
    
            objectOut.writeObject(obj);
        }
    }
	
    //反序列化
    public static Object deserialize(String filePath) throws IOException, ClassNotFoundException {
    
    
        try (FileInputStream fileIn = new FileInputStream(filePath);
             ObjectInputStream objectIn = new ObjectInputStream(fileIn)) {
    
    
            return objectIn.readObject();
        }
    }
}

序列化后的字符串

image-20230915200923576

说明:不同的编程语言的序列化和反序列化后的数据格式不一样。

那么漏洞点在哪里?

将Person类中的readObject方法注释了执行的时候,输出结果就是输出了反序列化后的结果。

image-20230915201540400

那么如果重写readObject方法后,在方法中添加一个Runtime.getRuntime().exec("calc"); 这行代码使用 Java 的 Runtime 类执行操作系统命令,即在 Windows 系统上运行计算器应用程序(calc)。执行结果如下:

image-20230915201716681

在实际的开发环境中,需要重写readObject()方法,例如:从前端传递的值是base64编码的,而系统的方法不识别base64,所以需要在重写的readObject()方法中先解码,将解码完的对象再去调用系统的方法。

漏洞成因

Java反序列漏洞的成因是函数的链式调用,满足链式调用的全部条件,并且参数可控制。以及重写了readObject()方法,才能造成Java反序列漏洞。(条件苛刻)。当然如果没有重写readObject()方法,执行的就是系统的反序列化方法,也就没有了反序列化漏洞了。

什么是反序列化漏洞?

PHP的反序列化和java的反序列化是两种不同的类型,序列化和反序列化本身没有漏洞点,只是为了实现数据的完整高效的传输。

PHP反序列漏洞是由于类里面的魔术方法调用了某个函数,该危险函数又调用了别的函数,最终执行到了危险函数的位置。

JAVA反序列化漏洞是由于开发者重写了readObject方法,该readObject方法方法调用了别的方法,最终执行到了例如Transfrom方法的危险方法(链式调用)。

shiro :爆破密钥,找寻CC利用链

猜你喜欢

转载自blog.csdn.net/weixin_58783105/article/details/132975714