文件操作安全之-文件包含原理篇

本节将详细的介绍一下文件包含安全相关内容,作为我的专栏《WEB安全原理和多种防御方法解读》中的一节。

软件开发的过程中,伴随着功能的复用,逐渐的形成了公共的函数,这些公共函数可以被同一个文件的其他函数调用。当公共的函数变多以及不同的文件对于这些公共函数有调用需求之后,这些公共函数会独立成为一个文件提供某项功能。在使用到这些功能的时候,直接包含该文件即可。因此很多的编程语言都提供了文件包含的功能,例如java,js,PHP等。如下分别为jsp,js,php等语言所提供的文件包含函数:

jsp:   include,<jsp:include>
js:require
PHP:include,include_once,require,require_once

文件包含之漏洞原理

文件包含本来是编程语言为了函数的复用提供的一项功能,这无可厚非。但是在使用的过程中,业务开发人员为了业务的灵活性,包含的文件往往是一个动态的变量,该变量在不可控的状态下会导致包含一个恶意的文件,文件包含的函数通常会去执行这个文件,这样就形成了文件包含的漏洞。

通常这些包含函数的入参是一个客户可以控制的变量,则客户可以构造恶意请求,达到执行未授权文件的目的。

文件包含通常会分为本地文件包含和远程文件包含两类,如下图1是OWASP关于LFI和RFI的定义:
在这里插入图片描述

图1
本地文件包含指的是包含的文件为本主机上的文件,远程文件包含指的是包含的文件为远程主机上的文件。由于访问远程注意需要借助网络,因此使用远程文件包含一般需要开启语言所提供的的配置项。通常如果说一个漏洞为文件包含漏洞往往其根因在于后端代码使用了上述的文件包含函数(require),并且缺乏过滤。

文件包含之漏洞举例

文件包含的漏洞在PHP中曾经是非常的普遍,同时在其他的语言中也是层多次出现。随着框架的普及以及安全意识的提升,没有任何过滤所导致的文件包含漏洞逐渐减少。但是业务的复杂性往往使得多数的程序员忽略对于文件包含的限制,下面选取几个影响面比较大的文件包含漏洞进行说明。

CVE-2018-17246

该漏洞影响的是kibana 5.0.0-5.6.13和6.0.0-6.4.3之间的版本,由于后台使用require函数进行文件包含,在解析HTTP请求中的apis参数时候,由于没有对apis参数做任何的过滤处理,可以通过构造apis的值进行文件包含,从而导致任意文件读取,反弹shell,DOS攻击等,如下图2 NVD中的介绍:
在这里插入图片描述

图2
可以看到NVD给出了非常严重的9.8的评分,深入评分的细节,可知该漏洞通过网络直接利用起来比较容易,同时不需要任何的前置条件,结合Kibana 的流程程度,以及该文件包含导致的后果来看,是一个非常严重的漏洞。其中POC如图3所示:
在这里插入图片描述

图3

图3中的POC是一个js脚本,其含义是在服务端通过文件包含执行该JS脚本建立反弹shell。拿到服务器的shell理论上是最危险的结果,当然也可以直接利用该文件包含漏洞获取敏感信息以及造成DOS都是可以的。

该漏洞的历史详情见这里,下面结合该漏洞历史代码进一步的分析该漏洞,如下图4:
在这里插入图片描述

图4
可以发现,该漏洞是在2015年9月份的一个commit引入的,图4可以看到name 变量来源于apis参数,程序员在添加该部分代码的时候没有考虑任何的过滤,用户的输入直接被require函数文件包含。该漏洞在2018年10月份被修复,如下图5:
在这里插入图片描述
图5
通过该修复,可以得到如下信息:

  • 首先从漏洞从被引入到漏洞修复经过了三年的时间,这三年期间,该漏洞是否被少数人掌握不得而知,鉴于该软件使用之广以及其严重性,不为人知的损失可能会很多。像这么重要的基础组件,这么明显的文件包含理论上是可以通过白盒审计加以避免的,可以看到整个开源社区的安全状况还是堪忧的。而且软件漏洞存在一个非常严重的问题,就是没有公开之前,造成的影响难以评估。
  • 其次图2中NVD发布该漏洞的日期为12月份,该漏洞的修补时间为10鱼粉,和漏洞被修补的时间相差两个月的时间,基本可以判断是Kibana官方先获得了该漏洞,修补完事之后才对外公布,这样NVD才能给该漏洞分配编号。一般NVD的公开才会引起广泛的重视,这样来看,这段时间内漏洞可能一直处于在野利用未公开状态,也是非常危险。
  • 最后,修复的方案是对于apis中的值进行了过滤,只允许白名单中的模块和文件被包含。

通过白名单是能够解决该种情况下文件包含所导致JS脚本的执行,解决任意敏感文件的访问问题,这是一种针对特定问题的快速处理方案。但是对于Kibana 中大量的使用require函数进行文件包含的情况并没有全部的解决。其他用到require进行文件包含的地方是否也存在着类似的问题呢?可以看到在后续的处理中,Kibana 同时使用了eslint-plugin-import中的模块对于项目中所有使用到require的文件包含进行了限制,这里,如下图6
在这里插入图片描述

图6
图6中的no-dynamic-require作用见这里,如图7:
在这里插入图片描述

图7
即通过限制require中入参的值,不允许表达式形式的入参进行过滤。

CVE-2018-12613

该漏洞影响的是phpMyAdmin 4.8.0至4.8.2版本,由于后台使用include函数进行文件包含,在解析HTTP请求中的target参数时候,存在绕过的利用,可以通过构造target的值实现任意文件读取,获取webshell等,如下图8 NVD中的介绍:
在这里插入图片描述

图8
其中POC如图9所示:
在这里插入图片描述

图9
可以看到该POC利用的是双编码获取敏感配置信息,至于双编码的原因见后续的分析。

phpMyAdmin为开源的项目,去到图10中对应的commit查看当时修复该漏洞的源码修复记录,这里,如图10:
在这里插入图片描述

图10
从图10可以看到,进入include分支条件有很多,包括判空,不能以index开头,黑名单限制等,最重要的判断条件是在checkPageValidity函数中,见图11:
在这里插入图片描述

图11

图11中的左侧可以看到,未修复前该函数的逻辑为判断target是否为白名单中的文件,如果是则返回true,不在白名单中,则返回false。同时考虑到target可能通过?带入一些参数。因此图11左侧红框部分中在通过截取问号前半部分进行黑名单的判定。

结合图9中的POC可知请求target的值为db_sql.php%253f/../../../../../../windows/wininit.ini$_REQUEST['target']获取URL对应的值之后会进行一次的URL解码,因此$_REQUEST['target']的值为db_sql.php%3f/../../../../../../windows/wininit.ini。在checkPageValidity函数中,再次通过urldecode进行URL的解码得到的$_page为db_sql.php,存在于$whitelist白名单中,因此返回true。在通过include进行文件包含的文件名称为$_REQUEST['target'],其值为db_sql.php%3f/../../../../../../windows/wininit.ini。虽然文件名中不允许问号的出现,但是此刻问号被编码为%3f,因此文件名上是合法的(如果不使用双编码,文件名合法性校验可能存在问题)。同时PHP在处理文件包含的时候,并不会检查db_sql.php%3f文件是否真实存在,而是会将db_sql.php%3f/../../../../../../当做一个整体,直接定位到对应的目录,因此可以通过目录穿越遍历指定目录的文件。

可以看出此处根因是由于在使用include进行文件包含的时候,虽然存在黑白名单的过滤,但是仍然存在着被绕过的情况。该漏洞是属于双编码的绕过黑白名单的校验。

这个漏洞也是一个典型的漏洞场景,即对于某些类型的漏洞,比如文件上传,目录穿越,文件包含等,在多种开源框架中其实已经采取了传统的修复建议,例如黑白名单等方式,但是编写业务的程序员,很难从攻击者的角度思考问题,导致近些年来,这些常见的漏洞仍然频繁,更多的是以绕过的形式出现,防不胜防。

文件包含之潜在危害

前面从原理和示例两份方面针对文件包含漏洞进行了简单阐述,文件包含漏洞会导致哪些危害呢。应该来说不同具体的漏洞影响程度是不一样的,一开始的图1中给出了常见的危害,解释如下:

  • 服务端代码执行获取shell,例如CVE-2018-17246漏洞可以在服务端执行js脚本形成反弹 shell。每种语言提供文件包含的功能主要目的是复用函数功能,因此文件包含一般伴随着对于包含文件的执行。这个时候所包含的文件如果是提前准备好的执行的脚本,例如js等脚本,则可以建立反弹shell等。

  • 敏感信息泄露,例如/etc/passwd,这应该是本地文件包含漏洞最常见的影响了。文件包含本质是去读取改文件并执行,对于不能够执行的文件,往往只是读取,会通过异常出错或者日志的形式记录。

  • DOS拒绝服务,同上,伴随着文件的执行,如果执行的文件中存在退出的操作,则会造成服务推出。但是现代的攻击主要以获取利益为主,DOS的攻击一般只出现在特殊的情况下。

本文为CSDN村中少年原创文章,未经允许不得转载,博主链接这里

猜你喜欢

转载自blog.csdn.net/javajiawei/article/details/127155874
今日推荐