
Moodle 5.2.3 - Alto - Remoto - IDOR - core_grades_get_gradeitems lista itens de nota ocultos
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · moodle-grades-gradeitems
Write-up: https://abraxaslabs.tech/research/moodle-grades-gradeitems
Moodle LMS 5.2.3 - Moodle
Classe: IDOR Alcance: Remoto
core_grades_get_gradeitems é ajax mais o serviço oficial de mobile, sem chave capabilities em services.php. validate_context é a única barreira. Em seguida, grade_item::fetch_all despeja todos os itens do curso. O array_filter descarta GRADE_TYPE_NONE, itens de categoria e o item do curso. Oculto não está nesse filtro. O irmão core_grades_get_grade_tree já exige moodle/grade:viewall.
Um estudante matriculado faz POST de {courseid} e obtém os nomes de itens de nota ocultos que a interface do boletim do estudante ainda esconde.
| ID | sem CVE ainda |
| CWE | CWE-862 / CWE-200 |
| CVSS | Médio: 4.3 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N |
| Produto | Moodle |
| Afetado | 5.2.3 tag v5.2.3 (344232c15336c71b80f9aca8359ce0e0a9f3d116) |
| Autenticação | estudante matriculado (moodle/grade:view; sem viewall / viewhidden) |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1 |
Autor: um estudante matriculado no curso. Ele faz POST do serviço AJAX com {courseid}. A resposta contém nomes, IDs e categorias. O esquema de retorno não tem notas. Não é RCE. Não é LPE. Não é escrita de nota.
| Privilégio | Método / sink | Recon / integridade / disponibilidade | Comprovado em lab ou inferido |
|---|---|---|---|
| Ler nome, id e categoria de item de nota oculto | POST /lib/ajax/service.php?sesskey= core_grades_get_gradeitems {courseid} | Recon | Comprovado em lab. HTTP 200, nomes incluem MOODLE-GRADES-GRADEITEMS-WITNESS |
| Ler nome, id e categoria de item de nota visível | Mesma resposta | Recon (destinado a professores) | Comprovado em lab. nomes incluem Visible Lab Assignment |
| Mesmo catálogo pelo serviço oficial de mobile | Mesma classe, services inclui MOODLE_OFFICIAL_MOBILE_SERVICE | Recon | Inferido de services.php. O lab usou AJAX. |
Percorrer valores sequenciais de courseid para cursos nos quais o estudante pode entrar | Mesmo método, ids adivinhados | Recon | Inferido. O lab usou o id de curso semeado 2 |
| Ver o item oculto na interface do boletim do estudante | GET /grade/report/user/index.php?id= | n/a | Comprovado em lab fechado. hidden-in-ui=False, visible-in-ui=True |
| Chamar sem sessão | AJAX com um sesskey fictício | n/a | Comprovado em lab fechado. servicerequireslogin |
| Chamar como usuário logado que não está matriculado | AJAX de outsider, mesmo courseid | n/a | Comprovado em lab fechado. requireloginerror |
| Ler notas de outros estudantes ou escrever notas | n/a | n/a | Fechado. As chaves de retorno são id, itemname, category |
| RCE em PHP / LPE no SO | n/a | n/a | Fechado. Este resíduo é uma leitura de catálogo |
Um professor ou gestor que já possui moodle/grade:viewall já vê o catálogo. Chamadores convidados / não autenticados ainda precisam de um contexto de curso.
Mesmos restos de pin: leitura de arquivo img do Blackboard, SQLi no enrol_database, IDOR no feedback de notas.
Fixe o moodle/moodle v5.2.3 após MSA-26-0042/0043. Os web services de notas estavam nessa janela do MSA. O get_gradeitems.php ainda não tem require_capability. A interface do aluno já ocultava o item. O catálogo AJAX não.
Caminhos errados já registrados: tratar o AJAX não autenticado 200 como o vazamento (o corpo é servicerequireslogin); chamar isso de IDOR de pontuação porque o nome do método tem grade (o schema é apenas nomes); esperar que get_grade_tree fosse o mesmo resto (ele já exige viewall). Um reverse shell. Teatro.
Moodle v5.2.3 ao vivo em php:8.3-apache + MariaDB 11.4. O seed matricula labstudent, deixa laboutsider fora do curso e cria um item manual visível mais um item oculto cujo nome é a testemunha. O run.sh copia um pin local ou git clone --depth 1 --branch v5.2.3. A árvore do Moodle não está neste pacote.
python3 moodle-grades-gradeitems-Abraxas-Labs.py
ou
cd lab
./run.sh
Aponte apenas para http://127.0.0.1:19590. Projeto do Compose moodle-grades-gradeitems. A stack é desmontada após a execução.
SUCCESS moodle-grades-gradeitems student-ajax=200 hidden-in-ajax=yes hidden-in-ui=no visible-in-ajax=yes visible-in-ui=yes outsider-error=yes unauth-error=yes MOODLE-GRADES-GRADEITEMS-WITNESS
Após validate_context, exigir o mesmo limite de capacidade que get_grade_tree: require_capability('moodle/grade:viewall', $context). Também remover itens ocultos, a menos que o chamador tenha moodle/grade:viewhidden. Adicionar um caso Behat/PHPUnit: estudante matriculado, item manual oculto, core_grades_get_gradeitems deve omitir esse item (ou 403). A interface do livro de notas do estudante já o oculta.
get_gradeitems.phpget_grade_tree.phpservices.php (core_grades_get_gradeitems, sem capabilities)GNU Affero GPL v3.0. Ver LICENSE. Apenas laboratório loopback. Sem garantia.