PHP Session反序列化漏洞原理与利用详解
本文深入解析PHP Session的存储机制与序列化处理器差异导致的反序列化漏洞。通过对比php_serialize与php引擎对'|'符号的解析歧义,结合具体代码示例与Payload构造,演示了如何在不同Handler环境下触发__wakeup魔法方法,为开发者提供防御思路与安全排查依据。
Session请求与运行机制
当用户首次访问网站时,session_start()函数会在服务器端创建一个唯一的Session ID,并通过HTTP响应头将Cookie中的PHPSESSID传递给客户端。服务器同时以该ID命名创建会话文件,用于存储用户状态。后续请求中,客户端携带相同的Session ID,服务器根据此ID定位对应的会话文件并读取数据,从而实现用户状态的保持。
在PHP内部,当启动会话时,系统会根据客户端传来的PHPSESSID获取现有的会话数据。PHP会自动反序列化Session文件内容,填充到$_SESSION超级全局变量中。如果未找到对应数据或未发送Session ID,则会创建新的Session ID及对应的会话文件(通常命名为sess_前缀加ID)。
Session存储与序列化配置
PHP默认将Session数据存储于文件系统而非内存中,具体行为由session.save_handler配置项决定。会话文件的文件名通常为sess_加上Session ID,文件内容为序列化后的值。

PHP提供了多种序列化处理引擎,不同的引擎对数据的编码和解码方式存在显著差异:

- php处理器:这是PHP 5.x时代的默认引擎。它以原始字节形式存储键名和值,中间使用竖线‘|’作为分隔符。格式通常为
|key|value。

- php_binary处理器:采用更紧凑的二进制格式。先以1字节的长度表示键名,紧接着是键名字符串和值。

- php_serialize处理器:PHP 5.5.4之后推荐的引擎。它对整个
$_SESSION数组进行一次标准的PHP序列化操作,不引入额外的分隔符逻辑。

反序列化漏洞原理剖析
Session漏洞的核心在于存储与读取时使用了不同的序列化处理器。当脚本写入Session时使用一种Handler,而读取出错或特定条件下使用另一种Handler时,数据结构会被错误解析。
以下是一个典型的冲突场景:页面A使用php_serialize存储数据,页面B使用默认的php引擎读取数据。
第1步:构造存储环境
在包含以下代码的`session.php`中,强制设置存储处理器为php_serialize,并将GET参数user存入Session:
<?php
error_reporting(0);
ini_set('session.serialize_handler','php_serialize');
session_start();
$_SESSION['username'] = $_GET['user'];
echo "<pre>";
var_dump($_SESSION);
echo "</pre>"
?>第2步:准备利用载体
在同一服务器下创建session2.php,这里注意ini_set被移除或设置为默认的php处理器:
<?php
error_reporting(0);
// ini_set('session.serialize_handler','php'); // 默认即为php
session_start();
class user {
var $name;
var $age;
function __wakeup(){
echo "hello ".$this->name." !";
}
}
?>第3步:分析解析歧义
当我们在session.php中输入恶意Payload时:
URL: `session.php?user=|O:4:"user":2:{...}`
由于session.php使用php_serialize,它会将整个字符串(包括开头的|)作为一个正常的值存入序列化数组中。Session文件的内容大致如下:
a:1:{s:8:"username";s:XX:"|O:4...
然而,当请求session2.php时,PHP使用php引擎解析Session文件。该引擎将|视为键值分隔符。它会尝试将|之前的部分(可能是空的或者是之前的键)作为键名,而将|之后的整段字符O:4:"user":2:{...}当作$_SESSION['xxx']的值进行反序列化。
这种错位导致了一个精心构造的对象序列化字符串被直接送入反序列化过程,进而触发目标类中的__wakeup()或其他魔术方法。
第4步:构造有效载荷 (Payload)
我们需要构造一个符合user类的序列化字符串。首先编写生成脚本payload.php:
<?php
class user {
var $name;
var $age;
}
$a = new user();
$a ->age="888";
$a ->name="cc";
echo serialize($a);
?>生成的值为:`O:4:"user":2:{s:4:"name";s:2:"cc";s:3:"age";s:3:"888";}`
将其拼接在竖线后作为输入:
|O:4:"user":2:{s:4:"name";s:2:"cc";s:3:"age";s:3:"888";}
漏洞验证与结果
访问session.php并传入上述Payload,成功将含竖线的恶意序列化字符串写入Session文件。
随后访问session2.php。由于php引擎在读取时将恶意对象进行了反序列化,触发了__wakeup方法,控制台输出预期的结果:
Hello cc !

以上就是PHP Session反序列化漏洞的原理分析与复现的详细讲解,更多关于PHP安全加固与漏洞防御的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









