CVE-2025-67847

Class Is Cancelled: RCE in Moodle's Restore Interface (CVE-2025-67847)

Alon Barad
Alon Barad
Software Engineer

Jan 24, 2026·6 min read·11 visits

Executive Summary (TL;DR)

Moodle's course restore feature blindly trusts parts of the backup archive structure. An attacker with 'Teacher' privileges can upload a crafted `.mbz` backup file containing malicious payloads. When Moodle parses this file to restore the course, it triggers arbitrary code execution, handing the attacker a shell with web server privileges.

A critical Remote Code Execution vulnerability in Moodle's core backup/restore functionality allows authenticated users (like Teachers) to compromise the entire server by uploading malicious course archives.

The Hook: Trust Issues

In the world of web security, file uploads are the "Check Engine" light that you've been ignoring for three years. You know it's going to be a problem, you just don't know when the engine block is going to melt. Moodle, the behemoth of Learning Management Systems (LMS), relies heavily on a feature called "Course Restore." It allows educators to move courses between sites or restore backups. It sounds mundane, but technically, it is a minefield.

The process involves taking a compressed archive (.mbz), unzipping it, parsing a labyrinth of XML configuration files, and reconstructing complex PHP objects and database entries. It is essentially a deserialization bomb waiting to go off. The developers assumed that because the feature requires authentication (usually a Teacher or Admin role), the input would be benevolent. That assumption is what we in the industry call "optimistic," and what hackers call "an open invitation."

CVE-2025-67847 isn't just a bug; it's a fundamental flaw in trust. Moodle treats the contents of a backup file—which is just user-controlled input wrapped in a ZIP—as a set of instructions to follow blindly. When you let a user write instructions for your server to execute, you shouldn't be surprised when they instruct it to open a reverse shell.

The Flaw: Logic in the Blender

The vulnerability lives deep within the core_backup and core_restore subsystems. When Moodle restores a course, it reads XML files (like moodle_backup.xml) that define everything from course settings to file references. The flaw specifically is an Improper Control of Generation of Code (CWE-94).

Here is the breakdown: The restore engine reads values from the XML and, in certain edge cases, uses them to dynamically instantiate classes or execute logic to rebuild the course state. If the sanitization is lazy—or nonexistent—an attacker can inject data that Moodle doesn't just store, but acts upon.

The specific vector here involves Moodle parsing serialized PHP objects or improperly validated XML elements that trigger magic methods. PHP's unserialize() is notorious for this, but even without direct unserialization, if the application takes a string from the XML and uses it in a call_user_func() or a dynamic class instantiation context without a strict allowlist, you achieve Code Injection. In this case, the restore routine fails to verify that the data being processed matches the expected data types before passing them to sensitive internal functions.

The Code: The Smoking Gun

While the exact diff is protected to prevent mass exploitation of unpatched systems, the vulnerability pattern is classic. Imagine a simplified version of the restore logic. The vulnerable code likely looked something like this, iterating over XML nodes and dynamically handling them:

// VULNERABLE LOGIC (Conceptual)
$data = $xml_parser->get_next_element();
// The code blindly trusts the 'handler' class specified in the backup
if (isset($data['handler_class'])) {
    $handler = new $data['handler_class']($data['params']);
    $handler->execute();
}

In the code above, if an attacker controls $data['handler_class'], they can instantiate any class available in the Moodle autoloader. If they find a class with a destructor or a constructor that performs file operations (a "gadget"), they win.

The fix involves enforcing strict type checking and allow-listing. The patched version likely introduces a validation layer that checks the class name against a hardcoded list of allowed restore handlers before instantiation:

// PATCHED LOGIC (Conceptual)
$allowed_handlers = ['restore_structure_step', 'restore_dbops'];
 
$handler_class = $data['handler_class'];
if (!in_array($handler_class, $allowed_handlers, true)) {
    throw new restore_exception('Invalid handler detected');
}
// Safe to instantiate now
$handler = new $handler_class($data['params']);

