当前位置: 首页 > article >正文

[Web安全 网络安全]-反序列化漏洞

文章目录:

一:前言

1.定义

2.原理

3.危害与影响

4.常见场景与案例

5.防御措施

6.魔术方法

7.基本数据类型

二:分类

1.PHP反序列化

例子1 

例子2

2.java反序列化

例子1 

例子2

三:靶场练习


一:前言

1.定义

反序列化漏洞存在于应用程序中对数据进行反序列化操作的过程中

当应用程序接收到外部传递的恶意序列化数据并进行反序列化时
攻击者可以利用这个漏洞执行未经授权的代码或导致应用程序受到攻击

简而言之

序列化与反序列化:按照特定的格式存储与读取的过程

目的:为了方便对象的传递使用,反序列化攻击也可以理解为对象注入

    序列化:把剩菜存进冰箱

    反序列化:从冰箱拿出剩菜

    注入攻击:给你冰箱里的剩菜下毒

2.原理

  序列化:将对象转化为字符串进行存储            Serialization      序列化serialize()
         将对象的状态信息转换为可以存储或传输的形式的过程
         在序列化期间,对象将其当前状态写入到临时或持久性存储区

反序列化:将字符串转化为对象                    UnSerialization    反序列化unserialize()
         从存储区中读取该数据,并将其还原为对象的过程,成为反序列化



在反序列化过程中,如果恶意者可以对将要转换的字符串进行操控,从而达到任意代码执行的操作,就形成了反序列化漏洞
这主要是因为应用程序在反序列化过程中没有对传入的数据进行足够的验证和过滤

3.危害与影响

远程代码执行(RCE):攻击者可以利用反序列化漏洞在目标系统上执行恶意代码,如远程控制命令、窃取敏感数据、修改系统配置等

拒绝服务攻击(DoS):攻击者可以构造大量的恶意序列化数据来消耗程序的资源,导致系统崩溃或服务不可用

数据篡改和伪造:攻击者可以利用反序列化漏洞来篡改数据或伪造合法的用户会话,导致系统信任恶意构造的数据或执行未经授权的操作

提升权限:如果攻击者成功利用反序列化漏洞执行了恶意代码,他们可能会尝试提升其在系统中的权限,获取更高的访问权限

敏感信息泄露:反序列化漏洞有可能导致敏感信息泄露,例如通过序列化和反序列化操作中的错误处理机制或日志泄露出敏感数据

4.常见场景与案例

Java中的反序列化漏洞:
    Java中的ObjectInputStream.readObject()方法用于将序列化的对象数据还原成实际的对象实例
    如果未对传入的序列化数据进行充分验证和过滤,攻击者可以构造恶意的序列化数据来执行任意代码


PHP中的反序列化漏洞:
    PHP中的unserialize()函数用于将序列化的字符串转换为PHP变量
    如果应用程序在接收用户输入后直接使用unserialize()函数进行反序列化操作,而没有对输入进行严格的验证和过滤,就可能存在反序列化漏洞


.NET中的反序列化漏洞:
    在.NET Framework中,BinaryFormatter类的Deserialize()方法用于将二进制数据反序列化为对象
    如果应用程序在使用BinaryFormatter进行反序列化时没有实施有效的安全措施,就可能受到反序列化攻击

5.防御措施

输入验证和过滤:对于外部传入的序列化数据,应该进行严格的输入验证和过滤,确保数据的来源可信和完整

应用程序安全配置:在应用程序的安全配置中,禁用或限制不必要的反序列化操作,只允许从受信任的源进行反序列化

使用安全的序列化库:选择使用安全性较高的序列化库,这些库通常提供了更多的安全特性和保护机制

持续更新和修补:及时更新和修补应用程序中使用的序列化库,以确保已知的反序列化漏洞得到修复

检测和监控:实施日志记录和监控机制,及时检测和响应可能的反序列化攻击

6.魔术方法

__construct():当对象被创建时触发

__destruct():当对象被销毁前触发

__tostring():当对象被当作一个字符串使用时触发

__sleep():序列化对象前调用(其返回需要是一个数组指定序列化哪些属性)

__wakeup():反序列化恢复对象前调用

__call():当调用对象中不存在的方法时调用

