如何渗透Discuz论坛(一)

  • A+
所属分类:moonsec_com
摘要

如何渗透Discuz论坛(一) 这几篇文章主要的分享给那些经常渗透Discuz 或者对 Discuz论坛无从下手的初学者,可能帮助或者提高你对Discuz论坛的安全认知,从而找到突破的方法,这几篇都是作者真实渗透的案例,如有雷同纯属巧合,毕竟渗透手法基本相同嘛。

如何渗透Discuz论坛(一)

作者:mOon    
博客:www.moonsec.com

0x01:叙述:

这几篇文章主要的分享给那些经常渗透Discuz 或者对 Discuz论坛无从下手的初学者,可能帮助或者提高你对Discuz论坛的安全认知,从而找到突破的方法,这几篇都是作者真实渗透的案例,如有雷同纯属巧合,毕竟渗透手法基本相同嘛。

如何渗透Discuz论坛(一)

 

 

0x02:Discuz简介

        如何渗透Discuz论坛(一)

Crossday Discuz! Board(以下简称 Discuz!,中国国家版权局著作权登记号 2006SR11895)是康盛创想(北京)科技有限公司(英文简称Comsenz)推出的一套通用的社区论坛软件系统,用户可以在不需要任何编程的基础上,通过简单的设置和安装,在互联网上搭建起具备完善功能、很强负载能力和可高度定制的论坛服务。Discuz! 的基础架构采用世界上最流行的 web 编程组合 PHP+MySQL实现,是一个经过完善设计,适用于各种服务器环境的高效论坛系统解决方案。
作为国内最大的社区软件及服务提供商,Comsenz旗下的 Discuz! 开发组具有丰富的 web 应用程序设计经验,尤其在论坛产品及相关领域,经过长期创新性开发,掌握了一整套从算法,数据结构到产品安全性方面的领先技术。使得 Discuz! 无论在稳定性,负载能力,安全保障等方面都居于国内外同类产品领先地位。

暗月论坛也是Discuz论坛 使用多年了,安全性 感觉还行,最近的几个漏洞,都是要配合第三方 才能获取权限,所以关于Discuz论坛,一般情况下是很难渗透,除某些大牛手里有大杀器除外。不过这类大牛一般都看不起我们这些站 因为 没有必要下手。一不小心被我获取了,想想也有点小激动。如何渗透Discuz论坛(一)

 

 

0x03 常见问题:

  • Discuz怎么破解
  • Discuz问题破解
  • Discuz删帖
  • Discuz权限绕过
  • Discuz后台获webshell

   以上这种这类问题,天天有人私聊,或者在群里提问。提问是对,但是这种问题不是一两句话,说得明白的。如何渗透Discuz论坛(一)

 

0x04 案例一:

 如何渗透Discuz论坛(一)

看上某站一个插件,但是在插件中心又看不见。怎么办,我们可以在谷歌搜索这类插件。
inurlplugin.php?id=这里是插件名 例如我想要微信机机器人这个插件 wuxin_qqrobo

如何渗透Discuz论坛(一)

 

 

如何渗透Discuz论坛(一)

 

目标确认后,新手如何渗透这样的论坛。记得年前有个基佬写了一款工具名为《Dzscan》针对Discuz论坛安全检测的工具。

 Dzscan项目设计的初衷,一方面是向wpscan,jmscan的等国外优秀作品的致敬,另一方面是更符合国情的量身定做。针对国内知名bbs建站系统discuz,所精心打造的一款漏洞扫描框架.
此处为discuz第三方漏洞收集和发布平台,当前的数十个漏洞都由Dzscan团队成员所发掘,为Dzscan能走更远而努力。
国内的大环境所决定,分享不易,漏洞分享更不易。未来,我们希望更多的小伙伴参与到对discuz的代码审计中去。作为国内极为优秀的一款开源cms,多读读其代码也是有益的。
为防止恶意利用,现今只公开低位和中危的漏洞,高危的开放与否留待后期再做决定。

 

如此富有文学和深度的介绍,相信这个工具能给我们带来帮助。不过高危漏洞的不开放,这样真的好吗。作者选择性搞基 ,这点我也无可奈何如何渗透Discuz论坛(一)
 
