简单聊聊PHP下的“截断”问题,从利用方式到适用情况
起因
有天在群里说起上传的%00截断的一些问题,就想起之前自己在这个问题踩过坑,想起了自己曾经的flag说要写文章,一直没写,现在来填坑了。
经过
源码理解:
//test.php<?phpinclude"1.txt000.jpg";?> //1.txt<?php echo'helloworld'; ?>
上面的示例代码在 php版本小于5.3.4 的情况下回输出 helloworld 。从php的内核执行过程来看,PHP通过php_execute_来执行PHP的脚本,这里选取部分有关代码,具体可以看这里(https://github.com/php/php-src/blob/PHP-5.2/main/main.c):
在第10行我们看到,他调用zend_execute_s来针对脚本进行解析,而这个函数是在Zend/zend.c里面,截取部分相关代码如下:
从PHP内核开来实际上是分为两块部分,一个是compile编译过程,另一个是execute执行过程。
第一部分:compile编译过程
我们可以看到这里的代码逻辑通过zend_compile_file获取文件的内容,zend_compile_file是一个函数指针,其声明在/Zend/zend_compile.c中
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle,inttypeTSRMLS_DC);
在引擎初始化的时候,会将compile_file函数的地址赋值给zend_compile_file 。
compile_file函数定义在/Zend/zend_language_scanner.l,截取部分相关代码。
简单总结一下上面部分代码的逻辑:
zend_compile_file函数首先调用open_file_for_scanning去读取文件,然后通过第17行的zendparse去进行语法和词法解析。而zendparse是通过lex_scan去扫描出token并进行语法分析。
第二部分:execute执行过程
zend_execute也是一个函数指针,其声明在/Zend/zend_execute.h中。
ZEND_APIexternvoid(*zend_execute)(zend_op_array *op_array TSRMLS_DC);
在引擎初始化的时候,会将execute函数的地址赋值给zend_execute 。
而execute的定义在/Zend/zend_vm_execute.h
根据我们的了解,zend_execute通过ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER函数来进行include的实际处理,即包含要包含的文件。
对比修复代码找到漏洞触发点:
摘出部分修复代码:
我看下存在漏洞的调试运行结果:
修复代码的Z_STRVAL_P(inc_filename) 即上图中的val,即”1.txt”,strlen取得长度为5,而Z_STRLEN_P(inc_filename) 即上图中的len即10。这里实际上解析到的文件名是1.txt。
不存在漏洞的调试运行结果:
一旦出现%00截断,include的文件名经过url转码由”1.txt%00.jpg”变为”1.txt000.jpg”,进入php语法词法分析器解析后会将这个字符串解析成一个字符串,并使用zend_scan_escape_string进行字符串转码,如图,进入zend_scan_escape_string的内容为:
只要比较发现文件名的strlen长度和语法分析出来的长度不一样,就说明内部存在截断的字符,因此输出了打开文件失败的信息。
利用方式
划重点PHP版本低于5.3.4
%00截断有这么2种利用状况
1.在url中加入%00,如http://xxxx/shell.php%00.jpg
2.在burpsuite的16进制编辑工具将”shell.php .jpg”(带空格的)中间的空格由20改成0
在1中,url中的%00(形如%xx),web server会把它当作十六进制处理,然后将该十六进制数据hex(00)“翻译”成统一的ascii码值“NUL(null)”,实现了截断。
在2中,burpsuite用burp自带的十六进制编辑工具将”shell.php .jpg”(中间有空格)中的空格由20改成00,如果burp中有二进制编辑工具。
延伸一下
其实关于截断相关问题,还有个很有趣的函数,iconv()函数:
在了解iconv()函数漏洞之前,可能需要一点前置知识,
在php中,所有的字符都是二进制的串,PHP本身并不认识任何编码,只是根据编码来显示内容。PHP中的chr()函数从指定的ASCII值返回字符。ASCII值可被指定为十进制值、八进制值或十六进制值。八进制值被定义为带前置0,而十六进制值被定义为带前置0x。
而在php5.4之前,iconv()函数在转换编码的时候,遇到不合法的字符串的时候会将其截断。
<?php for($k=0;$k<=255;$k++) { $a='shell.php'.chr($k)."1.jpg"; echo'k:'$k.' '.'$a:'.$a.' '.'iconv("UTF-8","gbk",$a):'.iconv("UTF-8","gbk",$a)."n"; } ?>
通过fuzz发现,其中iconv(“UTF-8″,”gbk”,$a)或是iconv(“UTF-8″,”gb2313″,$a)都会在chr(128)到chr(255)之间截断,使结果为shell.php
在php5.4.0版本的时候就不存在这个问题了。
实际例子
关于我们刚刚说的iconv()截断的问题,其实sitestar pro就是个典型例子,我们看个例子:
漏洞触发点在module/mod_tool.php中的img_create()函数,截取部分代码如下:
这部分中有段代码吸引了我的注意力
if(!preg_match('/.('.PIC_ALLOW_EXT.')$/i', $file_info["name"])) { Notice::set('mod_marquee/msg', __('File type error!')); Content::redirect(Html::uriquery('mod_marquee','upload_img')); }
跟进一下这个PIC_ALLOW_EXT参数,发现其在数据库中写死了,只允许gif|jpg|png|bmp这类文件。即如果文件名最后不是gif|jpg|png|bmp,则提示文件类型错误。
所以这部分的正则表达式的功能应该是针对文件后缀名进行检查。
继续跟进这部分代码,有一串代码如下:
if(!$this->_savelinkimg($file_info)) { Notice::set('mod_marquee/msg', __('Link image upload failed!')); Content::redirect(Html::uriquery('mod_marquee','upload_img')); }
这部分代码应该是进行文件保存的功能,这个有个核心函数_savelinkimg,跟进这个函数。
第二行问题出现了
$struct_file['name'] = iconv("UTF-8","gb2312",$struct_file['name']);
在iconv转码的过程中,utf->gb2312(其他部分编码之间转换同样存在这个问题)会导致字符串被截断,如:$filename=”shell.php(hex).jpg”; (hex为0×80-0×99),经过iconv转码后会变成$filename=”shell.php “;
所以,经过iconv后$struct_file['name'])为shell.php,于是我们利用这个逻辑缺陷可以成功的上传shell.php(前提是上传的文件名为shell.php{%80-%99}.jpg )。
结果
总结一下截断大概可以在以下情况适用
1.include(require);
2.file_get_contents;
3.file_exists;
4.所有url中参数可以用%00控制。
一、推荐使用迅雷或快车等多线程下载软件下载本站资源。
二、未登录会员无法下载,登录后可获得更多便利功能,若未注册,请先注册。
三、如果服务器暂不能下载请稍后重试!总是不能下载,请点我报错 ,谢谢合作!
四、本站大部分资源是网上搜集或私下交流学习之用,任何涉及商业盈利目的均不得使用,否则产生的一切后果将由您自己承担!本站将不对任何资源负法律责任.如果您发现本站有部分资源侵害了您的权益,请速与我们联系,我们将尽快处理.
五、如有其他问题,请加网站设计交流群(点击这里查看交流群 )进行交流。
六、如需转载本站资源,请注明转载来自并附带链接
七、本站部分资源为加密压缩文件,统一解压密码为:www.aizhanzhe.com
- 1CSS控制文字在Div最底部显示
- 2Thinkphp5如何配置IP+端口访问项目模块
- 3elementUI el-dialog弹框居中
- 4教你如何搭建及优化站点
- 5国内互联网视频行业运营分析
- 6service mysql start出错,mysql不能启动,解决mysql: unrecognized service错误
- 7CSS实现悬浮顶部的Div工具栏
- 8记一次Thinkphp5.1框架mysql数据库崩溃(SQLSTATE [08004] Too many connections)
- 9连接SQL Server数据库提示:Login failed for user 'sa'错误的解决方案
- 10Thinkphp3.2在centos7上设置计划任务的方法