__get():从不可访问的属性读取数据

__callStatic():调用类不存在的静态方式方法时执行

__set():用于将数据写入不可访问属性

__invoke():调用函数的方式调用一个对象时的回应方法

__isset():在不可访的属性上调用isset()或empty()触发

__unset():在不可访的属性上使用unset()时触发

7.基本数据类型

布尔值(bool):b:value => b:0

整数型 (int):i:value=>i:1

字符串型 (str):s:length:"value";=>s:5:"abcde".

数组型(array):a:<length>:{key,value pairs};=>a:1:{i:1;s:1:"a"}

对象型(object):O:<class_name_length>

浮点型(double):d:value=>d:10.8

引用类型:R : R:value=> R:2

null型:N

二:分类

1.PHP反序列化

例子1 

原理:未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程
     从而导致代码执行,SQL 注入,目录遍历等不可控后果
     在反序列化的过程中自动触发了某些魔术方法。当进行反序列化的时候就有可能会触发对象中的一些魔术方法


函数
    serialize()         //将一个对象转换成一个字符串
        举例
            <?php
                $key='liu';
                echo serialize($key);
            ?>
        输出:s:3:"liu";

    unserialize()       //将字符串还原成一个对象
        举例
            <?php
                $key='s:3:"liu";
                echo unserialize($key);
            ?>
        输出:liu


测试
    <?php
	    class ABC{
        public $test;
        function __construct(){
            $test = 1;
            echo '调用了构造函数<br>';
        }
        function __destruct(){
            echo '调用了析构函数<br>';
        }
        function __wakeup(){
            echo '调用了苏醒函数<br>';
        }
    }
    echo '创建对象a<br>';
    $a = new ABC;
    echo '序列化<br>';
    $a_ser=serialize($a);
    echo '反序列化<br>';
    $a_unser=unserialize($a_ser);
    echo '对象快要死了!';
    ?>

    运行结果
        创建对象a<br>
        调用了构造函数<br>
        序列化<br>
        反序列化<br>
        调用了苏醒函数<br>
        对象快要死了!
        调用了析构函数<br>
        调用了析构函数<br>

例子2

 序列化

<?php
    class  Person {
      var $name="varin";
    }
    $user1 = new Person();
    echo serialize($user1);
?>


输出:O:6:"Person":1:{s:4:"name";s:5:"varin";}
    O:对象
    6:对象名称长度
    Person:对象名称
    1:表示有一个值
    s:字符串
    4:变量名长度
    name:变量名称
    5:变量名长度
    varin:变量名称

反序列化

<?php
    class  Person {
          var $name="varin";
    }

    $user2 = unserialize($user1_ser);
    print_r($user2);

    echo $user1->name;
?>

输出
    Person Object([name]=> varin )
    varin

2.java反序列化

例子1 

Java 反序列化是将已序列化的对象状态恢复为对象的过程
    序列化是通过实现 java.io.Serializable 接口来完成的
    反序列化则是通过使用 ObjectInputStream 类来实现的

以下是一个简单的 Java 反序列化示例:
    创建一个实现 Serializable 接口的类
    序列化该类的对象并将其写入文件
    从文件中读取并反序列化该对象

运行步骤
    首先运行 SerializeDemo 类,将 Person 对象序列化并保存到 person.ser 文件中
    然后运行 DeserializeDemo 类,从 person.ser 文件中读取并反序列化 Person 对象,并打印到控制台

输出
    Deserialized Person...  
    Person{name='Alice', age=30}

输出表明
    成功从person.ser文件中读取了序列化数据
    数据被正确反序列化为Person对象
    反序列化后的Person对象的状态(即其name和age字段的值)与序列化时保持一致

1. 创建实现 Serializable 接口的类

import java.io.Serializable;  
  
public class Person implements Serializable {  
    private static final long serialVersionUID = 1L; // 推荐定义这个UID,确保序列化的兼容性  
    private String name;  
    private int age;  
  
    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
  
    @Override  
    public String toString() {  
        return "Person{name='" + name + "', age=" + age + '}';  
    }  
  
    // Getter 和 Setter 方法(可选)  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public int getAge() {  
        return age;  
    }  
  
    public void setAge(int age) {  
        this.age = age;  
    }  
}

