该漏洞触发点有两个,一个是在dz开启门户功能的前提下,可通过发布文章实现一个存储型xss(在生成过程中也包含反射型型xss的生成…),在只开启论坛功能的情况下,可触发反射型型xss。已测试影响版本,discuz X2.5和discuz X3.4。(据此合理猜测影响全版本2333)
由于对于反射型 xss生成原理不了解,因此在本文中只给出反射型 xss的利用方法,具体漏洞触发逻辑不做分析。(有兴趣的大佬可自行分析)仅对门户功能导致的存储型xss进行分析。
该漏洞的生成点在于dz(discuz X在下文中简称为dz,我懒23333)自带的编辑器。该编辑器在门户发布文章或者修改文章,论坛回复帖子或发布帖子中均有使用。从而导致该漏洞影响范围广。
在本文中以修改文章处的编辑器作示范。事先发布一篇文章,内容随意,标题随意。我这里生成的文章id为4因此得到如下url:
http://localhost/dz2/portal.php?mod=portalcp&ac=article&aid=4
直接看编辑器部分。在编辑器中存在一个插入图片功能。该功能包含两个部分,一个是本地图片的上传,另一个是远程图片文件的插入。问题就出在远程图片插入这个部分。在该文本框中未对输入的内容进行过滤,导致双引号的传入,从而引发反射型 xss。
插入图片中的payload,点击提交会发现成功弹框
在火狐中查看元素可以看到,以下代码:
会发现我们插入的payload被页面成功解析为img标签的事件。
以上步骤在dz的门户功能和论坛功能中均可实现。在论坛中发帖即可看到相同的编辑器。同样在插入图片处输入payload即可复现。
以下功能仅限于开启门户功能的dz。接下来对存储xss进行分析。
在以下漏洞中,我将payload替换为:’http://XXXXX/xss/1.png“ onclick=alert(1) =’
因为onerror的弹窗真的很烦………..
在插入图片后点击提交。便会将我们生成的文章内容插入数据库。我们通过其提交时的流量包进行跟踪可得到如下流程。
流量包如下:
可以看到,入口文件是portal.php文件。
跟进source\module\portal\portal_portalcp.php文件
继续跟进source\include\portalcp\portalcp_article.php:
在图中可以看到我们通过post提交的文章的具体内容进入了这个getstr函数,特别需要注意的是getstr函数参数列表中的最后这个1。
继续跟进getstr函数,函数位于source\function\function_home.php:
可以看到,该函数的确实现了对于字符串的过滤操作。但是,千不该万不该,不该将html参数设置为1,这样导致对字符串进行过滤的并不是dhtmlspecialchars()函数,而是一个自定义的正则匹配。我们可以很清晰的看到,该正则并未对双引号单引号进行过滤。
换句话说,该函数并未对我们传入的payload进行任何处理。
接下来我们的payload就一路畅通无阻的到达和数据库交互的地方,source\include\portalcp\portalcp_article.php:
如果是发布文章,那么进入插入的代码块,否则进入更新代码块。
这里对C::t(string)功能进行一个简要介绍:C类继承于source/class/class_core.php中的core类。Core类中存在t方法。t方法的主要功能就是引入pre_string类(pre为前缀)。Pre_string类对应着pre_string表,Pre_string类中的各种方法对应着对于pre_string表的各种操作。
在这里我们跟进执行插入操作的代码块。其中涉及C::t(‘portal_article_content’),那么我们就可以知道是引入pre_portal_article_content类,对应的操作表为pre_portal_article_content表(我在数据库中设置的前缀就是pre)
跟踪其中调用的insert方法,我们会发现最终调用的是source/class/discuz/discuz_database.php文件里discuz_database类中的insert方法:
由于在先前对于字符串进行过过滤,因此在此处dz对于我们输入的数据不再进行过滤。打印执行语句:
重点关注最后一个insert语句,可以看到我们的payload已经被拼接成一个符合正常语法的img标签和a标签。成功存入数据库。数据库中的数据如下:
接下来我们来看访问文章时该漏洞是如何触发的。由于我们先前插入文章时的aid为19,因此我们构造如下url:http://localhost/dz2/portal.php?mod=view&aid=19
当然,我们在生成文章之后会弹出界面让我们选择是否查看文章。
点击文章中的图片产生以下结果:
入口文件依旧是protal.php:
跟进\source\module\portal\portal_view.php文件,在该文件中执行数据取出,之后再对模板文件执行文件包含:
跟进data/template/1_diy_portal_view.tpl.php文件:
在该文件中,可看到直接将从数据库中取出的$content[‘content’]输出,未做任何过滤处理。最后形成我们在前段看到的如下代码:
Poc:
反射型 xss:
随便找个可使用编辑器的地方,如
http://localhost/dz2/forum.php?mod=post&action=newthread&fid=2
输入以下payload:
‘z” onerror=alert(1) =’ //相信你们可以构造更好的payload
即可实现弹框
存储xss:
利用前提:目标网站开启门户功能,并且所在用户组有发表文章的权限
发表文章:http://localhost/dz2/portal.php?mod=portalcp&ac=article
利用该界面的编辑器插入payload。
访问生成的文件即可。也在论坛里发布生成文章的链接,文字配上“澳门性感荷官在线发牌”这类的:)
修改方案:
反射型 xss:不会
存储xss:
1、重写编辑器 (根本解决方案)
2、将source\include\portalcp\portalcp_article.php文件中的$content = getstr($_POST[‘content’], 0, 0, 0, 0, 1);改为$content = getstr($_POST[‘content’], 0, 0, 0, 0, 0);
3、在data/template/1_diy_portal_view.tpl.php中过滤$content[‘content’]