freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

浅谈文件包含漏洞
2021-06-17 13:43:36

第一章:什么是文件包含漏洞?

1.1文件包含漏洞的原理

文件包含漏洞是一种常见的web类型漏洞,因为很多脚本语言支持使用文件包含,也就是我们所说的文件包含函数,网站开发者经常会把一些代码插入到指定的地方,从而节省之间避免再次编写 ,这就是包含函数的基础解释 ,但是我们不光可以包含我们预先指定的文件,也可以包含我们服务器内部的其他文件,前提条件就是我们需要有可读的权限才能读取这些文件 ,所以这样就会导致文件包含漏洞

1.2文件包含漏洞产生的原因

在网站的开发人员在开发网站的时候,会把经常重复使用的函数或者特定的页面写到单个文件中,需要使用的时候就直接调用此文件即可,而无需再次浪费时间再次编写,这种操作通常被称为文件包含。

如果我们没有对文件的来源进行严格的审查,也就是程序员在编写代码的时候触犯的逻辑性的错误就可能会导致文件读取漏洞和其它类型的漏洞,我们已php为例,在php中常用的文函数有(include、require、include_once、require_once),后续会介绍其中的区别。

1.3文件包含漏洞实例

Apace solr是apache公司研发的一款开源的搜索服务,应用范围很广,而且应用的人群也是很广的,但是在近几年它被爆出存在任意文件读取的漏洞,攻击者可以通过构造指定的payload对服务器内部文件进行读取的操作,这就造成很大的危害,因为我们可以通过读取敏感的数据从而控制服务器。

1.4文件包含漏洞分类

其文件包含漏洞共分为两大类,本地文件包含和远程文件包含,但是如果想要实现远程文件包含,需要php.ini开启了allow_url_fopen和allow_url_include的配置。包含的文件是第三方服务器的文件。本地文件包含的含义就是包含本地服务器的文件

第二章:文件包含漏洞的攻击步骤

我们将从php语言的角度来看一下文件包含漏洞,以及相关的攻击步骤

2.1相关文件包含函数基本知识:

在php语言当中,有四种文件包含的函数,分别是include、require、include_once、require_once

Include:被包含文件先按参数给出的路径寻找,如果没有给出目录(只有文件名)时则按照 include_path指定的目录寻找。如果在 include_path下没找到该文件则 include 最后才在调用脚本文件所在的目录和当前工作目录下寻找。如果最后仍未找到文件则 include 结构会发出一条警告

ps:php开启错误题型需要配置php.ini中disaply_errors为On

Require:require 和 include几乎完全一样,除了处理失败的方式不同之外。require 在出错时产生 E_COMPILE_ERROR 级别的错误。换句话说将导致脚本中止而 include只产生警告(E_WARNING),脚本会继续运行。

Include_once:include_once 语句在脚本执行期间包含并运行指定文件。此行为和 include语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含,且 include_once 会返回 true。 如同此语句名字暗示的那样,该文件只会包含一次。 include_once 可以用于在脚本执行期间同一个文件有可能被包含超过一次的情况下,想确保它只被包含一次以避免函数重定义,变量重新赋值等问题。

Require_once:require_once 语句和 require语句完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。

2.1文件包含函数的区别:

其实在上一章就告诉我们这几个函数的区别了,现在我们来总结下,include函数在执行文件时候每次都要进行读取和评估,在找不到文件的情况下会发出一条警告,且还会继续运行,require则会给出一条致命错误,从而停止运行,include_once和require_once和include和require类似,他们仅仅只包含一次。

2.2 文件包含攻击步骤

基于上面的文件包含的知识背景,我们可以有一个攻击的大概步骤:

我们先从include函数入手,来看一下include函数有什么特殊的地方,为此我们编写一个小脚本来验证下。

1623896337_60cab111202cede110a8f.png!small?1623896337417

在验证文件包漏洞的时候我们通常使用/etc/passwd文件是否能够被成功读取,该文件是我们linux的用户组信息,且这个文件的权限所有用户都可读。且李明包含的饿信息是是我们当前服务器的所有用户的信息,属于敏感信息。


现在我们用这个小脚本验证一下是否能够成功的读取/etc/passwd文件。


我们发现成功的读取了/etc/passwd下面的文件。下面我们换一下我们要读取的文件,换个不存在的文件试一试,看看有什么效果


我们可以看到我们的服务器报了个warning的错误,因为此文件不存在,这正好是include函数的特点,文件不在的时候会丢出warning的错误,然后还会接着运行下去。接下来我们将include函数切换到require函数,看看有什么区别。


我们可以看到,我们的include在找不到文件的情况下会丢出warning的错误,而我们的requore函数直接丢出failed错误,直接就停止运行了,这就是我们之前介绍我们include和require函数的区别的地方。

下面我们从session文件包含来进行getshelll的演示,我们先从phpinfo的信息获取到我们session的存储位置(这个位置其实我们可以猜测到的,因为就那几个固定的存储位置,例如:/var/lib/php5/sessions、/var/lib/php7/sessions、/var/lib/php/sessions等)


为了验证session文件包含漏洞我们编写了一个简单的脚本,如下所示:

1623896456_60cab188727c92a1f3f31.png!small?1623896456974

我们先打开浏览器访问此文件,然后我们在按F12键,查看我们的cookie,我们可以看到我们cookie中有个PHPSESSID的名称,其中它的值就是我们sessionid的值,也就是我们需要包含的文件。

