《Web安全基础》07. 反序列化漏洞

2023-09-14 15:58:10


本系列侧重方法论,各工具只是实现目标的载体。
命令与工具只做简单介绍,其使用另见《安全工具录》。

靶场参考:pikachu,WebGoat。

1:基本概念

1.1:序列化&反序列化

序列化(Serialization),指将内存数据(数据结构或对象)转化为一种便于存储或传输的格式(字节序列)的过程。

反序列化(Deserialization),是序列化的逆过程,把字节序列恢复为原先的内存数据,以便在程序中进行进一步处理和使用。

在这里插入图片描述

作用

  • 将内存中的数据转化为字节序列,以便于数据传递和恢复。

用途

  • 把内存数据以字节序列形式永久保存到硬盘上,通常存放在一个文件中(序列化对象)。
  • 在网络上传送内存数据的字节序列(网络传输对象)。

不同语言,不同操作序列化生成的字节流格式一般不同。

1.2:反序列化漏洞

反序列化漏洞(Deserialization Vulnerability):用户可以控制或修改用来反序列化的数据,这可能使攻击者能够操纵序列化对象,将有害数据传递到应用程序中,从而产生安全问题。

漏洞成因
在身份验证,文件读写,数据传输等功能处,未对反序列化接口做访问控制,未对序列化数据做加密和签名,加密密钥使用硬编码(如Shiro 1.2.4),使用不安全的反序列化框架库(如Fastjson 1.2.24)或函数的情况下,由于序列化数据可被用户控制,攻击者可以精心构造恶意的序列化数据(执行特定代码或命令的数据)传递给应用程序,在应用程序反序列化对象时执行攻击者构造的恶意代码,达到攻击者的目的。

反序列化漏洞一般都可执行任意命令或代码。

某些漏洞无法回显,所以一般情况下需要反弹 shell。
黑盒测试可以通过 http 头发现反序列化利用处。

参考文章
常见的Web漏洞——反序列化漏洞

1.3:POP 链

POP(Property-Oriented Programing,面向属性编程),从现有运行环境中寻找一系列能够调用的代码或指令,然后根据需求将这些指令整合成有逻辑的、能实现需求的代码。称为 POP 链。

一般的 CTF 反序列化,存在漏洞的地方在魔术方法(或反射)中,可以通过自动调用魔术方法(或反射)来达到攻击效果。
但是当注入点存在普通的类方法中,通过自动调用的方法就失效了,此时需要找到普通类与魔术方法(或反射)之间的联系,理出一种逻辑思路,通过这种逻辑思路来构造一条 pop 链,从而达到攻击的目的。

参考文章

php反序列化-POP链的构造利用

php反序列化之pop链构造

【Java安全】反序列化-CC3反序列化漏洞POP链分析

2:PHP 反序列化

在这里插入图片描述

2.1:序列化&反序列化

PHP 中的序列化与反序列化:

  • serialize():序列化。
  • unserialize():反序列化。

示例

<?php 

	class Stu {
		public $name = 'Bob';
		public $age = 18;
	
		public function demo() {
			echo "Hello";
		}
	}

	$stu = new Stu(); 

	print_r($stu);
	echo "\n\n----------\n\n";

	// 进行序列化
	$stus = serialize($stu);

	print_r($stus);
	echo "\n\n----------\n\n";

	// 进行反序列化
	$stus = unserialize($stus);
	
	print_r($stus);
	echo "\n\n----------\n\n";
?>

在这里插入图片描述

序列化结果说明:

在这里插入图片描述

2.2:魔术方法

魔术方法是 PHP 面向对象中特有的特性,在特定的情况下被触发,然后在魔术方法中的命令代码就会被执行。

示例

<?php
	class Stu {
		public $name = 'Bob';
		public $age = 18;

		function __construct() {
			echo "\n对象被创建了__construct()";
		}

		function __wakeup() {
			echo "\n执行了反序列化__wakeup()\n";
		}

		function __toString() {
			echo "\n对象被当做字符串输出__toString\n";
			return 'asdsadsad';
		}

		function __sleep() {
			echo "\n执行了序列化__sleep\n";
			return array('name', 'age');
		}

		function __destruct() {
			echo "对象被销毁了__destruct()\n";
		}
	}

	$stu = new Stu();

	echo "\n";

	// 序列化
	$stu_ser = serialize($stu);

	echo "\n";
	print_r($stu_ser);
	echo "\n";

	// 当成字符串输出
	echo "$stu";
	echo "\n";

	// 反序列化
	$stu_unser = unserialize($stu_ser);

	print_r($stu_unser);
	echo "\n";
