关于php的session.serialize_handler的问题

前言

php的session信息是储存在文件中的

session.save_path="" 指定储存的路径
session.save_handler="" 指定储存时使用的函数(默认是file)
session.auto_start boolen
session.serialize_handler="" 定义序列化和反序列化的处理器的名字,默认是php(5.5.4后改为php_serialize)

session.serialize_handler存在以下几种

  • php_binary 键名的长度对应的ascii字符+键名+经过serialize()函数序列化后的值
  • php 键名+竖线(|)+经过serialize()函数处理过的值
  • php_serialize 经过serialize()函数处理过的值,会将键名和值当作一个数组序列化

使用过程中如果想要修改,使用

ini_set('session.serialize_handler','php_serialize');

但这里设置的handler如果和默认的不同,就会出问题

比如默认是php的handler,在该页面设置为php_serialize

这是如果我们传入一个 '|O:5:"Class"';,这样的一个数据,在储存时就会加上键名进行序列化,但是进行读取的时候还是会按照php handler来处理,以|作为键和值的分隔符,将前半部分当作键,后半部分当作值,然后进行反序列化

CTF

jarvisoj PHPINFO

引用官方文档的内容

当 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连接在一起的值。 通常这些键值可以通过读取INI设置来获得

通俗的说就是请求时加上与session.upload_progress.name同名的变量时就会在$_SESSION中加上一组新的数据

来看这道题,题目给了源码

<?php
//A webshell is wait for you
ini_set('session.serialize_handler', 'php');
session_start();
class OowoO
{
    public $mdzz;
    function __construct()
    {
        $this->mdzz = 'phpinfo();';
    }
    
    function __destruct()
    {
        eval($this->mdzz);
    }
}
if(isset($_GET['phpinfo']))
{
    $m = new OowoO();
}
else
{
    highlight_string(file_get_contents('index.php'));
}
?>

看到这里使用了ini_set('sessionserialize_handler':'php'),有预感会出现handler不一样的问题

接下来查看phpinfo,发现php版本是5.6.21,大于5.5.4,默认的handler是php_serialize,会出现上面所述的问题

在使用session_start()时会自动加载session文件中的值,因为在这里在__destruct方法中使用eval,所以只要在session文件中写入这个类,就能够执行代码?

但是我们如何将类写入session文件?

这就用到刚才提到的东西,查看phpinfo,
因为session.upload_progress.enabled=1,所以我们就可以post一个和session.upload_progress.name同名的变量,来使得我们上传的文件名写入session

因为这里是php handler,是以|开头的,所以在反序列化时会按照|来识别键值对而不是按照默认的php_serialize来识别session,所以我们将文件名改为

"|O:5:"OowoO":1:{s:4:"mdzz";s:36:"print_r(scandir(dirname(__FILE__)));";}"

来读取文件目录

问题

session部分的问题大致是解决了……剩下的问题就是……为什么要将双引号转义?暂时还没有弄清楚,待日后分析吧

参考链接

https://blog.spoock.com/2016/11/15/jarvisoj-web-writeup-1/

https://blog.csdn.net/wy_97/article/details/78430690

原文地址:https://www.cnblogs.com/hf99/p/9746038.html