当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2014-051906

漏洞标题:ThinkPHP远程代码执行隐患(需满足特定条件)

相关厂商:ThinkPHP

漏洞作者: 猪头子

提交时间:2014-02-24 17:57

修复时间:2014-05-25 17:58

公开时间:2014-05-25 17:58

漏洞类型:远程代码执行

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-02-24: 细节已通知厂商并且等待厂商处理中
2014-02-24: 厂商已经确认,细节仅向厂商公开
2014-02-27: 细节向第三方安全合作伙伴开放
2014-04-20: 细节向核心白帽子及相关领域专家公开
2014-04-30: 细节向普通白帽子公开
2014-05-10: 细节向实习白帽子公开
2014-05-25: 细节向公众公开

简要描述:

其某处处理存在安全隐患,开发者一不小心就可能写出有漏洞的代码造成任意代码执行。

详细说明:

这个问题之前看ThinkSNS就发现了:
WooYun: ThinkSNS getshell一枚
ThinkSNS由于使用ThinkPHP模板,造成任意代码执行。
下面分析下ThinkPHP实现细节
模板类是ThinkPHP中一个重要的类,主要实现了为模板变量赋值,模板解析和输出模板变量的逻辑,其中模板变量的赋值通过assign函数进行,模板变量的解析通过display函数,模板编译通过fetch函数,这一系列对模板的读写与编译操作导致了漏洞的产生。
先看编译,在ThinkPHP\Lib\Core\View.class.php的fetch函数中:

public function fetch($templateFile='',$content='',$prefix='') {
… … …
if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // 使用PHP原生模板
// 模板阵列变量分解成为独立变量
extract($this->tVar, EXTR_OVERWRITE);
// 直接载入PHP模板
empty($content)?include $templateFile:eval('?>'.$content);
}else{
… … …
}


在ThinkPHP启用了原生模板的情况下,会调用extract把当前tVar导入到变量表里,然后会检测$content变量是否存在,如果存在就eval之,否则include $templateFile。
可以看到这里使用了extract函数,extract作用是从数组中把变量导入到当前的符号表中,而第二个参数表示如果有冲突,就覆盖已有变量。因此此处如果$this->tVar可控的话,那么就可以覆盖底下的$templateFile变量造成任意文件包含或覆盖$content造成任意代码执行。
漏洞的触发点就是上述的函数,而导致漏洞发生的参数可以通过模板变量赋值函数assign传入:
ThinkPHP\Lib\Core\View.class.php

public function assign($name,$value=''){
if(is_array($name)) {
$this->tVar = array_merge($this->tVar,$name);
}else {
$this->tVar[$name] = $value;
}
}


如果传入的是数组,那么直接将数组合并和放入到tVar。
漏洞最终会通过display函数触发:
ThinkPHP\Lib\Core\View.class.php

public function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {
G('viewStartTime');
// 视图开始标签
tag('view_begin',$templateFile);
// 解析并获取模板内容
$content = $this->fetch($templateFile,$content,$prefix);
// 输出模板内容
$this->render($content,$charset,$contentType);
// 视图结束标签
tag('view_end');
}


因此如果调用assign传入可控数组并且调用display显示模板就会触发漏洞。

漏洞证明:

可看之前一个例子:
WooYun: ThinkSNS getshell一枚
用ThinkPHP写一个demo测试:

class IndexAction extends Action {
public function index(){
$this->assign($_GET);
$this->display();
}
}


开发者通过assign函数将$_GET变量全数传入到模板示例里,然后调用display解析并输出模板,最终导致了任意代码执行:
http://www.ztz.com/thinkphp/App/?content=%3C%3Fphp%20phpinfo%28%29%3B%3F%3E
我们控制content参数为<?php phpinfo(); ?>

QQ图片20140224174613.jpg

修复方案:

开发者不要直接传入可控数组给模板变量

版权声明:转载请注明来源 猪头子@乌云


漏洞回应

厂商回应:

危害等级:低

漏洞Rank:5

确认时间:2014-02-24 21:58

厂商回复:

在框架中有很多的机制可以避免,采用新版的I函数就可以避免此类问题的可能性。暂无需修复!

最新状态:

暂无