用户
搜索
  • TA的每日心情
    慵懒
    2018-11-2 10:04
  • 签到天数: 139 天

    连续签到: 1 天

    [LV.7]常住居民III

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    35

    主题

    99

    帖子

    2323

    魔法币
    收听
    0
    粉丝
    4
    注册时间
    2015-11-20

    i春秋签约作者

    发表于 2018-6-14 14:06:28 75068

    Evil安全-Moodle3.4.2 远程代码执行漏洞分析

    有时候你不得不感叹RIPS审计软件的强大,好了,看文章吧。
    Moodle是一款广泛使用的开源电子学习软件,拥有超过1.27亿用户,允许教师和学生通过数字化方式管理课程活动并交换学习材料,这些材料通常由大学来部署。在本文中,我们将检查由RIPS代码分析检测到的以前Moodle版本中的一个关键漏洞的技术内幕。它位于Moodle的Quiz组件中,可以通过教师角色成功利用来进行远程代码执行。如果你运行的Moodle版本 <3.5.0,强烈建议立即将你的Moodle更新到最新版本。

    如何影响 - 谁可以利用?

    攻击者必须在Moodle(小于3.5.0)版本的使用过程中分配教师角色,并使用默认配置运行。如果不是教师角色,通过另一个漏洞(如XSS)升级到此角色也是可能的。由于有这些要求和漏洞的搭配,攻击者才能够在运行Moodle的服务器的底层操作系统上执行任意命令。通过使用由Moodle评估的特制数学公式 - 攻击者可以绕过防止恶意命令执行的内部安全机制。在下一节中,我们将分析下漏洞的具体技术细节。

    测验组件中的数学公式

    Moodle允许教师设置一个包含许多类型的问题的测验,其中有一个计算问题,它允许教师输入一个数学公式,并由随机输入变量动态地对Moodle进行评估。这可以防止学生作弊,并简单地分享他们的结果。例如,教师可以键入{x}加上{y}的值?答案公式变成{x} + {y}。然后,Moodle会生成两个随机数并将它们插入问答文本中的占位符{x}和{y}(例如3.9 + 2.1)。最后,它会通过调用对安全会敏感的PHP函数来评估答案6.0,eval()函数对输入的公式而言,它的恶意性是众所周知的,因为它允许执行任意PHP代码。

    question/type/calculated/questiontype.php
    
    public function substitute_variables_and_eval($str, $dataset) {
            // substitues {x} and {y} for numbers like 1.2 with str_replace():
            $formula = $this->substitute_variables($str, $dataset);  
            if ($error = qtype_calculated_find_formula_errors($formula)) {     
                return $error;                // formula security mechanism
            }
            $str=null;
            eval('$str = '.$formula.';');        // dangerous eval()-call
            return $str;
    }

    为了强制性只执行无危害的PHP代码,Moodle的开发者已经引入了一个校验函数qtype_calculated_find_formula_errors(),该函数在调用危险的eval()函数之前进行调用,目的是检测教师提供的公式中的非法恶意代码,并进行阻止。

    question/type/calculated/questiontype.php
    
    function qtype_calculated_find_formula_errors($formula) {
        // Returns false if everything is alright
        // otherwise it constructs an error message.
        // Strip away dataset names.
        while (preg_match('~\\{[[:alpha:]][^>} <{"\']*\\}~', $formula, $regs)){
            $formula = str_replace($regs[0], '1', $formula);
        }
    
        // Strip away empty space and lowercase it.
        $formula = strtolower(str_replace(' ', '', $formula));
    
        $safeoperatorchar = '-+/*%>:^\~<?=&|!'; /* */
        $operatorornumber = "[{$safeoperatorchar}.0-9eE]";
    
        // [...]
    
        if (preg_match("~[^{$safeoperatorchar}.0-9eE]+~", $formula, $regs)) {
            return get_string('illegalformulasyntax','qtype_calculated',$regs[0]);
        } else {
            // Formula just might be valid.
            return false;
        }
    }

    审计代码后绕过

    正如在上面的源代码中看到的那样,最后一次在19行preg_match()这里调用是非常严格的,并且禁止除-+/*%>:^\~<?=&|!.0-9eE公式以外的任何字符。然而,先前的str_replace()嵌套在一个while循环中对第7行将取代公式中类似于所有的占位符{x}的1进行递归。对应的正则表达式表示占位符的名称在其字符集的考虑几乎没有限制,所以{system(ls)}是有效的占位符,并也将被第8行中的1所取代。这个事实指出了一个弱点,因为它会因为preg_match()函数返回之前会隐藏所有潜在的恶意代码,通过返回false来表明这是一个有效的公式。使用这种技术来隐藏恶意代码并将其与嵌套占位符相结合,就会出现可利用的漏洞。

    NR  数学公式 合法性 eval()的参数 eval()的结果
    1   $ _GET [0] 非法
    2  {a.$ _GET [0]} 有效 1 | $str = 1.2; eval成功
    3 {a.$ _GET [0]; {X}} 有效 1 | $str= {a.$_GET[0];1.2}; PHP语法错误'{'
    4 /*{A*/$ _GET [0];//{X}} 有效 1 | $str= /*{a*/$_GET[0];//1.2}; eval成功

    第一个恶意公式被验证函数qtype_calculated_find_formula_errors()拒绝。如果我们使它成为一个占位符,并将其嵌入大括号中,那么验证器将无法检测到我们的攻击,但Moodle将数字1.2 在它到达eval()之前用随机数替换掉了我们的占位符。但是,如果我们引入另一个占位符并将其嵌入到我们已有的占位符中,Moodle将仅替换内部占位符,并且危险的剩余占位符将到达表格eval()的第三行。在这一点上,我们的有效payload将抛出一个PHP语法错误,因为输入eval()是无效的PHP代码。因此,我们只需通过使用PHP注释从PHP解析器中排除无效部分来修正PHP语法,从而导致我们在第四行的最终有效攻击公式,从而最终允许通过GET接收并执行恶意代码。

    <iframe width="560" height="315" src="https://www.youtube.com/embed/gzIVSFFeHeA" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>

    不完善的补丁

    在向Moodle报告问题后,他们立即回复并提出了一个补丁来快速解决问题。但是,使用RIPS重新扫描应用程序后,我们的SAST解​​决方案仍然检测到能指向绕过新引入的修补程序的相同漏洞。在更精确地检查相关源代码和扫描结果后,我们能够绕过补丁并获得与以前相同的效果。对于前三个建议更新的补丁,可能行很大,在接下来的小节中会解释每个绕过过程。

    第一个补丁:黑名单

    Moodle开发人员提出的第一个补丁是基于拒绝包含PHP注释中使用的公式的想法。正如你在代码中看到的那样,这个补丁前面加了一个foreach循环,它检查公式是否包含特定的字符串。

    question/type/calculated/questiontype.php
    
    function qtype_calculated_find_formula_errors($formula) {
            foreach (['//', '/*', '#'] as $commentstart) {
                    if (strpos($formula, $commentstart) !== false) {
                                    return get_string('illegalformulasyntax',
                                                      'qtype_calculated', 
                                                       $commentstart);
                    }
            }

    这个补丁使我们当前的有效payload不能执行了,因为qtype_calculated_find_formula_errors()检测了我们使用的攻击payload产生的PHP注释字符串//、/*、#。该补丁程序实施了黑名单方法,并基于这样的条件下,也就没有攻击者能够将上表中第3行的无效PHP语法更正为有效的PHP语法,而无需使用注释。然而,这个补丁并不完善,这个攻击payload的更复杂版本也是可以被允许利用的。

    md的表格有些无法转义,截图看看吧。

    第二个补丁:拒绝嵌套占位符

    第二个补丁的想法是通过在检测占位符时删除“递归”来防止在我们的有效payload中使用嵌套占位符。但是,再次使用RIPS重新扫描应用程序仍然报告了相同的漏洞,这导致我们更精确地查看以下新代码行。

    question/type/calculated/questiontype.php
    
    public function find_dataset_names($text) {
            // Returns the possible dataset names found in the text as an array.
            // The array has the dataset name for both key and value.
            if (preg_match_all('~\\{([[:alpha:]][^>} <{"\']*)\\}~',$text,$regs)) {
                    $datasetnames = array_unique($regs[1]);
                return array_combine($datasetnames, $datasetnames);
            } else {
                return [];
            }
         }
    // [...]
    function qtype_calculated_find_formula_errors($formula) {
        $datasetnames = find_dataset_names($formula);
        foreach ($datasetnames as $datasetname) {
            $formula = str_replace('{'.$datasetname.'}', '1', $formula);
         }

    无论什么时候我们输入一个嵌套的占位符,该方法qtype_calculated_find_formula_errors()现在只会将{a{b}}替换{b}为占位符,并将剩余公式{a1}检测为非法。但是,如果我们将公式更改为{b}{a1}{a{b}}两个占位符{b}并且{a1}被该find_dataset_names()函数检测并返回。一个接一个的,每个占位符在foreach我们开始的循环中被替换,{b}离开我们的公式1{a1}{a1}。最后,在替换{a1}公式equals之后成为111,验证程序会允许嵌套占位符,从而打破此补丁程序的限制。考虑到了这个技巧后,我们只需要适当调整下我们的最后一个有效payload以获得与以前相同的关键效果:

    如果不懂,可以查查字典。

    第三个补丁:黑名单和线性替换

    第三个补丁结合了前两种方法,并且在防止嵌套占位符方面看起来非常好。但是,如果攻击者针对Quiz组件的导入功能并重新导入恶意破坏性XML格式问题文件,则攻击者能够控制(substitute_variables()参见此处)$dataset参数并取消占位符替换。

    Abstract malicious XML file
    <quiz>
        <question type="calculated">
            [...]
            <answer fraction="100">
                <text>log(1){system($_GET[0])}</text>
            </answer>
        </question>
        <dataset_definitions>
            <dataset_definition>
                <name><text>x</text></name>
            </dataset_definition>
        </dataset_definitions>
    </quiz>

    突出显示的XML文件定义了{x}11行的占位符的名称。第6行的占位符从未在公式中在线使用。将使我们危险占位符的替代变得无效,{system($_GET[0])}将导致我们在以前的补丁程序中遇到的相同代码注入漏洞问题。

    第四个补丁

    不幸的是,由于时间限制,我们无法完全验证第四个补丁的完整性。如果发生变化,我们将更新此博客帖子,并且当然会事先通知开发人员。

    时间表

    日期        ---------事件
    01 /5月/ 18        与供应商的第一次接触
    01 /5月/ 18        建议没有足够的补丁#1
    02 /5月/ 18        绕过#1报告并得到确认
    07 /5月/ 18        建议没有足够的补丁#2
    08 /5月/ 18        绕过#2报告并得到确认
    12 /5月/ 18        建议没有足够的补丁#3
    15 /5月/ 18        #3绕过建议并予以确认
    16 /5月/ 18        提议修补程序4
    17 /5月/ 18        修复发布

    概要

    在这篇文章中,我们研究了Moodle中的一个重要漏洞。Moodle经常集成到更大的系统中,将更大的系统加入WebMailer,电子学习平台和其他技术,并将其融入单一体系结构,共享帐户证书,为未经认证的攻击者提供钓鱼或提取教师帐户凭据的强大攻击面。在某些情况下,存在一个用于请求Moodle课程的自动化服务,这将使学生有权进入他可以执行他选择的恶意软件的位置,并在他参加的大学课程中为自己划定长期的A级。

    在自动化安全分析的帮助下,不仅在10分钟内报告了漏洞本身,而且还报告了修补不足的补丁,这可以节省很多很多的人工投入。我们要感谢Moodle团队在修补这个问题上的快速反应和合作,最后我们建议使用者更新到最新的Moodle版本。

    参考来源:https://blog.ripstech.com/2018/moodle-remote-code-execution/

    很详细,谢谢分享
    使用道具 举报 回复
    发表于 2018-6-18 00:18:16
    使用道具 举报 回复
    发表于 2018-6-20 16:20:42
    使用道具 举报 回复
    发表于 2018-6-21 11:39:30
    使用道具 举报 回复
    发表于 2018-6-21 11:39:46

    感谢支持!
    使用道具 举报 回复
    发表于 2018-6-28 11:23:32
    长知识了,学习
    使用道具 举报 回复
    发表于 2018-10-7 12:13:50
    支持一下~
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册