?>

在这里插入图片描述

参考文章:

PHP反序列化漏洞详解
https://blog.csdn.net/LJH1999ZN/article/details/123338591

PHP反序列化与魔术方法
https://www.cnblogs.com/20175211lyz/p/11403397.html

php反序列化完整总结
https://xz.aliyun.com/t/12507#toc-15

3:JAVA 反序列化

在这里插入图片描述

3.1:序列化&反序列化

Java 中的序列化与反序列化:

  • 序列化:ObjectOutputStream -> writeObject()
  • 反序列化:ObjectInputStream -> readIObject()

序列化方法对参数指定的 obj 对象进行序列化,把字节序列写到目标输出流中,按 Java 的标准约定文件扩展名为 .ser。

反序列化方法从一个源输入流中读取字节序列,再把字节序列反序列化为一个对象,并将其返回。

示例:以下代码写在 Test.java 文件。
1、javac Test.java
2、java Test

import java.io.*;

public class Test {
    public static void main(String[] args) {
        try {
            // 序列化
            serialize();

            // 反序列化
            deserialize();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void serialize() throws IOException {
        Student student = new Student();
        student.setName("Bob");
        student.setAge(18);
        student.setScore(1000);

        ObjectOutputStream objectOutputStream =
                new ObjectOutputStream(new FileOutputStream(new File("student.txt")));
        objectOutputStream.writeObject(student);
        objectOutputStream.close();

        System.out.println("序列化成功!已经生成 student.txt 文件");
        System.out.println("==============================================");
    }

    public static void deserialize() throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream =
                new ObjectInputStream(new FileInputStream(new File("student.txt")));
        Student student = (Student) objectInputStream.readObject();
        objectInputStream.close();

        System.out.println("\n反序列化结果为:");
        System.out.println(student);
    }
}

class Student implements Serializable {
    private String name;
    private Integer age;
    private Integer score;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setScore(Integer score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student:" + '\n' +
                "name = " + this.name + '\n' +
                "age = " + this.age + '\n' +
                "score = " + this.score + '\n';
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Java 序列化的结果不可读。

Java 序列化的标志特征参考:

  • 数据以 aced 开头,那么这是一段 16 进制的 Java 序列化数据。
  • 数据以 rO0 开头,基本可以确定这是一段 base64 编码的 Java 序列化数据。

3.2:反射机制

Java 中没有魔术方法,但是有反射(Reflection)机制。

Java 反射机制是一种动态获取信息以及动态调用对象方法的功能。即在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个类的成员变量和方法,可以了解任意一个对象所属的类,可以调用任意一个对象的属性和方法。

Java 反射机制允许在运行时获取和操作类、对象、方法、字段等信息,而不需要在编译时知道这些信息的确切类型。反射机制为开发者提供了一种动态获取和操作类的能力,使得编写更灵活、通用和可扩展的代码成为可能。

一般利用反射机制来构造一个执行命令的对象或直接调用一个具有命令/代码执行功能的方法,以此实现任意代码执行。

示例
1、javac Person.java ReflectionExample.java
2、java ReflectionExample

Person.java 文件:

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void introduce() {
        System.out.println("My name is " + name + " and I am " + age + " years old.");
    }
}

ReflectionExample.java 文件:

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectionExample {
    public static void main(String[] args) throws Exception {
        // 使用反射创建 Person 类的实例
        Class<?> personClass = Class.forName("Person");
        Constructor<?> constructor = personClass.getConstructor(String.class, int.class);
        Object personObject = constructor.newInstance("John Doe", 30);

        // 使用反射调用 Person 类的 introduce 方法
        Method introduceMethod = personClass.getMethod("introduce");
        introduceMethod.invoke(personObject);
    }
}

在这里插入图片描述

3.3:相关资源

参考文章
JAVA反序列化-反射机制

Java 反序列化工具 ysoserial
https://github.com/frohoff/ysoserial

Java 反序列化工具 SerializationDumper
https://github.com/NickstaDB/SerializationDumper/tree/1.12


非鬼亦非仙,一曲桃花水。

——《生查子 · 独游雨岩》(宋)辛弃疾

更多推荐

算法通关村-----回溯模板如何解决排列组合问题

组合总和问题描述给你一个无重复元素的整数数组candidates和一个目标整数target,找出candidates中可以使数字和为目标数target的所有不同组合,并以列表形式返回。你可以按任意顺序返回这些组合。candidates中的同一个数字可以无限制重复被选取。如果至少一个数字的被选数量不同,则两种组合是不同的

论文阅读:AugGAN: Cross Domain Adaptation with GAN-based Data Augmentation

Abstract基于GAN的图像转换方法存在两个缺陷:保留图像目标和保持图像转换前后的一致性,这导致不能用它生成大量不同域的训练数据。论文提出了一种结构感知(Structure-aware)的图像转换网络(image-to-imagetranslationnetwork)。ProposedFramework为了将图像正

基于复旦微的FMQL45T900全国产化ARM开发开发套件(核心板+底板)

TES745D是我司自主研制的一款基于上海复旦微电子FMQL45T900的全国产化ARM核心板(模块)。该核心板将复旦微的FMQL45T900(与XILINX的XC7Z045-2FFG900I兼容)的最小系统集成在了一个87*117mm的核心板上,可以作为一个核心模块,进行功能性扩展,能够快速的搭建起一个信号平台,方便

在Scrapy框架中使用隧道代理

今天我要和大家分享一些实战经验,教你如何在Scrapy框架中使用隧道代理。如果你是一个热爱网络爬虫的开发者,或者对数据抓取和处理感兴趣,那么这篇文章将帮助你走上更高级的爬虫之路。首先,让我们简单介绍一下Scrapy框架。Scrapy是一个强大的Python网络爬虫框架,它能够帮助我们高效地抓取网页数据并进行处理。使用S

京东商品详情数据采集接口

使用京东商品详情接口的具体流程如下:注册账号并登录。填写应用相关信息,包括应用名称、应用描述、应用回调地址等,然后提交申请。审核通过后,进入应用管理页面,点击“应用信息”,获取应用Key和应用Secret。获取商品详情接口。京东提供了丰富的API接口,不同的接口可以获取不同的商品信息。这里以获取商品详情接口为例。获取A

电容笔哪个厂家的产品比较好?开学季值得买电容笔

现在,几乎每个人都有一个ipad平板,可以帮助你解决很多工作和学习上的难题,比如工作时的整理文档,做一些简单的PPT,以及在学习上记录笔记等等。所以,用一支好用的电容笔来搭配iPad是非常重要的。在这里,我给大家安利几款既使用方便,又价格不贵的电容笔!一、电容笔和ApplePencil的区别以及电容笔的优势1、压感电容

zabbix监控

一、zabbix概述1.zabbix是什么?zabbix是一个基于web界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。zabbix能监视各种网络参数,保证服务器系统的安全运营,并提供灵活的通知机制以让系统管理员快速定位、解决存在的各种问题。zabbix由两部分构成,zabbixserver与可选组件z

【大规模 MIMO 检测】基于ADMM的大型MU-MIMO无穷大范数检测研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。⛳️座右铭:行百里者,半于九十。📋📋📋本文目录如下:🎁🎁🎁目录💥1概述📚2运行结果🎉3参考文献🌈4Matlab代码实现💥1概述针对大型多用户(MU)多输入多输出(MIMO)无线

MATLAB的输入与输出函数

标题输入:input()1.输入单个数值2.输入字符串3.输入以空格隔开的一行数值4.输入以空格与换行符隔开的多行数值输出1.disp()(1)输出单个数值(2)输出一维数组(3)输出矩阵(4)输出字符串2.fprintf()(1)输出格式化的单个数值(2)输出格式化的一维数组(3)输出格式化的矩阵(4)输出格式化的字

PostgreSQL 数据类型

文章目录PostgreSQL数据类型说明PostgreSQL数据类型使用单引号和双引号数据类型转换布尔类型数值类型整型浮点型序列数值的常见操作字符串类型日期类型枚举类型IP类型JSON&JSONB类型复合类型数组类型PostgreSQL数据类型说明PGSQL支持的类型特别丰富,大多数的类型和MySQL都有对应的关系名称

参议院算法Java

Dota2的世界里有两个阵营:Radiant(天辉)和Dire(夜魇)Dota2参议院由来自两派的参议员组成。现在参议院希望对一个Dota2游戏里的改变作出决定,他们以一个基于轮为过程的投票进行。在每一轮中,每一位参议员都可以行使两项权利中的一项:禁止一名参议员的权利:参议员可以让另一位参议员在这一轮和随后的几轮中丧失

热文推荐