谈一谈文件包含漏洞

什么是文件包含


文件包含这个漏洞,简单来说既是程序猿在开发中为了方便,会将在多个页面重复使用的代码单独写到一个文件中,在需要用到的地方直接包含进来,包含后的文件既相当于将被包含的整个文件内容复制到了包含处。因为在开发中是经常用到的,因此成为了攻击者的目标,便衍生了多种文件包含的攻击。

本地文件包含


先来感受一下,当包含值可被直接控制的情况下是怎么样的如以下代码:

1
2
3
<?php
$file = $_GET['file'];
include($file);

可看到以上代码,直接包含的 $file 这种情况下呢,就是可控的情况。

先说一下文件包含的一个要点:文件包含可以包含任意文件,即便被包含的文件并不是与当前编程语言相关,甚至为图片,只要被包含的文件,其内容会被包含文件包含,并以包含文件当前语言执行。

首先在当前文件夹内随便创建任意后缀格式的文件,如:file.txt (就算是图片格式那么效果也是如下)文件内容如下:

1
2
<?php
phpinfo();

image

文件包含漏洞在支持包含web应用内的目录的同时也直冲包含当前服务器内的其它文件,如下:
尝试包含C盘里的某个内容。如:C:\WINDOWS\system.ini

image

可看到是直接被包含进来的。

那么上面说的是传入的文件值为全部可控的情况下的方法,那么如果程序猿在开发中固定死了所包含的文件后缀的话,怎么办?代码如下:

1
2
3
4
<?php
$file = $_GET['file'] . '.php';
echo $file;
include($file);

这种情况下,我们按照上面的方法尝试一下,为了方便看到直观效果,这里
是将$file输出了。

image

我们可以看到,如果在程序中固定死了后缀,那么就像上图一样,将会找不到需要包含的文件。可看到最后所包含的文件名为:./include.txt.php

因此这就可以使用另一种方法,就是:%00截断。那么%00截断呢,是可以使用在非常多的地方的,这里不多讲。想了解的童鞋可以网上查一查相关资料。

这里先说一下PHP中使用%00的前提:

  1. PHP版本 < 5.3 (不包括5.3) ;
  2. PHPmagic_quotes_gpc = off;
  3. PHP对所接收的参数,如以上代码的$_GET['file']未使用addslashes函数

因为PHP大于等于5.3的版本已经修复了这个问题,如果开启了gpc或者使用了addslashes函数的话则会对其进行转义。
首先我们可以试试如果在gpc开启的情况下会出现什么情况(效果与使用函数的为一致)

image

image

可以看到了。效果是非常的明显。

接下来看看在5.3的情况是什么样的

image

image

也可以看到。是没有任何效果的。

因此我们可以得知只要满足以上三种情况,那么就可以使用%00
首先我们将PHP版本更换为5.2,然后在php.inimagic_quotes_gpc = on改为magic_quotes_gpc = off之后重启 Apache,在尝试下使用截断。

image

成功使用截断包含。那么文件包含就只有包含的功能吗?那肯定不是的,既然是文件包含,那么我们可以直接包含一句话。先创建一个文件:shell.txt内容为一句话。

image

可以看到,拿shell不是什么问题。

那么这两种包含有什么区别呢?其实是没有区别的,原理都一样,只不过第一种是将后缀一起传入,第二种则在程序内固定死了后缀。但是可以使用%00因为当程序流遇到%00终止符的时候将直接终止。

远程文件包含

本地文件包含与远程文件包含的原理是相同的,不同点就是前者只能包含服务器内存在的文件,后者则可包含远程服务器内的文件。

远程文件包含的注意点:

  1. 需要 php.ini 内的 allow_url_include = on 以及 allow_url_fopen=on
  2. 所需包含的远程文件后缀格式不能以目标服务器的语言相同,如(目标服务器解析PHP代码,那么远程文件后缀格式则不能为 PHP

来解释一下第二点:因为如果你的远程文件是php后缀的话,那么如果你远程文件内容为:

1
2
<?php
phpinfo();

那么在目标服务器内拿到的内容则是你的远程服务器执行phpinfo()后的一个内容,并不是这段代码,因此包含得到的信息并不是目标服务器的而是你远程服务器的。如下:
image

这个是我远程机的信息,为php5.6版本,目标机的是5.2版本。接下来包含一下。
image

可以看到,包含后得到的结果就是我们远程机的,为什么呢??
因为目标服务器包含的代码并不是:

1
<?php phpinfo();?>

而是远程服务器执行完这段代码的源代码,如下图:

image

所以说远程文件包含只有符合了以上两点才能正常包含。
先来修改下:

  1. 修改配置
    image

  2. 修改文件后缀
    image

再来包含一下。
image

可以看到这次包含后返回的信息就是我们目标机的信息。

接下来继续尝试拿shell
image

image

远程文件包含的利用前提其实就是符合本地文件包含的前提并且符合远程文件包含本身的前提即可利用。

文件包含之伪协议


伪协议在文件包含的利用,本文演示以下伪协议:
data:text/plaindata:text/plain;base64
php://input
php://filter
file://
zip://

其它协议可阅读官方文档:直通车

data:text/plain

直接在对应URL参数内输出:data:text/plain,需要执行的php代码 如下图:
image

这个伪协议还有另一种使用方法,那么就是将需要执行的php代码使用base64编码:data:text/plain;base64,需要执行的base64php代码 如下图:
image


php://input

php://input 可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。

image

可以看到程序内是固定死后缀的,那么在包含 php://input 的时候就会自动拼接上 .php 所以肯定是不能正常使用 php://input的。所以我们也是可以使用 %00 截断的

image

image

可以看到终止符是非常强大的。


php://filter

php://filter 该伪协议可以读取php文件代码以base64编码输出,比如说我们想读取一个php文件但是不想让它正常php执行代码后的结果,我们想要这个php文件的代码的时候就可以使用这个伪协议。
使用方法:php://filter/read=convert.base64-encode/resource=需要读取的文件代码内容

image

解码后可得到内容

image


file://

file:// 用于访问本地文件系统,且不受allow_url_fopenallow_url_include的影响。
使用方法:file://文件绝对路径

image


zip://

zip://可以访问压缩文件中的文件。但是需要绝对路径。
使用方法:zip://[压缩包绝对路径]#[压缩文件内的文件名]

在本地创建一个文件,并且压缩成zip压缩包。

image

可以看到我已经填写了绝对路径以及文件名称,但是为什么不能成功包含呢,可以看到它的报错 Warning: include(zip://C:/phpStudy/WWW/include/phpinfo.zip.php) 我们并不是包含这个文件,我们是要包含这个zip里面的文件,为什么#后面的值没了呢,是因为#会忽略后边的参数,所以我们需要使用编码%23的形式,还有一点就是程序里固定死了 php后缀,因为我们压缩的文件是为php后缀的。所以我们就不用带后缀了,如下图:

image

转载自:http://www.bugsafe.cn/archives/167.html

-------------本文结束感谢您的阅读-------------