Discuz 排行頁面儲存型XSS漏洞 分析
2018年10月12日,某CMS官方修復了一處XSS漏洞:
簡要分析
source/module/misc/misc_ranklist.php:166
<?php function getranklist_members($offset = 0, $limit = 20) { require_once libfile('function/forum'); $members = array(); $topusers = C::t('home_show')->fetch_all_by_unitprice($offset, $limit, true); foreach($topusers as $member) { $member['avatar'] = avatar($member['uid'], 'small'); $member['note'] = dhtmlspecialchars($member['note']); $members[] = $member; } return $members; }
Dz在此處獲取到 $member['note']
後呼叫了 dhtmlspecialchars
進行過濾,在source/function/function_core.php:203 會對'&', '"', '<', '>'進行實體編碼。
<?php function dhtmlspecialchars($string, $flags = null) { if(is_array($string)) { 。。。 } else { if($flags === null) { $string = str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $string); } else { 。。。 } return $string; }
從 getranklist_members
返回後 source/include/misc/misc_ranklist_index.php:113
<?php 。。。 if($ranklist_setting['member']['available']) { $memberlist = getranklist_members(0, 27); } 。。。 include template('diy:ranklist/ranklist');
進行模板的渲染在 data/template/1_diy_ranklist_ranklist.tpl.php:32
<?php if($memberlist) { ?> <a href="home.php?mod=space&uid=<?php echo $memberlist['0']['uid'];?>&do=profile" target="_blank" id="bid_<?php echo $memberlist['0']['uid'];?>" class="hm" <?php if($memberlist['0']['note']) { ?> onmouseover="showTip(trhis)" tip="<?php echo $memberlist['0']['username'];?>: <?php echo $memberlist['0']['note'];?>"<?php } ?>><?php echo avatar($memberlist[0][uid],middle);?></a> <?php } ?>
可以看到在 tip
屬性中輸出了 $memberlist['0']['note']
。在之前有一個 onmouseover
事件,跟入 showTip(trhis)
在 static/js/common.js:1062
function showTip(ctrlobj) { $F('_showTip', arguments); }
跟入 _showTip
,在 static/js/common_extra.js:912
function _showTip(ctrlobj) { if(!ctrlobj.id) { ctrlobj.id = 'tip_' + Math.random(); } menuid = ctrlobj.id + '_menu'; if(!$(menuid)) { var div = document.createElement('div'); div.id = ctrlobj.id + '_menu'; div.className = 'tip tip_4'; div.style.display = 'none'; div.innerHTML = '<div class="tip_horn"></div><div class="tip_c">' + ctrlobj.getAttribute('tip') + '</div>'; $('append_parent').appendChild(div); } $(ctrlobj.id).onmouseout = function () { hideMenu('', 'prompt'); }; showMenu({'mtype':'prompt','ctrlid':ctrlobj.id,'pos':'12!','duration':2,'zindex':JSMENU['zIndex']['prompt']}); }
通過 ctrlobj.getAttribute('tip')
獲取tip屬性的值,由於 getAttribute
獲取的內容會自動反轉義,即前面在 dhtmlspecialchars
編碼過的內容又被解碼了一次。此後拼接到div標籤的 innerHTML
中,最後輸出到頁面上造成了xss
關於 getAttribute
,可以用下面程式碼測試:
<html> <div name="<a>" id="div">test</div> <script> div1 = document.getElementById("div"); align = div1.getAttribute("name"); alert(align); </script>
漏洞復現
該CMS中,排行榜功能是預設開啟的。在地址 ofollow,noindex">http://127.0.0.1/misc.php?mod=ranklist&type=member 的上榜宣言中輸入payload(拒絕伸手黨)
在 http://127.0.0.1/misc.php?mod=ranklist 當滑鼠移動到頭像上觸發 onmouseover
事件,執行xss
修復方案
多增加一次 dhtmlspecialchars
。