前几天打省赛,遇到一个seesion反序列化的题,当时没做出来,今天复盘学习了一下,写个笔记
什么是SESSION
首先session是什么,就是一个会话控制,这样描述很肤浅,还得往更深的层次研究,这里是我学习的一个大佬的文章,讲的很透彻什么是session(一定要看啊,不然无法理解)
大概流程就是,当你打开一个页面,php会先判断你有没有sessionid,没有就生成一个id,当你结束后会生成一个文件,当判断出你有id时,php会直接读取上回生成的文件,把里面的东西反序列化出来。
这一套操作通常是用来,用户持续保持会话的,也就是用户退出页面后,再访问该页面,也能通过id访问到上回访问的资源。
php session中的序列化
再来讲讲php的相关序列化
session后产生的id文件中的内容就是一段序列化
然而php中的下面这个选项,可以选择序列化的方式
session.serialize_handler = php
session.serialize_handler = php_binary
session.serialize_handler = php_serialize
这三种都是他的序列化方式
下面时一段源码
<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['name'] = 'spoock';
var_dump($_SESSION);
在 php_serialize 引擎下,session文件中存储的数据为:
a:1:{s:4:"name";s:6:"spoock";}
php 引擎下文件内容为:
name|s:6:"spoock";
php_binary 引擎下文件内容为:
names:6:"spoock";
上面就介绍了这三种序列化的形式,理解这三种序列化很重要
PHP session序列化漏洞
本来这种序列化是没有漏洞的,可我们经常需要跨文件操作,当两个文件的php序列化解释器不一样时,漏洞就由此产生了
由实例来解释一下吧,下面这是一段设置序列化引擎的php文件
同时还向session文件中写入了内容(这里使用的php_serialize引擎,要求php版本>5.5.4,当时自己也是弄了半天才发现)
<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
echo "session_id(): ".session_id()."<br>";
$_SESSION['ryat'] = '|O:1:"A":1:{s:1:"a";s:2:"xx";}';
?>
最后存储的session文件内容为
好了,就是这样一个序列化,假如当我们进入另一个网页时,该网页首先会看你有没有一个sessionid,有的话就直接根据id访问session文件,将里面的内容反序列化出来
又假如这个网页使用的序列化引擎是php引擎,根据php引擎的解释,面对这段序列化他则会认为a:1:{s:4:“ryat”;s:30:“是他的对象,而"A”:1:{s:1:“a”;s:2:“xx”;}"是里面的内容
最后解释出来的内容也和原本的内容大相径庭了
空口无凭,直接用用实例说话
<?php
session_start();
class A {
public $a = 'aa';
function __wakeup() {
echo $this->a;
}
}
按照我们刚才的分析,最后页面输出的应该是xx对吧,最后结果也的确如此,
本来第二个php文件输出的应该是对象A中的元素,也就是aa,但是被我们这样一操作最终输出的居然是xx,也就是绕过了 $a=aa这条语句,这就是漏洞的产生
CTF中的应用
上面的例子我是在php文件中直接向session文件中写入了’|O:1:“A”:1:{s:1:“a”;s:2:“xx”;}’
然而在实际CTF和应用中通常都是通过GET注入的方式达到注入效果
buuctf也是有个相关的题 [HarekazeCTF2019]Easy Notes
没有$_SEESION变量赋值
攻击思路
先找到两个有不同引擎的php文件
然后往a.php注入对应的payload
再访问b.php注入就达成了
如何防范
其实也没啥事,这个漏洞的根本原因就是php序列化引擎不一样导致的,只需要各个文件都用一个引擎就好了。防范也就没啥好说的了。
小总结
总结一下吧,当你打开一个页面,session所作出的具体反应就是先看你是否带有session id,如果有的话就直接读取你上一次会话结束后存储在本地的session文件,如果php序列化引擎不一样,解释的结果就不一样,就导致了漏洞的产生(如果没有sessionid,则会给你生成一个sessionid,以便于在关闭页面时,存储一个session文件)