By moving from an implicit trust model ("run whatever the file says") to an explicit trust model ("only run what we know is safe"), the RCE vector is closed.

The Exploit: School's Out Forever

Exploiting this requires an authenticated user account, but don't let that lower the severity score. In a university setting, "Teacher" accounts are handed out to thousands of adjuncts, TAs, and staff. Compromising one weak password gives you the keys to the kingdom.

Step 1: The Payload. The attacker creates a valid-looking Moodle backup. They can start by exporting a legitimate empty course.

Step 2: The Injection. They unzip the .mbz file and modify moodle_backup.xml. They locate the section responsible for defining restore steps or file handlers. They inject a PHP Object Injection payload or a malicious class definition designed to trigger a system command (e.g., system('id')) upon instantiation.

Step 3: The Delivery. The attacker logs in as the compromised Teacher, navigates to Course Administration > Restore, and uploads the evil.mbz file.

Step 4: Detonation. The moment the "Restore" button is clicked, Moodle's backend process (often running as www-data) parses the XML. It hits the malicious tag, instantiates the gadget, and executes the command. The attacker now has a reverse shell. From there, they can dump the mdl_user table, change grades, or pivot to the internal LDAP server.

The Impact: Why We Panic

This is a CVSS 8.8 High severity issue, and frankly, that might be conservative depending on your environment. The impact is total confidentiality, integrity, and availability loss.

Data Theft: Moodle databases are treasure troves. Student PII, home addresses, grades, and sometimes payment information. A shell on the web server usually implies read access to config.php, which contains the cleartext database credentials.

Ransomware: educational institutions are prime targets for ransomware. With RCE, an attacker can encrypt the course materials and the database, effectively shutting down the university's ability to operate.

Academic Integrity: Imagine the chaos if a hacker subtly altered grades across the board. The trust in the institution would be shattered irrevocably. This isn't just a technical glitch; it's an existential threat to the organization's reputation.

The Fix: Closing the Window

If you are running Moodle 5.1.0, 5.0.x, or older branches like 4.5.x/4.1.x, you are vulnerable. The remediation is straightforward but urgent.

1. Patch Immediately: Update to versions 5.1.1, 5.0.4, 4.5.8, 4.4.12, or 4.1.22. Moodle has backported the fix to LTS versions, so you have no excuse to stay on insecure code.

2. Least Privilege: Why does every adjunct professor need the ability to restore course backups? Review your roles. Remove the moodle/restore:restorecourse capability from the standard Teacher role and create a specialized "Course Creator" role for the few who actually need it.

3. Monitoring: Set up alerts for the creation of restore processes in your logs, specifically looking for failures or anomalies in the restore log files. If a restore fails with a "class not found" or "serialization error," investigate immediately—it might be a failed exploit attempt.

Technical Appendix

CVSS Score
8.8/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
0.04%
Top 100% most exploited
100,000
via Shodan

Affected Systems

Moodle LMS 5.1.0Moodle LMS 5.0.0 - 5.0.3Moodle LMS 4.5.0 - 4.5.7Moodle LMS 4.4.0 - 4.4.11Moodle LMS 4.1.0 - 4.1.21

Affected Versions Detail

Product
Affected Versions
Fixed Version
Moodle
Moodle
= 5.1.05.1.1
Moodle
Moodle
>= 5.0.0, <= 5.0.35.0.4
Moodle
Moodle
>= 4.5.0, <= 4.5.74.5.8
Moodle
Moodle
>= 4.1.0, <= 4.1.214.1.22
AttributeDetail
CWE IDCWE-94 (Code Injection)
CVSS Score8.8 (High)
Attack VectorNetwork (Authenticated)
Attack ComplexityLow
Privileges RequiredLow (e.g., Teacher)
ImpactConfidentiality, Integrity, Availability (High)
CWE-94
Improper Control of Generation of Code ('Code Injection')

The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.

Vulnerability Timeline

Vulnerability Publicly Disclosed
2025-01-23
Patches released for all supported branches
2025-01-23
GHSA-xvmh-25jw-gmmm Published
2025-01-23

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.