一、前言
最近在做BUUCTF时,遇到了Session反序列化相关的题目,觉得还是挺重要的,就记录一下
二、Session 和 Cookie
之前也有专门去找过一些文章来理解cookie 和 session之间的关系,但都是半懂不懂的
2.1 session 和 cookie 简介
什么是session?
在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。
这些话也是见过很多次了,简而言之,session是用来保持会话的(防止页面间的跳转导致会话终止)
什么是cookie?
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
简而言之,cookie是用来验证用户身份的
这样看来,两者好像并不冲突,那么是不是可以认为不同的Cookie(用户身份)可以有不同的session(会话)?或者说两者可以是一种包含关系?
2.2 session_start() 函数
当第一次访问网站时,Seesion_start()函数就会创建一个唯一的Session ID,并自动通过HTTP的响应头,将这个Session ID保存到客户端Cookie中。同时,也在服务器端创建一个以Session ID命名的文件,用于保存这个用户的会话信息。
这样的话是不是说,当同一个用户再次访问网站时,客户端携带Cookie向服务端发送请求,服务端接收到cookie以及其中session,再去寻找与该session同名的文件,最终达到检验用户信息的目的。
观察这个cookie,可以看到PHPSESSID,说明该网页使用了session_start() 函数,显而易见,Cookie中包含了session
当会话自动开始或者通过 session_start() 手动开始的时候, PHP 内部会依据客户端传来的PHPSESSID来获取现有的对应的会话数据(即session文件), PHP 会自动反序列化session文件的内容,并将之填充到 $_SESSION 超级全局变量中。如果不存在对应的会话数据,则创建名为sess_PHPSESSID(客户端传来的)的文件。如果客户端未发送PHPSESSID,则创建一个由32个字母组成的PHPSESSID,并返回set-cookie。
我也从phpstudy的根目录中找到了一些session文件:
打开其中一个:
可以看到内容是以序列化的格式保存的,并且出现了竖线,说明session的反序列化引擎为php,这也是默认的session反序列化引擎
那么当初设置的session为:$_SESSION[‘username’]=’admin’;
2.3 php.ini 中的session配置
1 session.save_path="" --设置session的存储路径
2 session.save_handler=""--设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)
3 session.auto_start boolen--指定会话模块是否在请求开始时启动一个会话默认为0不启动
4 session.serialize_handler string--定义用来序列化/反序列化的处理器名字。默认使用php
以下是session序列化的三个引擎:
php_binary:存储方式是,键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值
php:存储方式是,键名+竖线+经过serialize()函数序列处理的值
php_serialize(php>5.5.4):存储方式是,经过serialize()函数序列化处理的值
我们可以通过 ini_set() 和 session_start() 函数来设置
1、ini_set()
ini_set('session.serialize_handler', 'php'); //两个参数都为string类型
2、session_start()
session_start(['serialize_handler'=>'php']); //一个参数为数组
三、通过一道CTF题来理解
下题是BUUCTF-bestphp’s revenge
可以看到题目中可以写入Session:
$_SESSION['name']=$_GET['name'];
前面我们知道了Session反序列化的机制,PHP默认为php序列化/反序列化引擎
但是这道题在session_start()
之前可以通过call_user_func()
来主动修改引擎,导致session序列化和反序列化的引擎不一样,从而导致解析错误
例如:
$a['name']='123';
echo serialize($a); //a:1:{s:4:"name";s:3:"123";}
//这相当于使用php_serialize 引擎来进行序列化
看上去没什么毛病,但是我们可以主动写入竖线|
$a['name']='|123';
echo serialize($a); //a:1:{s:4:"name";s:4:"|123";}
这时如果反序列化引擎为php的话:
a:1:{s:4:”name”;s:4:” 被当做键名,后面的一部分被当做值
那么如果继续构造呢?
$a['name']='|a:1:{s:4:"name";s:3:"123";}';
echo serialize($a);
//a:1:{s:4:"name";s:28:"|a:1:{s:4:"name";s:3:"123";}";}
这时php引擎进行反序列化,竖线后面的内容为值,也是完整的反序列化字符串,从而也能解析
那么如果后面是类呢?这时就可以调用PHP的一些内置类来操作了
四、总结
这道题也能更好地增强我对cookie和session的理解吧,希望继续努力!
- 本文链接:http://siii0.github.io/Session%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。