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_name
和name
都是我们可控的,如果此时存在上一篇文章所说的处理器不同的问题,那么就能成功反序列化攻击,下面是一个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,如下
这里处理器的局部变量(local value)是php
,而全局变量master value
是php_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`;";}
然后我们用自己构造的表单上传文件并抓包:
在Repeater中改完后(注意转义序列化数据中的双引号,或者filename=’’,使用单引号),发送后,将这一部分复制(让burp帮我们改变一下C-L),然后在目标网站抓包并构造请求:
实验结果如下,成功执行命令,并且存储的session如下:
另外我们也可以试下另一个可控的地方input 中的文件变量名
:
结果也是可行的:
这个攻击的不足就是,需要改变太多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,只要我改规则,我就永远完成了),并且方便我自己整理,我就在另一篇文章再讲吧