反序列化 漏洞
0x00 序列化与反序列化
语言结构
-
序列化的定义是,将对象的状态信息 转换为可以存储或传输的形式 (字符串)的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
-
简单的说,序列化就是把—个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台、安全的进行通信。
序列化的用途
- 方便对象在网络中的传输与存储
序列化与反序列的过程
-
序列化:将对象转换为流,利于储存和传输的格式
-
反序列化:将流转换为对象
序列化的过程
-
首先创建一个类,类名是 Stu,该类有 4 个属性。用这个 Stu 类 new 一个$stu1 对象,使用 serialize() ,将 $stu1 这个对象序列化成一个字符串,这样的字符串容易传输和存储。
-
测试代码:
// class.php
<?php
class Stu{
public $name;
public $sex;
public $age;
Public $score;
}
$stu1 = new Stu();
$stu1->name = "ichunqiu";
$stu1->sex = true;
$stu1->age = 18;
$stu1->score = 89.9;
echo serialize($stu1);
?>
序列化的结果
-
O:3:"Stu":4 // O 代表 Object 对象;3 代表 对象名有三个字符;4 代表 对象中有 4 个属性
-
{s:4:"name"; // s 代表 属性数据类型,s 代表 string,i 代表 int;4 代表 属性名 长度;name 是 属性名
-
s:8:"ichunqiu"; // s 代表 属性数据类型,s 代表 string,i 代表 int;8 代表 属性值 长度;ichunqiu 是 属性值
-
b:1; // b 代表 bool
-
后面的属性名和属性值依次类推
反序列化的过程
- 测试代码:
<?php
include "class.php";
$stu =
<<<STR
O:3:"Stu":4:{s:4:"name";s:8:"ichunqiu";s:3:"sex";b:1;s:3:"age";i:18;s:5:"score";d:89.900000000000006;}
STR;
$stu1 = unserialize($stu1);
var_dump($stu1);
?>
反序列化的结果
0x01 反序列化漏洞 概述
PHP 反序列化漏洞 概述
-
概念:PHP 反序列化漏洞也叫 PHP 对象注入
-
危害:这种类型的漏洞虽然有些难以利用,但一旦利用成功就会造成非常危险 的后果
-
形成原因:程序没有对用户输入的反序列化字符串进行检测 ,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell 等一系列不可控的后果。反序列化漏洞并不是 PHP 特有,也存在于 Java、 Python 等语言之中,但其原理基本相通
常见的魔法函数介绍
- 在学习过序列化与反序列化的过程之后,我们知道,序列化本身并不存在任何漏洞 ,但是搭配上 PHP 的魔法函数 ,整个程序的执行流程就将变得可控 。
-
__construct():当一个对象创建 时被调用(相当于 c++ 的构造函数)。
-
__destruct(): 当一个对象销毁 时被调用(相当于 c++ 的析构函数)。
-
__sleep(): 当在对象被序列化之前 被调用。
-
__wakeup(): 当在 unserialize()函数执行反序列化时 调用。
-
__toString(): 当一个对象被当作一个字符串 时使用。
测试代码
<?php
class Test{
public $str='ichunqiu';
function __construct()
{
echo '_construct() is execute!!!<br>';
}
function __destruct()
{
echo '<br>_destruct() is execute!!!<br>';
@system($this->str);
}
function __wakeup()
{
echo '_wakeup() is execute!!!<br>';
$fp = fopen("shell.php","a+");
fwrite($fp,$this->str);
fclose($fp);
}
function __sleep()
{
echo '_sleep() is execute!!!<br>';
return array('str');
}
function __tostring()
{
echo 'tostring() is execute!!!<br>';
return "testvalue";
}
}
$test = new Test();
echo "hello!!!".$test.'<br>';
echo serialize($test).'<br>';
var_dump(unserialize($_GET['code']));
?>
测试代码执行结果
0x02 反序列化漏洞 原理
- 程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell 等一系列不可控的后果
0x03 反序列化漏洞 利用
绕过 __wakeup()
绕过原理
- 当序列化后的字符串的属性个数字段大与真实属性个数 时,会跳过__wekeup()函数 执行
绕过示例
- 正常属性值 1,__wekeup()函数 正常执行
- 比之前属性1大的2,__wekeup()函数 被成功绕过,whoami命令成功执行
0x04 反序列化漏洞 防御
-
不要反序列化不可信的数据
-
给反序列数据加密签名,并确保解密在反序列之前
-
给反序列化接口添加认证授权