在php.ini中存在以下几个配置项:

session.save_path=""   --设置session的存储路径
session.save_handler="" --设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)
session.auto_start   boolen --指定会话模块是否在请求开始时启动一个会话,默认为0不启动
session.serialize_handler   string --定义用来序列化/反序列化引擎名字。默认使用php

例如:

session.save_path="D:\xampp\tmp" 表明所有的session文件都是存储在xampp/tmp下
session.save_handler=files    表明session是以文件的方式来进行存储的
session.auto_start=0 表明默认不启动session
session.serialize_handler=php     表明session的默认序列化引擎使用的是php序列化引擎

不同的引擎所对应的session的存储方式不相同。php存储session的三种模式(序列化/反序列化引擎):

php_serialize(php≥5.5.4)经过serialize()函数序列化数组
php键名➕竖线➕经过serialize()序列化的值
php_biary键名长度对应的ascii字符➕键名➕serialize()序列化的值

在PHP中默认使用的是PHP引擎,如果要修改为其他的引擎,只需要添加代码ini_set('session.serialize_handler', '需要设置的引擎');

举栗说明:

<?php
ini_set("session.serialize_handler","php");
session_start();
$_SESSION['shaw'] = $_GET['shaw'];
?>

运行该代码后,可看到请求头存在Cookie=a7d4f0vgjr1l1hr6aud13noae6

关于session的存储机制:

php中的session中的内容并不是放在内存中的,而是以文件的方式来存储的,存储方式就是由配置项session.save_handler来进行确定的,默认是以文件的方式存储。

存储的文件是以sess_sessionid来进行命名的,文件的内容就是session值的序列话之后的内容。

在本地找到sess_a7d4f0vgjr1l1hr6aud13noae6,查看内容:

简单记就是有竖线就是php类型。康康另一种模式(php_serialize):

<?php
ini_set("session.serialize_handler","php_serialize");
session_start();
$_SESSION['shaw'] = $_GET['shaw'];
?>

最后,看一下第三种(php_biary):

<?php
ini_set("session.serialize_handler","php_binary");
session_start();
$_SESSION['shaw'] = $_GET['shaw'];
?>

显示的是:shaws:3:"123";由于shaw的长度是4,4在ASCII表中对应的就是EOT。根据php_binary的存储规则,最后就是shaws:3:"123";

CTF比赛中常考的session反序列化漏洞产生的原因简单来说就是序列化及反序列化处理器(引擎)设置使用不当。如果phpphp_serialize这两个处理器混合起来使用,就会出现session反序列化漏洞。session_start会检测sess_sessionid中的内容是否符合引擎的格式,如果符合则对其反序列化,否则清空。

php_serialize存储的反序列化字符可以引用|,如果这时候使用php处理器的格式取出$_SESSION的值,|会被当成键值对的分隔符,在特定的地方会造成反序列化漏洞

当无可控的,可以修改sess_sessionid内容的点时,如果php配置满足以下三个条件(详见php的Bug #71101),仍可达到触发反序列化漏洞的目的:

  • session.serialize_handler [session序列化存储所用处理器。]局部变量(Local)为php,全局变量为php_serialize
  • session.upload_progress.cleanup [一旦读取了所有POST数据,立即清除进度信息。](其值默认开启)关闭状态
  • session.upload_progress.enabled [将上传文件的进度信息存在session中。](其中默认开启)开启状态

session.upload_progress.enabled本身的作用不大,其作用是检测文件的上传进度。但当一个文件上传时,同时POST一个与php.ini中session.upload_progress.name同名的变量时(session.upload_progress.name的变量默认值为PHP_SESSION_UPLOAD_PROCRESS),PHP检测到这种同名请求会在$_SESSION中添加一条数据,由此来设置session。

本地创建一个表单,网址写题目地址。

<!DOCTYPE html>
<html>
<body>
<form action="http://example.com/" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
    <input type="file" name="file" />
    <input type="submit" value="submit" />
</form>
</body>
</html>

访问该表单,上传文件的文件名写自己的payload,即精心构造的序列化的值,并记得把双引号转义。