我在测试修复的时候发现Discuz! X的门户编辑器和论坛编辑器体制不一样,系统会直接提交html代码上去,所以无法通过简单的转义方式进行XSS的修复(POC提到通过转义修复,实际上不行,如果那么修复了那门户页面上都是html代码......)
该漏洞触发点有两个,一个是在dz开启门户功能的前提下,可通过发布文章实现一个存储型xss(在生成过程中也包含反射型型xss的生成…),在只开启论坛功能的情况下,可触发反射型型xss。已测试影响版本,discuz X2.5和discuz X3.4。(据此合理猜测影响全版本2333)
由于对于反射型 xss生成原理不了解,因此在本文中只给出反射型 xss的利用方法,具体漏洞触发逻辑不做分析。(有兴趣的大佬可自行分析)仅对门户功能导致的存储型xss进行分析。
该漏洞的生成点在于dz(discuz X在下文中简称为dz,我懒23333)自带的编辑器。该编辑器在门户发布文章或者修改文章,论坛回复帖子或发布帖子中均有使用。从而导致该漏洞影响范围广。
直接看编辑器部分。在编辑器中存在一个插入图片功能。该功能包含两个部分,一个是本地图片的上传,另一个是远程图片文件的插入。问题就出在远程图片插入这个部分。在该文本框中未对输入的内容进行过滤,导致双引号的传入,从而引发反射型 xss。
插入图片中的payload,点击提交会发现成功弹框
在火狐中查看元素可以看到,以下代码:
会发现我们插入的payload被页面成功解析为img标签的事件。
以上步骤在dz的门户功能和论坛功能中均可实现。在论坛中发帖即可看到相同的编辑器。同样在插入图片处输入payload即可复现。
考虑到存储型XSS漏洞安全隐患还是较大,我本来考虑通过过滤的形式进行修复,但是考虑到门户还是支持直接输入html的,这样修复会影响发布部分含有特殊代码的html。
在此我也抛砖引玉,给出过滤方式的修复方案。当然也希望各位大佬给出更好的,适合提交到主线的修复方案。
source\function\function_home.php
function getstr($string, $length = 0, $in_slashes=0, $out_slashes=0, $bbcode=0, $html=0) {
global $_G;
$string = trim($string);
$sppos = strpos($string, chr(0).chr(0).chr(0));
if($sppos !== false) {
$string = substr($string, 0, $sppos);
}
if($in_slashes) {
$string = dstripslashes($string);
}
$string = preg_replace("/\[hide=?\d*\](.*?)\[\/hide\]/is", '', $string);
if($html < 0) {
$string = preg_replace("/(\<[^\<]*\>|\r|\n|\s|\[.+?\])/is", ' ', $string);
$string = getstr_remove_xss($string);//添加的代码,调用以下函数
} elseif ($html == 0) {
$string = dhtmlspecialchars($string);
}
if($length) {
$string = cutstr($string, $length);
}
if($bbcode) {
require_once DISCUZ_ROOT.'./source/class/class_bbcode.php';
$bb = & bbcode::instance();
$string = $bb->bbcode2html($string, $bbcode);
}
if($out_slashes) {
$string = daddslashes($string);
}
return trim($string);
}
function getstr_remove_xss($string) {//添加的过滤函数,过滤了html标签的onxx属性
$parm = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
for ($i = 0; $i < sizeof($parm); $i++) {
$pattern = '/';
for ($j = 0; $j < strlen($parm[$i]); $j++) {
if ($j > 0) {
$pattern .= '(';
$pattern .= '(&#[x|X]0([9][a][b]);?)?';
$pattern .= '|(�([9][10][13]);?)?';
$pattern .= ')?';
}
$pattern .= $parm[$i][$j];
}
$pattern .= '/i';
$string = preg_replace($pattern, ' ', $string);
}
return $string;
}
历史资源提醒--必看
该页面资源/教程来自原魔趣吧历史资源转移,因发布历史久远,部分资源/教程可能已失效或无法在最新版程序中安装使用!DZ资源建议在Discuz3.4及以下版本使用,PHP版本建议5.6。资源仅提供做代码研究学习使用!
因改版,部分贴内链接将无法正常跳转,如链接失效或未正常跳转,请利用站内搜索功能搜索资源名称获取对应资源!