导语:本文分析Moodle的Quiz模块的关键漏洞,利用该漏洞teacher角色可以执行远程代码。本文将对该漏洞和对应补丁进行分析。
Moodle(Modular Object-Oriented Dynamic Learning Environment)是一个用于制作网络课程或网站的软件包。它是一个全球性的开发项目,用以支持社会建构主义(social constructionist)的教育框架。Moodle用户超过1.27亿用户,利用Moodle老师和学生可以管理课程活动,交换学习材料。本文主要讲述Moodle的关键漏洞,漏洞存在于Moodle的Quiz模块,可以通过teacher角色利用该漏洞来执行远程代码。如果Moodle版本低于3.5.0,研究人员建议用户更新到最新版本。
影响
攻击者的角色必须是老师,而且Moodle版本要早于3.5.0,以默认配置运行。通过其他漏洞进行提权也是有可能的。了解了漏洞和必要条件后,攻击者就可以在运行Moodle的服务器的操作系统上执行任意代码。用一个伪造的数学攻击,攻击者就可以绕过Moodle的内部安全机制,而这个安全机制是防止恶意代码执行的。
Quiz组件中的数学公式
Moodle允许老师设置有多种类型问题的测验。在计算题中,老师可以输入一个数学公式,Moodle会通过随机的输入变量动态地对公式进行评估。这就可以防止学生作弊或分享答案。比如,老师想要学生计算x加y两个数的和,那么就在问题的占位符中插入公式{x} + {y},那么学生看到的题目可能是(3.9+2.1)。最终,在公式输入中调用安全敏感PHP函数eval()来评估答案6。
为了强制执行无害的PHP代码的使用,Moodle的开发者引入了验证函数qtype_calculated_find_formula_errors()。
绕过
从上面的源码可以看出,1939行的preg_match()调用时非常严格的,不允许除了公式中的-+/*%>:^\~<?=&|!.0-9eE以外的字符出现。1927行的str_replace()会替换公式中所有的占位符。相应的正则表达式表明占位符名仅限于字符集中有的部分。从中我们可以看出一个弱点,那就是可能会隐藏恶意字符,防止preg_match()调用。使用这种技术来隐藏恶意代码,并将这些与嵌套占位符相结合就会产生可利用的漏洞。
第一个恶意公式会被validatorqtype_calculated_find_formula_errors()拒绝。可以看到第二个payload中,如果把占位符嵌入到括号中,validator不会去检测攻击,但是会用随机数去替换占位符。如果引入另一个占位符并将其放置在已有占位符附近,Moodle只会替换内部占位符,剩下的占位符就会到达eval()函数。因为eval()的输入是无效的PHP代码,所以payload就会出现一个PHP语法错误。(原文附带视频)
补丁
在将问题报告给Moodle后,Moodle很快就做出响应并提出补丁来快速解决该问题。但研究人员用RIPS再次扫描应用时发现来了同样的绕过漏洞。
补丁1:黑名单
Moodle开发者提出的第一个补丁是基于拒绝利用payload使用的含有PHP注释的公式。代码中可以看到,补丁预先在foreach loop中来检查公式中是否含有特定字符串。
该补丁让当前payload变得无用了,因为validator函数qtype_calculated_find_formula_errors()会检测当前利用payload中PHP注释中的//,/*,#等字符。该补丁是基于黑名单的方法,还基于攻击者不能修正无效的PHP语法。但该补丁对于更加复杂的payload利用是不够的。
补丁2:拒绝嵌套占位符
第二个补丁的原理是防止payload中使用嵌套占位符,这可以在检测占位符时移除递归来实现。
当输入嵌套占位符{a{b}}时间,qtype_calculated_find_formula_errors()方法把{b}替换为占位符,把左边的替换为{a1}被认为是不合法的。如果把公式变为{b}{a1}{a{b}},那么函数find_dataset_names()会检测并返回两个占位符{b}和{a1}。当占位符在以{b}开头的foreach循环中时,公式就会被替换成1{a1}{a1}。在替换完{a1}之后,公式就等于111了;这样的嵌套占位符就打破了补丁2的目的。
补丁3:黑名单和线性替换
补丁3融合了补丁1和补丁2的方法,在预防嵌套占位符上效果非常好。如果攻击者的目标是Quiz不见得import特征,那么就可以重新import一个恶意的XML问题文件,攻击者就可以控制substitute_variables()的$dataset参数,并使占位符的替换无效。
上面的代码1951行显示XML文件定义了占位符x的名字。而占位符并没有在1946行的公式中使用。这也会使对占位符{system($_GET[0])}的替换无效,导致与前2个补丁同样的代码注入漏洞。
总结
本文分析了Moodle的关键漏洞,因为Moodle经常集成在大型的eLearning平台中。因为漏洞的存在,学生可以通过执行恶意代码来给自己所学的课程打分。研究人员对本文报告的漏洞进行了修复,提出4个补丁,但其中一些补丁不能完全解决漏洞利用的payload。因此,研究人员建议更新到最新版的Moodle。