这个工具更不更新插件都没关系了,因为插件的exp漏洞 高危的漏洞,团队还真没放出来,而且最近新的漏洞,模块也没更新,估计网站也是快倒闭的,还没把网站内网保存的的同学,快点保存吧。
装个python scan go

如何渗透Discuz论坛(一)

 

先对目标干一炮:

 如何渗透Discuz论坛(一)

好像记得 utility 曾经有个漏洞,可以直接GETSHELL的。不急 我们先看下源码有没有加载exp模块的功能。

def fetch_sensitive(self):         # X3 Deafult password 188281MWWxjk         # https://www.bugscan.net/#!/n/449         robots_path = '%s/%s' % (self.url, '/source/plugin/tools/tools.php')         req = requests.get(robots_path, headers=HEADERS)         self.reqs += 1         if req.status_code == 200:             print '[!] The Discuz! /'%s/' file exists./n' % robots_path                # X3.1 Remote code execute         # https://www.sebug.net/vuldb/ssvid-61217         robots_path = '%s/%s' % (self.url, '/utility/convert/index.php?a=config&source=d7.2_x2.0')         req = requests.get(robots_path, headers=HEADERS)         self.reqs += 1         if req.status_code == 200:             print '[!] The Discuz! /'%s/' file exists./n' % robots_path                     # 7.2 faq.php SQL         # https://www.bugscan.net/#!/n/118         robots_path = '%s/%s' % (self.url, '/faq.php')         req = requests.get(robots_path, headers=HEADERS)         self.reqs += 1         if req.status_code == 200:             print '[!] The Discuz! /'%s/' file exists./n' % robots_path          # 7.2 manyou SQL         # http://www.venustech.com.cn/NewsInfo/124/6791.Html         robots_path = '%s/%s' % (self.url, '/manyou/userapp.php')         req = requests.get(robots_path, headers=HEADERS)         self.reqs += 1         if req.status_code == 200:             print '[!] The Discuz! /'%s/' file exists./n' % robots_path          # 7.2 admincp.php XSS          # https://www.bugscan.net/#!/n/141         robots_path = '%s/%s' % (self.url, '/manyou/admincp.php?my_suffix=%0A%0DTOBY57')         req = requests.get(robots_path, headers=HEADERS)         self.reqs += 1         if req.status_code == 200:             print '[!] The Discuz! /'%s/' file exists./n' % robots_path          # 6.x SQL          # http://www.wooyun.org/bugs/wooyun-2014-080359         robots_path = '%s/%s' % (self.url, '/my.php')         req = requests.get(robots_path, headers=HEADERS)         self.reqs += 1         if req.status_code == 200:             print '[!] The Discuz! /'%s/' file exists./n' % robots_path          # deafult admin login page         robots_path = '%s/%s' % (self.url, '/admin.php')         req = requests.get(robots_path, headers=HEADERS, allow_redirects=False)         self.reqs += 1         if req.status_code == 200 and 'Comsenz' in req.content:             print '[!] The Discuz! /'%s/' file exists./n' % robots_path          # deafult uc_server login page         robots_path = '%s/%s' % (self.url, '/uc_server/admin.php')         req = requests.get(robots_path, headers=HEADERS, allow_redirects=False)         self.reqs += 1         if req.status_code == 200 and 'UCenter' in req.content:             print '[!] The Discuz! /'%s/' file exists./n' % robots_path          # develop.php         robots_path = '%s/%s' % (self.url, '/develop.php')         req = requests.get(robots_path, headers=HEADERS)         self.reqs += 1         if req.status_code == 200:             print '[!] The Discuz! /'%s/' file exists./n' % robots_path  

 

 

只是单纯的扫描确认文件存在否,没有加载exp模块,拿出内部EXP工具 GETSHELL

如何渗透Discuz论坛(一)

菜刀连接:
 

如何渗透Discuz论坛(一)

 
 
实在意料之外这么简单就搞定目标了。如何渗透Discuz论坛(一)
 
0x05:漏洞分析
 