2. 序列化对象并写入文件

import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.ObjectOutputStream;  
  
public class SerializeDemo {  
    public static void main(String[] args) {  
        Person person = new Person("Alice", 30);  
  
        try (FileOutputStream fileOut = new FileOutputStream("person.ser");  
             ObjectOutputStream out = new ObjectOutputStream(fileOut)) {  
            out.writeObject(person);  
            System.out.println("Serialized data is saved in person.ser");  
        } catch (IOException i) {  
            i.printStackTrace();  
        }  
    }  
}

3. 从文件中读取并反序列化对象

import java.io.FileInputStream;  
import java.io.IOException;  
import java.io.ObjectInputStream;  
  
public class DeserializeDemo {  
    public static void main(String[] args) {  
        Person person = null;  
  
        try (FileInputStream fileIn = new FileInputStream("person.ser");  
             ObjectInputStream in = new ObjectInputStream(fileIn)) {  
            person = (Person) in.readObject();  
        } catch (IOException i) {  
            i.printStackTrace();  
        } catch (ClassNotFoundException c) {  
            System.out.println("Person class not found");  
            c.printStackTrace();  
        }  
  
        System.out.println("Deserialized Person...");  
        System.out.println(person);  
    }  
}

例子2

序列化 

class S{
    public $test="pikachu";
}
$s=new S();     
serialize($s);

//序列化后得到的结果是这个样子的:O:1:"S":1:{s:4:"test";s:7:"pikachu";}`   
    O:代表object    
    1:表示该对象的类名的字节数(即类名长度为1)    
    S:对象的名称    
    1:表示该对象有 1 个属性   
    s:数据类型    
    4:变量名称的长度   
    test:变量名称    
    s:数据类型    
    7:变量值的长度
    pikachu:变量值

反序列化

$u=unserialize("O:1:"S":1:{s:4:"test";s:7:"pikachu";}");
echo $u->test;     //得到的结果为pikachu

三:靶场练习

当我们输入序列化数据:O:1:"S":1:{s:4:"test";s:7:"pikachu";}
    此时反序列化函数将输入的序列化数据还原为了对象


如果攻击者在此输入页面中输入恶意代码,则会被该反序列化函数还原为对象,进行执行
    比如
        O:1:"S":1:{s:4:"test";s:30:"<script>alert('haha')</script>";}
        O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";} 
    则会弹出XSS攻击页面


http://www.kler.cn/a/369172.html

相关文章:

  • Qt 文本文件读写与保存
  • springboot基本概念
  • JavaEE 多线程第四节 (线程核心操作----线程开始/线程终止)
  • JVM(HotSpot):GC之G1垃圾回收器
  • 基于Datawhale开源量化投资学习指南(11):LightGBM在量化选股中的优化与实战
  • pytorh学习笔记——cifar10(六)MobileNet V1网络结构
  • 【rabbitmq】rabbitmq工作模式
  • 震惊!25岁普信男又思索出自己的成功学?
  • 机器学习之 AdaBoost(Adaptive Boosting)
  • web相关知识学习笔记
  • MFC扩展库BCGControlBar Pro v35.1新版亮点 - 改进编辑控件性能
  • AI创作者与人类创作者的协作模式
  • 本地搭建Trilium Notes轻松创建个人知识库并实现远程查看文档资料
  • python 实现一个简单的浏览器引擎
  • Springboot整合原生ES依赖
  • 【力扣 + 牛客 | SQL题 | 每日3题】SQL大厂面试题SQL156, 157
  • 软考中级嵌入式系统设计师笔记分享(一)
  • Seatunnel和Seatunnel-web部署-linux
  • 【脚本】B站视频AB复读
  • 无人机之红外探测技术篇
  • [含文档+PPT+源码等]精品基于PHP实现的培训机构信息管理系统的设计与实现
  • 我用自研引擎做游戏:《干得好,托尼》
  • 【NOIP提高组】 自由落体
  • 网络编程 Linux环境 C语言实现
  • 电脑连接海康相机并在PictureBox和HWindowControl中分别显示。
  • Flink CDC系列之:学习理解核心概念——Data Source