从源码级别了解PHP %00截断原理
PHP的00截断是5.2.x版本的一个漏洞,当用户输入的url参数包含%00经过浏览器自动转码后截断后面字符。
例如url输入的文件名1.txt%00.jpg经过url转码后会变为1.txt 00.jpg,测试文件1.php如下<?php include "1.txt 00.jpg"; ?>测试文件1.txt如下
<?php echo "fireXXX"; ?>php5.2.x版本解析1.php时,会将1.txt 00.jpg解释为1.txt php5.2.17代码分析: 调用php去解析1.php文件。 主要的执行流程在Zend/zend.c的zend_execute_scripts函数中。该函数首先通过zend_compile_file获取1.php文件的内容,然后调用zend_execute解析读取到的文件内容。 zend_compile_file函数首先调用open_file_for_scanning去读取文件,然后通过zendparse去进行语法和词法解析,而zendparse是通过lex_scan去扫描出token并进行语法分析。可以通过调试器观察到include的文件名参数经过lex_scan后的数据:
可以从php5.3.24代码中找到修复的方案。修复的代码位于ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER函数的开始处:
if (Z_LVAL(opline->op2.u.constant) != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) { if (Z_LVAL(opline->op2.u.constant)==ZEND_INCLUDE_ONCE || Z_LVAL(opline->op2.u.constant)==ZEND_INCLUDE) { zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC); } else { zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC); } }代码
strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)中,Z_STRVAL_P(inc_filename)即上图中的val,即"1.txt",strlen取得长度为5,而Z_STRLEN_P(inc_filename)即上图中的len即10。 一旦出现%00截断,include的文件名经过url转码由"1.txt%00.jpg"变为"1.txt 00.jpg",进入php语法词法分析器解析后会将这个字符串解析成一个字符串,并使用zend_scan_escape_string进行字符串转码,如图,进入zend_scan_escape_string的内容为:
中间的\000还被解析为4个字符,转码中会将他当作八进制数据转成一个字符 ,因此最终1.txt 00.jpg长度是10。 只要比较发现文件名的strlen长度和语法分析出来的长度不一样,就说明内部存在截断的字符,因此输出了打开文件失败的信息。
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: 集合是否包含某些元素,获取元素索引位置,元素排序(三)
- 下一篇: 索引器与数组的区别(详解)