Utility/convert/index.php
<?php  /** * DiscuzX Convert * * $Id: index.php 10469 2010-05-11 09:12:14Z monkey $ */  require './include/common.inc.php';  $action = getgpc('a'); $action = empty($action) ? getgpc('action') : $action; $source = getgpc('source') ? getgpc('source') : getgpc('s'); $step = getgpc('step'); $start = getgpc('start');  $setting = array(); if($source) {         if(!$setting = loadsetting($source)) {                 showmessage('load_setting_error');         } }  $action = empty($action) || empty($source) ? 'source' : $action; showheader($action, $setting);  if($action == 'source') {         require DISCUZ_ROOT.'./include/do_source.inc.php'; } elseif($action == 'config' || CONFIG_EMPTY) {         require DISCUZ_ROOT.'./include/do_config.inc.php'; } elseif($action == 'setting') {         require DISCUZ_ROOT.'./include/do_setting.inc.php'; } elseif($action == 'select') {         require DISCUZ_ROOT.'./include/do_select.inc.php'; } elseif($action == 'convert') {         require DISCUZ_ROOT.'./include/do_convert.inc.php'; } elseif($action == 'finish') {         require DISCUZ_ROOT.'./include/do_finish.inc.php'; } else {         showmessage('非法请求'); }  showfooter(); ?>

require DISCUZ_ROOT.'./include/do_config.inc.php';

?php  /** * DiscuzX Convert * * $Id: do_config.inc.php 10469 2010-05-11 09:12:14Z monkey $ */  if(!defined('DISCUZ_ROOT')) {         exit('Access error'); }  $configfile = DISCUZ_ROOT.'./data/config.inc.php'; $configfile_default = DISCUZ_ROOT.'./data/config.default.php';  @touch($configfile);//创建文件 if(!is_writable($configfile)) {//文件是否可写         showmessage('config_write_error'); }  $config_default = loadconfig('config.default.php');//载入默认配置文件 $error = array(); if(submitcheck()) {//检测是否提交         $newconfig = getgpc('newconfig');         if(is_array($newconfig)) {//是否为数组                 $checkarray = $setting['config']['ucenter'] ? array('source', 'target', 'ucenter') : array('source', 'target');                 foreach ($checkarray as $key) {                         if(!empty($newconfig[$key]['dbhost'])) {                                 $check = mysql_connect_test($newconfig[$key], $key);                                 if($check < 0) {                                         $error[$key] = lang('mysql_connect_error_'.abs($check));                                 }                         } else {                                 $error[$key] = lang('mysql_config_error');                         }                 }                 save_config_file($configfile, $newconfig, $config_default);                 if(empty($error)) {                         $db_target = new db_mysql($newconfig['target']);                         $db_target->connect();                         delete_process('all');                         showmessage('config_success', 'index.php?a=select&source='.$source);                 }         } }  showtips('如果无法显示设置项目,请删除文件 data/config.inc.php'); $config = loadconfig('config.inc.php'); if(empty($config)) {         $config = $config_default; } show_form_header(); show_config_input('source', $config['source'], $error['source']); show_config_input('target', $config['target'], $error['target']); if($setting['config']['ucenter']) {         show_config_input('ucenter', $config['ucenter'], $error['ucenter']); } show_form_footer('submit', 'config_save');  ?>

跟踪save_config_file 函数

