不安全的反序列化

文章目录

  • [一、 序列化与反序列化](#一、 序列化与反序列化)
    • [1.1 引例](#1.1 引例)
    • [1.2 序列化实例](#1.2 序列化实例)
      • [1.2.1 定义一个类](#1.2.1 定义一个类)
      • [1.2.2 创建对象](#1.2.2 创建对象)
      • [1.2.3 反序列化](#1.2.3 反序列化)
      • [1.2.4 对象注入](#1.2.4 对象注入)
  • [二、 漏洞何在](#二、 漏洞何在)
    • [2.1 漏洞触发](#2.1 漏洞触发)
      • [2.1.1 有一个类](#2.1.1 有一个类)
      • [2.1.2 有一个对象](#2.1.2 有一个对象)
      • [2.1.3 反序列化执行代码](#2.1.3 反序列化执行代码)
    • [2.2 为什么会这样](#2.2 为什么会这样)
  • 三、反序列化漏洞攻防
    • [3.1 PHP反序列化实例](#3.1 PHP反序列化实例)
    • [3.2 Java 反序列化实例](#3.2 Java 反序列化实例)
    • [3.3 反序列化漏洞防御](#3.3 反序列化漏洞防御)

A8:2017-不安全的反序列化

A08:2021-Software and Data Integrity Failures

对象(真实存在) ----通过序列化 --> 字符串、Json ---通过反序列化--->对象

为什么要序列化?

序列化,"将对象的状态信息转换为可以存储或传输的形式的过程",这种形式⼤多为字节流、字符串、json 串。在序列化期间内,将对象当前状态写⼊到临时或永久性的存储区。以后,就可以通过从存储区中读取或还原(反序列化)对象的状态,重新创建该对象。简单的说,序列化就是把一个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台安全的进⾏通信。

一、 序列化与反序列化

1.1 引例

JSON 数据是数据的一种表达形式,与Python ⾥的字典类似。

php 复制代码
// json.php

$stu = array(
'name'   => 'ghui', 'age'	=> 18,
'sex'	=> true, 'score' => 89.9
);

// echo $stu; //echo不能输出数组,可以使用var_dump()进行输出
//var_dump($stu);

$stu_json = json_encode($stu); //进行json编码
echo $stu_json; //json编码能够用echo输出,说明json数据能够存储和传输

echo "<hr />";

$stu_json = isset($_GET['stu'])?$_GET['stu']:$stu_json;
$stu = json_decode($stu_json); //将ghui数据重新还原成对象
var_dump($stu); #强制转换成字符串

json编码结果

sh 复制代码
{"name":"ghui","age":18,"sex":true,"score":89.9}

结果很像python中的字典

isset() 函数用于检测变量是否已设置并且非 NULL。如果为空,则返回false,否则返回true.

验证:

sh 复制代码
?stu={"name":"ghui","age":19,"sex":true,"score":89.9}

补充:

echo 只能输出文本字符串,不能输出数组

输出数组可以使用var_dump 进行输出。

var_dump() 函数用于输出变量的相关信息。

var_dump() 函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构。

1.2 序列化实例

1.2.1 定义一个类

php 复制代码
//   stu.class.php

class Stu{  //定义了一个类,类的名字为Stu
public $name; 
public $age; 
public $sex; 
public $score;
}

解释:

PHP 提供了四个文件包含的语句,四个语句之间略有不同。

语句 区别
include() 多次包含,多次执行; 如果包含失败,脚本产生警告,继续运行。
include_once() 多次包含,一次执行; 如果包含失败,脚本产生警告,继续运行。
require() 多次包含,多次执行; 如果包含失败,脚本产生错误,结束执行.
require_once() 多次包含,一次执行; 如果包含失败,脚本产生错误,结束执行。

1.2.2 创建对象

创建一个对象,并对该对象进⾏序列化操作,将对象转化为可以存储、传输的字符串。

php 复制代码
// serialize.php

include   "./stu.class.php"; //包含一下stu.class.php文件,主要是让能够使用里面的Stu类

$stu1 = new Stu();

$stu1 -> name	= "zhangsan"; //$stu1.name

$stu1 -> age	= 24;
$stu1 -> sex	= true;
$stu1 -> score   = 99.9;

// echo $stu1; //echo输出不了字符串
// var_dump($stu1); 

$_stu1 = serialize($stu1); //要想输出,必须将对象stu1进行序列化-->字符串
echo $_stu1; //输出序列化后的字符串

serialize() 函数用于序列化对象或数组,并返回一个字符串。

serialize() 函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变。

如果想要将已序列化的字符串变回 PHP 的值,可使用 unserialize()

序列化后的字符串:

sh 复制代码
O:3:"Stu":4:{s:4:"name";s:8:"zhangsan";s:3:"age";s:2:"24";s:3:"sex";N;s:5:"score";d:99.900000000000006;}

解释:

O :代表object

3 :代表类名的字符数,Stu,三个字符,所以是3

4 :代表有4个变量

1.2.3 反序列化

将字符串转化为对象。

php 复制代码
//   unserialize.php

include "./stu.class.php"; //文件包含

$stu1_ser = 'O:3:"Stu":4:{s:4:"name";s:8:"zhangsan";s:3:"age";s:2:"24";s:3:"sex";N;s:5:"score";d:99.900000000000006;}'; //定义一个变量,放入序列化后的字符串。

$stu1_obj = unserialize($stu1_ser); 
var_dump($stu1_obj);

unserialize() 函数用于将通过 serialize()函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。

1.2.4 对象注入

如果反序列化字符串,Web ⽤⼾可以控制,则造成对象注⼊。

php 复制代码
// $stu1_seria = 'O:3:"Stu":4:{s:4:"name";s:8:"zhangsan";s:3:"age";s:2:"24";s:3:"sex";N;s:5:"score";d:99.900000000000006;}';

//将stu_ser通过GET来获取序列化后的数据:
$stu1_ser = $_GET['stu1_ser'];

$stu1_obj = unserialize($stu1_ser); 
var_dump($stu1_obj);

PHP 的反序列化漏洞也叫PHP 对象注⼊,是一个⾮常常⻅的漏洞,这种漏洞在某些场景下虽然有些难以利⽤,但是一旦利⽤成功就会造成⾮常危险的后果。

我们这时可以将zhangsan改为phpinfo(); 来试着执行以下,注意:这里修改的时候还要修改它的长度,zhangsan的字符长度为8,而phpinfo();的长度为10

我们发现输出了字符phpinfo();,而没有执行phpinfo();,那么漏洞在哪里呢?

二、 漏洞何在

2.1 漏洞触发

2.1.1 有一个类

sh 复制代码
//   vul.class.php

class Vul{
public $str = "lisi";

function __destruct(){
//echo "This is function __destruct()"; 
@eval($this -> str);

}
}

解释:

eval 是一个危险语句,因为它可以将字符串当作PHP代码来执行。

​ 例如:

​ 如果编辑php代码为:

php 复制代码
<?php
    $str="phpinfo();";  
    echo $str;   //只会输出字符串:  phpinfo();
?>

​ 而如果将echo改为eval:

php 复制代码
<?php
    $str="phpinfo();";  
    eval($str);  //执行phpinfo();
?>

结果:

2.1.2 有一个对象

php 复制代码
// test.php

include './vul.class.php';

$s = new Vul(); 
echo serialize($s);  //序列化操作
echo "<hr />";

$_s = $_GET['s_ser'];
$s = unserialize($_s);  //反序列化操作
var_dump($s);

序列化后:

sh 复制代码
O:3:"Vul":1:{s:3:"str";s:4:"lisi";}

2.1.3 反序列化执行代码

sh 复制代码
?obj=O:3:"Vul":1:{s:3:"str";s:10:"phpinfo();";}

我们现在将lisi 换成phpinfo(); 来执行一下试试:

怎么执行的呢?

​ 其实是因为危险函数eval,我们发现eval在__destruct() 函数里面,而我们没有调用这个函数啊,怎么就触发这个函数了呢。

2.2 为什么会这样

__destruct(),会被对象⾃动调⽤。

以 __ 开头的函数,是PHP 中的魔术⽅法。类中的魔术⽅法,在特定情况下会⾃动调⽤。即使魔术⽅法在类中没有被定义,也是真实存在的。

魔术方式 触发条件
__construct() 在创建对象时⾃动调⽤,构造函数
__destruct() 在销毁对象时⾃动调⽤,析构函数
__call(); __callStatic(); __get(); __set(); __isset(); __unset(); __sleep(); __wakeup(); toString(); __invoke(); __set_state(); __clone(); __debuginfo(); 创建对象之前触发

漏洞形成的根本原因就是程序没有对⽤⼾输⼊的反序列化字符串进⾏检测,导致反序列化过程可以被恶意控制,进而造成代码执⾏、GetShell 等一系列不可控的后果。反序列化漏洞并不是PHP 特有的,也存在于Java、Python 语⾔中,其原理基本相同。

三、反序列化漏洞攻防

3.1 PHP反序列化实例

typecho 反序列化漏洞

3.2 Java 反序列化实例

Weblogic < 10.3.6 'wls-wsat' XMLDecoder 反序列化漏洞

S2-045 Remote Code Execution Vulnerablity

JBoss 5.x/6.x 反序列化漏洞

fastjson 1.2.24 反序列化导致任意命令执⾏漏洞Fastjson 1.2.47 远程命令执⾏漏洞

Apache Shiro 1.2.4反序列化漏洞(CVE-2016-4437)

3.3 反序列化漏洞防御

  • 升级组件到最新版本;
  • ⿊⽩名单过滤敏感字符;
  • 禁⽤反序列化功能;
    149/)

fastjson 1.2.24 反序列化导致任意命令执⾏漏洞Fastjson 1.2.47 远程命令执⾏漏洞

Apache Shiro 1.2.4反序列化漏洞(CVE-2016-4437)

相关推荐
工程师老罗5 小时前
如何在Android工程中配置NDK版本
android
Hello.Reader6 小时前
Flink ZooKeeper HA 实战原理、必配项、Kerberos、安全与稳定性调优
安全·zookeeper·flink
智驱力人工智能7 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算
七夜zippoe7 小时前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
数据与后端架构提升之路7 小时前
论系统安全架构设计及其应用(基于AI大模型项目)
人工智能·安全·系统安全
Fcy6488 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满8 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
Libraeking8 小时前
破壁行动:在旧项目中丝滑嵌入 Compose(混合开发实战)
android·经验分享·android jetpack
代码游侠8 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
Harvey9039 小时前
通过 Helm 部署 Nginx 应用的完整标准化步骤
linux·运维·nginx·k8s