PHP Session反序列化漏洞
PHP Session反序列化漏洞
session是什么
session在计算机网络应用中被称作会话控制,在服务器端创建但是保存于服务器,session对象存储特定用户所需的属性以及配置信息,一旦开启了session会话,便可以在网站的任何页面使用或保持这个会话,php session是一种特殊的变量,可以存储关于用户的会话信息,或者更改用户会话的设置。
cookie存储在客户端,而session存储在服务端,当开启一个session时,php会创建一个随机的session id,每个用户的Session id都是唯一的,而且Session id 与服务器上存储该用户Session数据的文本文件名称相同
因此Session ID会分别保存在客户端和服务器端两个位置
- 客户端,使用临时的Cookie保存在浏览器指定目录中,Cookie名称默认为“PHPSESSION”
- 服务器端,以文本文件形式保存在指定的Session目录中
当php发现cookie里面没有session,就会调用php_session_create_id函数创建一个新的会话,并且在响应包头中通过set-cookie参数发给客户端保存
当客户端cookie被禁用的情况下,php会自动将session id添加到url参数、form、hidden字段中,但是这需要php.ini中的session.use_trans_sid设为开启,也可以在运行时调用ini_set()函数来设置这个配置项
php session会话开始之后,php就会把会话中的数据设置到$_SESSION变量中,当php停止运行时,它会自动读取$__SESSION中的内容,并将其进行序列化,然后发送给会话保存管理器来进行保存。默认情况下,php使用内置的文件会话保存管理器来完成对session的保存,也可以通过配置项session.save_handler来修改所要采用的会话保存管理器,对于文件会话保存管理器,会将会话数据保存到配置项session.save_path所指定的位置
php session在php.ini里面的一些配置
1 | session.serialize_handler = php //定义用来session序列化/反序列化的处理器名字,默认使用php,还有其他引擎,且不同引擎的对应的session的存储方式不相同 |
php session不用引擎的存储机制
PHP session的存储机制是由session.serialize_handler来定义引擎的,默认是以文件的方式存储,且存储的文件是由sess_sessionid来决定文件名的,当然这个文件名也不是不变的,一般session.serialize_handler定义的引擎有以下三种
处理器名称 | 存储格式 |
---|---|
php | 键名+竖线+经过serialize()函数序列化处理的值 |
php_binary | 键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值 |
php_serialize | 经过serialize()函数序列化处理的数组 |
不同处理器的差别可以看下面
1 |
|
分别得到
user|s:5:”Kenoe”;
!KenoeKenoeKenoeKenoeKenoeKenoe___s:5:”Kenoe”; //这里键名修改了
a:1:{s:4:”user”;s:5:”Kenoe”;}
如果题目里面发现不同的php文件用了不同的引擎,那么可以构造payload来写入我们想要的内容,比如下面
1 | //session.php |
session.php传入一个|O:4:”user”:1:{s:4:”name”;s:4:”Kino”;}
这个时候的session为
a:1:{s:7:”session”;s:38:”|O:4:”user”:1:{s:4:”name”;s:4:”Kino”;}”;}
然后访问class.php,这个时候会输出
1 | wakeup |
可以看到由于不同的反序列化引擎,原来session的值会反序列化成user类,然后也会执行对应的wakeup函数和析构函数
session反序列化题目
题目地址:http://web.jarvisoj.com:32784/index.php
1 |
|
看一下phpinfo
同时还有这个也是开着的
Session 上传进度
当 session.upload_progress.enabled INI 选项开启时,PHP 能够在每一个文件上传时监测上传进度。 这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态
当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,上传进度可以在$_SESSION中获得。 当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据, 索引是 session.upload_progress.prefix 与 session.upload_progress.name连接在一起的值
所以我们可以构造一个表单来上传文件
1 | #upload.php |
1 |
|
然后修改filename为序列化字符串,根据回显去修改我们的值可以得到flag