Moodle 5.2.3 - Alta - Remota - SQLi - enrol_database concatena el idnumber del curso en SQL
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · moodle-enrol-database-sqli
Moodle LMS 5.2.3 - Moodle
Clase: SQLi Alcance: Remoto
enrol_database::db_get_sql todavía escapa con barras y concatena. MSA-26-0005 / MDL-88138 parametrizó auth_db como Execute($sql, [$value]). Este plugin no copió esa forma. Valores por defecto en la configuración: dbsybasequoting=0, localcoursefield=idnumber. El sink es la base de datos de matriculación externa. El $DB del núcleo de Moodle no está en esta ruta.
Un profesor con permisos de edición en un sitio con enrol_database habilitado establece el idnumber del curso. Cron lo interpola. Filas adicionales regresan desde la base de datos de matriculación.
| ID | sin CVE todavía |
| 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 |
| Producto | Moodle |
| Afectado | etiqueta 5.2.3 v5.2.3 (344232c15336c71b80f9aca8359ce0e0a9f3d116). El plugin enrol_database debe estar activado. |
| Autenticación | profesor con permisos de edición (idnumber del curso, mapa local por defecto) |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | solo 127.0.0.1 |
Un profesor con permisos de edición en un sitio con enrol_database habilitado inyecta SQL en la base de datos de matriculación externa estableciendo el idnumber del curso. Luego cron sync_enrolments ejecuta ese SQL.
| Privilegio | Método / sink | Reconocimiento / integridad / disponibilidad | Probado en laboratorio o inferido |
|---|---|---|---|
| Insertar un fragmento SQL en el SELECT de matriculación externa | Cron sync_enrolments -> db_get_sql($table, array($coursefield=>$course->mapping), ...) -> $extdb->Execute($sql) | Integridad de la cadena de consulta | Probado en laboratorio. El SQL concatenado es WHERE courseid = 'LABCOURSE\'' OR 1=1 -- ' |
| Leer filas de matriculación de otros cursos en esa base de datos externa | El mismo SELECT después de cerrar la cadena | Reconocimiento | Probado en laboratorio. Limpio: 1 fila teacher-local. Inyectado: 2 filas incluyendo MOODLE-ENROL-DATABASE-SQLI-WITNESS |
| Omitir la consulta cuando el plugin está desactivado | El mismo gadget, plugin=off | n/a | Probado en laboratorio cerrado. executed=false, SQL vacío, 0 filas |
| Mantener el mismo payload como parámetro vinculado | Residuo de auth_db de MSA-26-0005: Execute($sql, [$value]) | n/a | Probado en laboratorio cerrado. style=param devolvió 0 filas, el SQL contiene ? |
| Matricular / desmatricular / asignar rol a usuarios de Moodle nombrados en filas adicionales | Después de que cron aplica requestedenrols | Integridad de las matriculaciones | Inferido. El laboratorio se detiene en las filas adicionales en la base de datos de matriculación |
| FILE / INTO OUTFILE como el usuario de la base de datos de matriculación | El mismo sink si esa cuenta tiene FILE | Integridad / disponibilidad de ese host de base de datos | Inferido. No demostrado. No es LPE del SO |
| Ruta controlada por el estudiante | Solo si el administrador mapea localuserfield=email (o similar) | n/a | Inferido. La ruta por defecto es el idnumber del profesor |
Cerrado en este residuo: $DB del núcleo de Moodle; plugin deshabilitado (sin consulta); acceso no autenticado; shell del SO; consultas apiladas (este gadget mysqli es de una sola sentencia). Moodle por defecto sin enrol_database no es este bug.
Mismos residuos de la versión fijada: Blackboard img file read, grades feedback IDOR, hidden grade items.
Fijé moodle/moodle v5.2.3 después de MSA-26-0042/0043. MSA-26-0005 cerró auth_db con un placeholder. Abrí enrol_database porque habla con el mismo tipo de base de datos externa y todavía tiene db_addslashes.
dbsybasequoting es 0 por defecto, así que solo se duplica '. Una barra invertida seguida de comilla en el idnumber cierra la cadena de MySQL.
Caminos equivocados ya registrados: tratar el $DB del núcleo de Moodle como el sink (no lo es); llamar a esto LPE del SO porque FILE existe como privilegio de MySQL (no demostrado, no es este residuo); el email del estudiante como el mapa por defecto (el administrador tiene que cambiar localuserfield). Una reverse shell. Teatro.
Gadget fiel de los constructores de la versión fijada, no una aplicación PHP completa de Moodle. php:8.3-cli sirve el db_get_sql / db_addslashes / db_encode copiados. mysql:8.0 contiene dos filas de matriculación.
python3 moodle-enrol-database-sqli-Abraxas-Labs.py
o
cd lab
./run.sh
Objetivo solo http://127.0.0.1:19570. Proyecto de Compose moodle-enrol-database-sqli. El stack se desmonta después de la ejecución.
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
Copiar las consultas parametrizadas de auth_db (MDL-88138). Pasar el valor mapeado del curso / usuario como Execute($sql, [$value]). No concatenar db_addslashes dentro de '$value'. Agregar una prueba de que una comilla en el idnumber del curso no devuelve filas de otros cursos.
lib.php (db_get_sql, db_addslashes, sync_enrolments)auth_dbGNU Affero GPL v3.0. Ver LICENSE. Solo laboratorio en loopback. Sin garantía.