
Nom de l'application : Moodle
Version de build : moodle-4.4.1
Versions affectées : 4.4 à 4.4.1, 4.3 à 4.3.5, 4.2 à 4.2.8, 4.1 à 4.1.11 et les versions antérieures non prises en charge
Lien de téléchargement : moodle-4.4.1
Les attaquants disposant de la permission de créer ou de modifier des questions dans un cours Moodle peuvent générer des entrées malveillantes pour les questions calculées, qui peuvent être exploitées pour exécuter des commandes arbitraires sur le système sous-jacent.

La fonction qtype_calculated_find_formula_errors garantit la validité des formules saisies dans Moodle, empêchant les erreurs de syntaxe.

Les variables sont remplacées par le nombre 1.0, la formule est convertie en minuscules et les espaces sont supprimés.


La logique de validation principale est mise en œuvre en parcourant la formule et en déterminant l'expression mathématique la plus à gauche, identifiable par l'absence de parenthèses imbriquées. Ensuite, cette expression est remplacée par 1.0.

Enfin, lorsque l'expression régulière ne renvoie plus de correspondance supplémentaire, la formule est considérée comme valide si elle ne contient que des opérateurs ou des nombres sûrs. La formule d'origine est ensuite transmise à eval.
La vérification du résultat est effectuée en transmettant la formule à la fonction php eval() après un filtrage incomplet. Il existe 2 approches pour contourner la logique de validation :

Les variables de substitution comme {a} sont remplacées par leurs valeurs entourées de parenthèses (). Si l'on ajoute {a} à l'expression ci-dessus correspondant à 'PRINTF', le résultat sera 'PRINTF'(1). Il est donc possible de définir une formule de réponse avec deux parties : a (function_name) et a {variable}.
2) Les variables non définies ne sont pas remplacées avant d'être transmises à la fonction eval(), de sorte qu'elles ne sont pas affectées en tant que partie de la formule. De plus, les contrôles d'assainissement des noms de variables sont moins stricts que ceux mis en œuvre pour toutes les autres parties de la formule. Cela peut être exploité pour appeler des fonctions arbitraires en utilisant la syntaxe php object->{"member"}.
Créez une question calculée avec une variable, par exemple {a}

Enregistrez la question et définissez la plage de valeurs de la variable comme étant exactement l'ID du cours, soit 3.

Enregistrez la question, puis modifiez l'expression en :
((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}

L'enregistrement de la question modifiée entraînera une erreur, mais la question sera quand même enregistrée. Revenez à la banque de questions et prévisualisez la question : la fonction DELETE_COURSE supprimera le cours dont l'ID est spécifié, en ignorant tous les contrôles d'autorisation.


Créez une question calculée. Définissez la formule de réponse sur :
(1)->{system($_GET[chr(97)])}

L'expression est modifiée en 1-0-system($_GET{chr(97)})

Interceptez la requête et modifiez-la à nouveau en (1)->{system($_GET[chr(97)])} %281%29-%3E%7Bsystem%28%24_GET%5Bchr%2897%29%5D%29%7D

Une erreur apparaît : exception-system():Argument#1($command) cannotbe empty

Fournissez la commande souhaitée en ajoutant &a=[arbitrary command] à l'URL. La sortie de la commande système spécifiée sera placée au début de la réponse HTTP résultante.
A=id

A=ls

Corrigez la fonction d'assainissement qtype_calculated_find_formula_errors afin que /question/type/calculated/questiontype.php renvoie toujours false si les questions calculées ne sont pas utilisées.