许多应用程序中,开发人员需要包含文件来加载类或在多个网页之间共享一些模板。
文件包含漏洞来自缺乏过滤,当用户控制的参数在调用包含函数(例如,PHP中的require,require_once,include或include_once)中用作文件名的一部分时。 如果对这些方法之一的调用容易受到攻击,则攻击者将能够操纵该函数来加载自己的代码。 文件包含漏洞也可以用作目录遍历来读取任意文件。 但是,如果任意代码包含一个打开的PHP标记,则该文件将被解释为PHP代码。
这文件包含功能可以允许加载本地资源或远程资源(例如,网站)。如果易受攻击,将导致:
- 本地文件包含:LFI。读取并解释本地文件。
- 远程文件包含:RFI。检索并解释远程文件。
默认情况下,由于配置选项,PHP禁用了远程文件的加载:allow_url_include。在ISO中,它已启用允许您测试它。
Example 1
<?php require_once '../header.php'; ?> <?php if ($_GET["page"]) { include($_GET["page"]); } ?> <?php require_once '../footer.php'; ?>
在第一个示例中,只要将特殊字符(例如引号)注入参数,就可以看到错误消息:
Warning: include(intro.php'): failed to open stream: No such file or directory in /var/www/fileincl/example1.php on line 7 Warning: include(): Failed opening 'intro.php'' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/fileincl/example1.php on line 7
如果您仔细阅读错误消息,则可以提取大量信息:
- 脚本的路径:/var/www/fileincl/example1.php。
- 使用的函数:include()。
- 调用中使用include的值是我们注入的值,intro.php’没有任何添加或过滤。
我们可以使用用于检测目录遍历的方法,来检测文件包含。 例如,您可以尝试使用../技术包含/etc/passwd。
我们可以通过请求外部资源来测试远程文件包含:http://www.baidu.com/。我们将看到百度的页面包含在当前页面中。(可查看源码看!)
PentesterLab的网站还包含对此类漏洞的测试。 如果您使用URL:http://assets.pentesterlab.com/test_include.txt。 您应该在当前页面中获得函数phpinfo()的结果:
test_include.txt 代码如下:
<?php phpinfo(); ?>
Example 2
<?php require_once '../header.php'; ?> <?php if ($_GET["page"]) { $file = $_GET["page"].".php"; // simulate null byte issue $file = preg_replace('/\x00.*/',"",$file); include($file); } ?> <?php require_once '../footer.php'; ?>
以与目录遍历类似的方式,此示例将其自己的后缀添加到提供的值。 和以前一样,你可以使用NULL BYTE(空字节)去除后缀(对于LFI)。
对于RFI,您可以根据您的URL添加&blah=或?blah=来删除后缀。
在本练习中,代码模拟旧版PHP的行为。 PHP现在可以正确处理路径,并且它们不会像过去那样使用NULL BYTE中毒。
提醒:在此代码中,问题被模拟,因为PHP从版本(5.3.4)[http://php.net/releases/5_3_4.php]开始解决了这种类型的绕过。