我们在通过这个脚本,向seesion写入恶意的数据


这个时候我们打开我们的服务器,进去我们存储session的目录,然后找到对应的session文件,我们可以看到我们的内容已经成功写入到我们的session里面了。

然后我们访问我们session文件发现我们写入的脚本已经成功被执行了

接下来我们继续验证日志文件包含,但是我们需要满足条件才能进行文件包含,因为我们在读取文件的时候我们需要权限才能读取,我们看一下我们原本服务器日志文件的权限

我们可以看到我们可读权限仅适用于当前用户和用户组,其它用户并没有可读的权限。为了验证我们的实验,我们将其它用户设置成可读的权限。这样我们就可以读取我们的日志文件了。

现在我们就可以构造我们恶意的日志信息了,这里有一点需要注意下,我们在构造我们的日志信息的时候,不能直接在浏览器中构造(在url后面构造信息),因为如果直接在浏览器中构造,存储到日志信息的时候就会进行urlencode编码了,导致我们不能正常构造我们需要的日志信息,此时我们就需要BurpSuite工具了,通过抓包修改数据,这样存储的日志就不会进行urlencode编码了。

此时我们就可以看到我们的日志信息有了我们构造的恶意信息,这个时候我们再包含我们的日志信息我们就可以执行我们的恶意信息了。

2.2 文件包含之伪协议利用

php语言内置了很多封装协议,而这些协议则是我们处理文件包含漏洞经常用到的方法,最常见的协议有以下几种:

php://input:

php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。 而且,这样的情况下 $HTTP_RAW_POST_DATA 默认没有填充, 比激活 always_populate_raw_post_data 潜在需要更少的内存。 enctype="multipart/form-data" 的时候 php://input 是无效的。

php://filter:

php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()file()file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。

file://:

file:// — 访问本地文件系统

ftp://和ftps://:

ftp:// -- ftps:// — 访问 FTP(s) URLs

zip://:

可以访问压缩包里的文件。当他与包含函数结合时,zip://流会被当做php文件执行。

下面是针对某些封装协议的利用方式和特点

接下来我们就利用php伪协议接着我们下面的实验,我们从中挑选几种伪协议来进行实验。

我们来看下我们用filter伪协议读取的文件,因为我们使用了转换过滤器,导致输出的结果是base64编码的格式

我们对它进行解码过后就是我们/etc/passwd的内容。

其中filter伪协议内置了很多过滤器,有字符串过滤器,转换过滤器、压缩过滤器、加密过滤器等

我们再以input伪协议为例,我们来看下我们构造的语句,成功被执行了。此协议需要allow_url_include为on,在之前也强调过了。Input伪协议可以访问请求的原始数据的只读流,在POST请求中访问POST的data部分,所以它才能执行我们构造的数据。

下面介绍文件包含漏洞的另一个利用方式,那就是远程文件包含,顾名思义就是包含远程服务器的文件。首先我们在我们的云主机上面写入一个文件。然后通过带有文件包含漏洞的主机对它进行读取。

然后我们构造我们的payload,发现成功包含了我们云主机主机上的内容。

第三章 文件包含漏洞攻击防范

文件包含漏洞已经是Web安全史上经常用的攻击手段,且它的利用方式简单,造成的危害巨大,虽然我们现在已经有了很全面的防范对策,但是它的危害还是很大,上述实验我己经从多种角度解析了文件包含漏洞,也阐述了它可以做的事情已经造成的危害,下面我们开始着重介绍怎么对此漏洞进行防范和检测,避免造成不必要的损失。

3.1检查服务器配置文件

在php中有个php.ini的配置文件,里面大概是对php语言所有功能配置文件集合,其中里面有两项是allow_url_foprn、allow_url_include两个选项,其中allow_url_fopen默认是开启的,allow_url_include默认是关闭的,如果我们开启这个配置文件,我们就可以使用伪协议读取我们的敏感信息和其它操作,虽然开启allow_url_fopen也可以读取我们的文件,但是我们可以通过过滤一些字符或者限制用户的输入从而达到攻击不能读取我们信息的操作。

3.2过滤特殊符号

在进行文件包含的时候我们可能经常会用到几个固定的字符,或者我们在用伪协议的时候我们也会使用特定的字符,例如:\,//,input,output,filter等我们可以将这些铭感字符都给过滤掉。代码如下

此时我们再用我们之前的攻击手法,发现已经读取不到文件了。

因为str_repleace只会替换一次,可以有办法绕过的,所以这里我们还有正则匹配的方式,只要用户输入的字符串被我们正则匹配我们就会警告结束程序的运行。我们来看下我们的源码。

这个时候我们再访问下,输入一些敏感的信息发现它给我们提示说我们是不合法字符。

3.3 指定包含的文件 (白名单)

我们在做网站开发的时候我们可能经常会使用我们文件包含的函数,但是我们呢包含的文件都是我们指定的文件,也就是我们知道我们需要包含什么文件。这样,我们在包含文件的时候就可以添加一条规则,让我们只能包含指定的文件,如果我们包含了非指定的文件,程序就会报错退出。下面来看下我们实现的方法。

3.4 设置文件目录

php的配置文件中有open_basedir选项可以设置用户需要执行的文件目录,如果设置文件目录的话,我们编写的脚本只会在该目录中搜索文件,这样我们就可以把我们需要包含的文件放到这个目录就可以了,从而也避免了敏感文件的泄露。

# web安全
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录