function lang($name, $vars = array()) {         static $language;         if($language === null) {                 @include DISCUZ_ROOT.'./language/lang.php';                 if(empty($language)) {                         $language = array();                 }         }         $ret = isset($language[$name]) ? $language[$name] : $name;         if(!empty($vars)) {                 foreach ($vars as $key => $value) {                         $ret = str_replace('{'.$key.'}', $value);                 }         }         return $ret; }  function show_hidden_field($name, $value) {         echo '<input type="hidden" name="'.$name.'" value="'.$value.'">'."/n"; }  function show_form_header($method = 'post') {         echo <<<EOT <form method="$method" action="index.php"> <input type="hidden" name="a" value="$GLOBALS[action]"> <input type="hidden" name="source" value="$GLOBALS[source]"> <input type="hidden" name="submit" value="yes"> EOT; }  function show_form_footer($submitname = '', $submitvalue = 'submit') {         if($submitname != '') {                 $submitvalue = lang($submitvalue);                 echo <<<EOT <table class="button">         <tr><td><input type="submit" value="$submitvalue" name="$submitname"></td></tr> </table> EOT;         }         echo '</form>'; }  function show_config_input($type, $config, $error = array()) {         $title = lang('config_type_'.$type);         show_table_header();         show_table_row(array(array('colspan="3"', $title)), 'header title');         if($type == 'target') {                 show_table_row(array(array('colspan="3"', '<font color="red">'.lang('config_type_target_comment').'</font>')), 'bg2');         }         foreach ($config as $key => $value) {                 $addmsg = $error && $key == 'dbhost' ? lang($error) : '';                 $tip = $key == 'pconnect' ? lang('tips_pconnect') : '';                 show_table_row(        array(                 array('width="150"', lang('config_'.$key)),                 array('class="bg2"', '<input type="text" size="40" name="newconfig['.$type.']['.$key.']" value="'.htmlspecialchars($value).'">'),                 array('class="bg2"', '<font color="red">'.$tip.'</font><font color="red">'.$addmsg.'</font>')                 ), 'bg1'                 );         }          show_table_footer();         echo '<br>'; }  function getvars($data, $type = 'VAR') {         $evaluate = '';         foreach($data as $key => $val) {                 if(!preg_match("/^[a-zA-Z_/x7f-/xff][a-zA-Z0-9_/x7f-/xff]*$/", $key)) {                         continue;                 }                 if(is_array($val)) {                         $evaluate .= buildarray($val, 0, "/${$key}")."/r/n";                 } else {                         $val = addcslashes($val, '/'//');                         $evaluate .= $type == 'VAR' ? "/$key = '$val';/n" : "define('".strtoupper($key)."', '$val');/n";                 }         }         return $evaluate; }  function buildarray($array, $level = 0, $pre = '$_config') {         static $ks;         if($level == 0) {                 $ks = array();                 $return = '';         }          foreach ($array as $key => $val) {                  if($level == 0) {                         $newline = str_pad('  CONFIG '.strtoupper($key).'  ', 50, '-', STR_PAD_BOTH);                         $return .= "/r/n// $newline ///r/n";                 }                  $ks[$level] = $ks[$level - 1]."['$key']";                 if(is_array($val)) {                         $ks[$level] = $ks[$level - 1]."['$key']";                         $return .= buildarray($val, $level + 1, $pre);                 } else {                         $val = !is_array($val) && (!preg_match("/^/-?[1-9]/d*$/", $val) || strlen($val) > 12) ? '/''.addcslashes($val, '/'//').'/'' : $val;                         $return .= $pre.$ks[$level - 1]."['$key']"." = $val;/r/n";                 }         }         return $return; }  function save_config_file($filename, $config, $default) {         $config = setdefault($config, $default);          $date = gmdate("Y-m-d H:i:s", time() + 3600 * 8);         $year = date('Y');         $content = <<<EOT <?php   /$_config = array();  EOT;         $content .= getvars(array('_config' => $config));         $content .= "/r/n// ".str_pad('  THE END  ', 50, '-', STR_PAD_BOTH)." ///r/n/r/n?>";         file_put_contents($filename, $content); }  function setdefault($var, $default) {         foreach ($default as $k => $v) {                 if(!isset($var[$k])) {                         $var[$k] = $default[$k];                 } elseif(is_array($v)) {                         $var[$k] = setdefault($var[$k], $default[$k]);                 }         }         return $var; } 

 简单点来说,创建文件config.inc.php  然去加载 config.default.php 替换内容没有过滤 写入 config.inc.php

0x06:扩展:

最近暗月有时间会写下关于Discuz渗透方面的文章,这是开头篇,欢迎长期关注暗月论坛微信号 (moonsec)和本论坛。

dzscan team:http://dzscan.org/

moon_Discuz_utility 下载:moon_Discuz_utility.zip

 

 

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: