0x00 前言
很早之前就有国外的安全研究人员发现PHP语言在Windows上的一些奇妙特性:
大于号(>)相等于通配符问号(?)
小于号(
双引号(")相当于点字符(.)
具体文章参见:https://soroush.secproject.com/blog/2014/07/file-upload-and-php-on-iis-wildcards/
那么问题来了,根本原因是什么呢?是PHP语言本身的问题还是Windows的锅呢?
0x01 分析
处于对这个问题的好奇,笔者进行了一下的挖掘和分析。
在分析之前为了避免自己做了无用功,先Google了一番,找到了以下这些文章且都是通过Fuzz的方法发现的,并没有太多资料解释更深层次的原因。
https://github.com/ironbee/ironbee-rules/blob/master/support/php/test_fs_evasion.php
http://www.ush.it/2009/07/26/php-filesystem-attack-vectors-take-two/
静态分析
既然没有现成的解释,那么我们便可以自己动手分析以下。
首先,下载PHP的源代码进行尝试进行静态分析。
随便选取一个可以操作文件的PHP方法, 如.
尝试进行全局搜索,我们在的第1501-1506行发现了该方法的具体定义:
/* }}} *//* {{{ proto array getimagesize(string imagefile [, array info]) Get the size of an image as 4-element array */PHP_FUNCTION(getimagesize){ php_getimagesize_from_any(INTERNAL_FUNCTION_PARAM_PASSTHRU, FROM_PATH);}
可见,方法调用了方法,那么接下来又是如何调用的呢?当然,你可以继续逐层追踪下去,但是这将会比较费时费力同时也需要更过的精力去理解大量的代码逻辑。笔者在这里将尝试从动态调试的角度来简化这个分析过程。
动态调试
在动态调试之前,我们需要做一些提前的准备如下:
PHP的源码(本文调试的版本是7.2.1)
Visual Studio 2017
参考PHP官方文档在Windows上编译PHP-7.2.1:
https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2
具体步骤这里不在赘述,唯一需要注意的点在于在编译之前用以下的命令来建立自己的configure文件:
configure --enable-debug --enable-phpdbg
编译完成之后,你会看到类似于下图的编译之后的PHP可执行文件:
接下来,我们需要准备一个测试目录,具体结构如下:
C:\- Research\-- admin\--- test.png -- poc.php
准备一个文件,具体内容如下:
使用我们编译后的PHP来执行的话,正常情况下应该会返回:
一切准备就绪,便可以进行动态调试了。
先启动Visual Studio打开我们在静态分析时找到的文件在第1505行下一个断点。
进入目录,使用编译后的PHP(例如:)来执行我们的文件,并在Visual Studio里打开“调试-附加进程”来附加此处的PHP进程。
返回到执行poc文件的命令行下,敲击回车,我们发现前面设置的断点被成功hit了。
接下来的操作就需要特别的仔细和耐心了,使用VS提供的调试命令:
F10: 单步调试
F11: 逐语句调试
Shift + F11: 跳出
经过以上一系列的调试,我们最终发现了PHP的方法最终调用了Windows API里的FindFirstFileExW(),调用顺序如下:
PHP_FUNCTION(getimagesize)
php_getimagesize_from_any
_php_stream_open_wrapper_ex
php_stream_locate_url_wrapper
wrapper->wops->stream_opener
php_plain_files_stream_opener
php_stream_fopen_rel
_php_stream_fopen
expand_filepath
expand_filepath_ex
expand_filepath_with_mode
virtual_file_ex
tsrm_realpath_r
FindFirstFileExW
而根据StackOverflow上面的一个相关问题和MSDN的解释,这是NtQueryDirectoryFile / ZwQueryDirectoryFile通过FsRtlIsNameInExpression的一个功能特性,对于FsRtlIsNameInExpression有如下描述:
另外,MSDN的解释并没有提到具体指哪些字符,但根据,我们发现了如下的定义:
因此,我们终于搞明白了为什么前言中说的这三个字符在Windows上被赋予了不同的含义了。
0x02 总结
通过以上分析,我们可以做以下的简短总结:
问题的产生的根本原因PHP调用了Windows API里的FindFirstFileExW()/FindFirstFile()方法
该Windows API方法对于这个三个字符做了特别的对待和处理
任何调用该Windows API方法的语言都有可能存在以上这个问题,比如:Python
0x03 参考
https://stackoverflow.com/questions/24190389/findfirstfile-undocumented-wildcard-or-bug
http://www.osronline.com/showThread.cfm?link=36720
领取专属 10元无门槛券
私享最新 技术干货