Moodle 5.2.3 - Alto - Remoto - SQLi - enrol_database concatena o idnumber do curso no SQL
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · moodle-enrol-database-sqli
Moodle LMS 5.2.3 - Moodle
Classe: SQLi Alcance: Remoto
enrol_database::db_get_sql ainda escapa com barras e concatena. O MSA-26-0005 / MDL-88138 parametrizou o auth_db como Execute($sql, [$value]). Este plugin não copiou esse formato. Padrões nas configurações: dbsybasequoting=0, localcoursefield=idnumber. O sink é o banco de dados de matrícula externo. O $DB do núcleo do Moodle não está nesse caminho.
Um professor com permissão de edição em um site com o enrol_database habilitado define o idnumber do curso. O cron interpola esse valor. Linhas extras retornam do banco de matrícula.
| ID | ainda sem CVE |
| CWE | CWE-89 |
| CVSS | Alto: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| Produto | Moodle |
| Afetado | tag 5.2.3 v5.2.3 (344232c15336c71b80f9aca8359ce0e0a9f3d116). O plugin enrol_database precisa estar ativo. |
| Autenticação | professor com permissão de edição (idnumber do curso, mapeamento local padrão) |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1 |
Um professor com permissão de edição em um site com o enrol_database habilitado injeta SQL no banco de dados de matrícula externo ao definir o idnumber do curso. O cron sync_enrolments então executa esse SQL.
| Privilégio | Método / sink | Reconhecimento / integridade / disponibilidade | Comprovado em lab ou inferido |
|---|---|---|---|
| Inserir um fragmento SQL no SELECT de matrícula externo | Cron sync_enrolments -> db_get_sql($table, array($coursefield=>$course->mapping), ...) -> $extdb->Execute($sql) | Integridade da string de consulta | Comprovado em lab. SQL concatenado é WHERE courseid = 'LABCOURSE\'' OR 1=1 -- ' |
| Ler linhas de matrícula de outros cursos nesse banco externo | Mesmo SELECT após o fechamento da string | Reconhecimento | Comprovado em lab. Limpo: 1 linha teacher-local. Injeção: 2 linhas incluindo MOODLE-ENROL-DATABASE-SQLI-WITNESS |
| Ignorar a consulta quando o plugin está desativado | Mesmo gadget, plugin=off | n/a | Comprovado em lab fechado. executed=false, SQL vazio, 0 linhas |
| Manter o mesmo payload como parâmetro vinculado | Resquício do auth_db do MSA-26-0005: Execute($sql, [$value]) | n/a | Comprovado em lab fechado. style=param retornou 0 linhas, SQL contém ? |
| Matricular / desmatricular / atribuir papel a usuários do Moodle nomeados nas linhas extras | Após o cron aplicar requestedenrols | Integridade das matrículas | Inferido. O lab para nas linhas extras no banco de matrícula |
| FILE / INTO OUTFILE como o usuário do banco de matrícula | Mesmo sink se essa conta tiver FILE | Integridade / disponibilidade desse host de banco | Inferido. Não demonstrado. Não é LPE de SO |
| Caminho controlado por estudante | Apenas se o admin mapear localuserfield=email (ou similar) | n/a | Inferido. O caminho padrão é o idnumber do professor |
Fechado neste resquício: $DB do núcleo do Moodle; plugin desativado (sem consulta); acesso não autenticado; shell do SO; consultas empilhadas (este gadget mysqli é de instrução única). O Moodle padrão sem enrol_database não é este bug.
Mesmos resquícios do pin: leitura de arquivo img do Blackboard, IDOR de feedback de notas, itens de nota ocultos.
Fiz o pin do moodle/moodle v5.2.3 após o MSA-26-0042/0043. O MSA-26-0005 fechou o auth_db com um placeholder. Abri o enrol_database porque ele fala com o mesmo tipo de banco externo e ainda tem db_addslashes.
dbsybasequoting tem padrão 0, então apenas ' é duplicado. Uma barra invertida seguida de aspas no idnumber fecha a string do MySQL.
Caminhos errados já registrados: tratar o $DB do núcleo do Moodle como o sink (não é); chamar isso de LPE de SO porque FILE existe como privilégio do MySQL (não demonstrado, não é este resquício); email de estudante como o mapeamento padrão (o admin precisa alterar localuserfield). Um reverse shell. Teatro.
Gadget fiel dos construtores do pin, não um app PHP completo do Moodle. php:8.3-cli serve o db_get_sql / db_addslashes / db_encode copiados. mysql:8.0 contém duas linhas de matrícula.
python3 moodle-enrol-database-sqli-Abraxas-Labs.py
ou
cd lab
./run.sh
Alvo apenas http://127.0.0.1:19570. Projeto Compose moodle-enrol-database-sqli. A stack é desmontada após a execução.
SUCCESS moodle-enrol-database-sqli how=gadget plugin-off=no-query clean-rows=1 inject-rows=2 sql-concat=yes param-rows=0 extra=yes sink=enrol-db MOODLE-ENROL-DATABASE-SQLI-WITNESS
Copie as consultas parametrizadas do auth_db (MDL-88138). Passe o valor mapeado de curso / usuário como Execute($sql, [$value]). Não concatene db_addslashes em '$value'. Adicione um teste que garanta que uma aspa no idnumber do curso não retorne linhas de outros cursos.
lib.php (db_get_sql, db_addslashes, sync_enrolments)auth_dbGNU Affero GPL v3.0. Veja LICENSE. Apenas lab em loopback. Sem garantia.