目录
漏洞信息分析
代码审计分析
总结
关于漏洞利用
漏洞修复
漏洞信息分析
漏洞信息的原话是这样的
“可以在日历块中的事件名称中注入JavaScript。但通常情况下,创建活动的能力只提供给信任的用户(如教师),所以不会被标记为具有XSS风险,而被视为安全问题。”
Xss注入点在’日历块中的事件名称中’
于是注册了一个账号,根据描述找了一下,并没有找到’event name’,但是找到了一些较为相近的,单单根据上面的漏洞描述信息,感觉xss注入点可能是在类似下面的链接的页面里。
可能一:
https://learn.moodle.net/calendar/view.php?view=month
可能二:
https://learn.moodle.net/calendar/managesubscriptions.php?course=1
继续查看信息,找到一个diff
很明显,这里的修复方法是对$name这个参数使用了clean_text()函数进行了过滤,也就是原来的$name变量是存在xss注入的。
代码审计分析
下面下载3.3.4版本的源码进行代码审计分析一下
(为什么下载修复后的3.3.4版本 不下载存在漏洞的3.3.3版本呢?因为3.3.3版本我没找到,而且3.3.4版本和3.3.3版本在这个漏洞上的不同只在于一句代码,所以我们完全可以拿3.3.4版本来分析。)
分析目标有两个
- 找出$name变量具体是在哪里传过来的(找到可控的点)
- 分析$name变量在没有进行clean_text()函数过滤时最后是在哪里输出,是如何导致xss注入的,如何构造payload
- 分析修补方案是否存在绕过(由于时间关系,这次暂不分析这一点)
漏洞修复点在/calendar/lib.php的1460行
这一行未修复前的代码为
跟进html_writer::link方法,class html_writer 类在/lib/outputcomponents.php第1590行,link方法在1732行,这里我整理了一下相关的代码,让逻辑更加清晰一点,贴出整理后的关键代码,可以得到如下逻辑
通过阅读这个逻辑可以知道,$name变量的变化过程是$name–$text–$contents,
,变量$popupcontent返回的内容的最后的格式肯定是类似这个样子的 <a ………>$name</………….a>
然后后面的变量的传递过程就是$popupcontent–$popupdata–$data–$cell然后最后实际上就是把$popupcontent输出到html页面,实际上就是把
<a ………>$name</………….a> 这样的内容输出到页面,并且在这个过程中(从返回$popupcontent到输出的过程中)没有对$name做任何的过滤。
下面我们可以验证一下输出的内容是不是像分析的 <a ………>$name</………….a> 这样的格式的
Ps:这里要说明一下,因为我搭建了很久都没有把那个moodle.的网站搭建起来,按照官方文档去搭建总是会显示安装出错,谷歌了好久也没搞定,所以最后很无奈,只能直接在这个页面做测试了(需要先登录)
https://learn.moodle.net/calendar/view.php?view=month
我们审查一下元素,可以看到
确实是符合<a ………>$name</………….a> 这样的格式的在这里$name=test
说明我们上面的分析是正确的。(这个页面的版本什么的可能会有发生一定的变化,发生的变化应该也是对$name变量进行了过滤而已,并不会影响$name输出的位置,而且我们这里使用的是 字符串‘test’进行的验证,目的是验证”我们上面的分析返回的$popupcontent值的格式是<a ………>$name</………….a>这样的” ,这里虽然版本会不一样,但实际上应该是不会影响这一个的验证的。)
既然上面我们已经分析和验证了,输入的$name,最后会以<a ………>$name</………….a>的格式输出,而且在这个过程中没有对$name进行过滤,那么在$event->name传递到$name的过程中,如果也没有对其进行过滤的话,这就可能造成xss注入了。
下面先分析$name的来源,有四处 分别在1444、1452、1454、1457行(实际上都是传入的$event-name)
先跟进一下format_string方法,在/lib/weblib.php 1409行,此部分代码有点多就不贴出了,但是可以发现这里也是没有对$event-name变量进行过滤的。
结合上面的分析,可以知道从1452、1454、1457行得到的$name是会存在xss注入的。
下面分析$name = get_string(‘namewithsource’, ‘calendar’, $a);
跟进get_string方法,在/lib/moodlelib.php 7031行,内容如下
我们继续跟进class lang_string这个类,在/lib/moodlelib.php 9827行
贴出部分关键代码
这部分的代码有点多,具体逻辑细节也稍微有点复杂,但是根据最初的这几句代码
我们可以知道,但其实我们的重点是要分析$name有没有被过滤,也就是分析$a->name有没有被过滤(因为可控变量是$event->name,传给了$a->name)所以我们只要关注在$a->name变量的传递过程中是否被过滤了就可以了。
经过跟踪$a的传递过程,并没有发现对$a->name有做过什么过滤,所以从第1444行进来的$name变量也是存在xss的
$name = get_string('namewithsource', 'calendar', $a);
并且根据代码的注释
以及初始漏洞的描述
以及我们上面的分析过程,我们可以知道$name变量是the event name in the calendar block,而且这个是我们完全可控的。也就是在类似这样的页面中
https://learn.moodle.net/calendar/view.php?view=month&time=1516665600&lang=en
这里我们只要输入<script>alert(0)</script>或者<img src=0 onerror=alert(0)>即可验证此漏洞。
(但是网页https://learn.moodle.net/calendar/view.php?view=month已经修复了这个漏洞,我没有办法在该网页上验证~然后moodle这个网站我又尝试了很久也没有搭建起来,总是会安装报错,谷歌也暂时没有找到有用的解决办法)
总结:
本漏洞存在的原因是存在可控输入点 Event title而且传递到$name中并且未经任何过滤就按以下格式直接输出<a….>$name</…a> 由此导致了xss注入 (此格式是简化格式)
(较完整格式类似下图)
关于漏洞利用:
但是这里利用这个漏洞需要用户先进行登录,我们才能打开日程管理模块,才能进行xss注入,所以利用起来可能会显得非常的鸡肋。
因为这里是属于存储型的xss,目前想到的一种利用方法就是 攻击者注册账户A,并在自己的日程管理模块中注入盲打cookie的xss代码,这样如果其他用户B访问查看了A的日程事件安排event的话,这时候就会执行A注入进去的xss代码,可能能够盲打到访问的用户B的cookie。
很遗憾的是没能够把环境搭建起来进行实际的测试。
漏洞修复
只需要更改/calendar/lib.php的1460行代码,把原来的
$popupcontent .= \html_writer::link($dayhref, $name);
改为
$popupcontent .= \html_writer::link($dayhref, clean_text($name));
即可