Resumen
Al abrir la definición de una tabla, MariaDB lee metadatos desde un fichero .frm. Entre esos datos figura, por cada parte de un índice, el número de campo al que apunta (key_part->fieldnr). El servidor usaba ese valor, controlado por quien construye el .frm, como índice del array de campos share->field[] comprobando únicamente que no fuera cero. Nunca verificaba el límite superior, es decir, que fieldnr fuera menor o igual que share->fields.
La consecuencia es una lectura fuera de límites dentro de la misma reserva de memoria. Como share->field y la zona comment_pos se ubican en la misma asignación (multi_alloc_root), un fieldnr fuera de rango puede caer en una posición que solapa datos que el propio atacante colocó en comment_pos. Ese valor se interpreta luego como un puntero Field* legítimo.
El código afectado toma ese puntero y realiza una llamada a método virtual de C++ a través de él:
// mariadb-10.4.18/sql/table.cc:2705
// mariadb-11.8.8/sql/table.cc:3162
// mariadb-12.3.2/sql/table.cc:3201
// mariadb-13.1.0/sql/table.cc:3209
if (!key_part->fieldnr)
goto err;
field = key_part->field = share->field[key_part->fieldnr - 1];
// mariadb-11.8.8/sql/table.cc:3166
// mariadb-12.3.2/sql/table.cc:3205
// mariadb-13.1.0/sql/table.cc:3213
if (Charset::collation_changed_order(share->mysql_version, field->charset()->number))
// mariadb-10.4.18/sql/table.cc:2709
key_part->type = field->key_type();
Al controlar los bytes a los que apunta ese Field*, el atacante puede suministrar un objeto C++ falso con una vtable falsa. La llamada virtual desreferencia esa vtable manipulada y desvía el flujo de ejecución. El investigador indica que en su entorno de pruebas esto se aprovechó para lograr ejecución de código arbitrario en el contexto de seguridad del proceso del servidor MariaDB.
Requisitos y escenario de ataque
El reporte no publica un PoC ejecutable ni el contenido concreto del .frm; describe las condiciones bajo las que el investigador reprodujo el problema:
- El atacante dispone de una sesión SQL autenticada.
- La cuenta SQL tiene el privilegio global
FILE. secure_file_privestá sin definir o vacío, permitiendo operaciones de fichero en rutas accesibles para el proceso del servidor.- La cuenta del sistema operativo bajo la que corre MariaDB puede crear ficheros dentro del directorio de datos de la base de datos.
- El atacante consigue que MariaDB cargue los metadatos
.frmmanipulados.
El fichero .frm manipulado se entrega a través de la interfaz SQL usando el privilegio FILE, sin necesidad de un shell previo en el sistema ni de acceso directo al sistema de ficheros. En el entorno probado, la cuenta del sistema operativo de MariaDB podía escribir en el directorio de datos, pero no en el directorio de plugins ni en otros directorios de ejecutables o librerías.
El .frm se construye de modo que un key_part->fieldnr fuera de rango apunte, dentro de la misma asignación de memoria, a la zona comment_pos, cuyos bytes también controla el atacante. Cuando MariaDB abre esa definición de tabla, interpreta esos bytes como un Field* y ejecuta la llamada a método virtual mostrada arriba.
Impacto
Un atacante autenticado con el privilegio FILE de MariaDB convierte la capacidad de crear un fichero en el directorio de datos en ejecución de código nativo dentro del proceso mariadbd. Esto excede lo que el privilegio FILE debería permitir: ese privilegio autoriza ciertas operaciones de fichero, pero no ejecutar código nativo ni controlar el despacho de funciones virtuales de C++. Además, SELECT ... INTO DUMPFILE/OUTFILE no puede sobrescribir un fichero existente, así que el atacante se limita a crear un fichero nuevo en una ruta escribible por el servidor; la vulnerabilidad es lo que cruza esa frontera. Si el servicio SQL es accesible por red, se trata de una ejecución remota de código autenticada.
Según el reporte, la explotación con éxito permite:
- Realizar la lectura fuera de límites en el array de punteros
share->field[]. - Sustituir un
Field*legítimo por un puntero controlado por el atacante. - Suministrar un objeto C++ y una vtable falsos.
- Controlar el destino de una llamada a función virtual de C++.
- Ejecutar código arbitrario con los privilegios del sistema operativo del proceso del servidor.
A partir de ahí, el atacante podría leer o modificar datos accesibles para la cuenta del sistema de MariaDB, saltarse las comprobaciones de autorización a nivel SQL operando dentro del proceso, modificar o borrar ficheros escribibles por esa cuenta, acceder a credenciales, claves, configuración o memoria del proceso, establecer conexiones de red salientes desde el servidor, o detener y corromper el proceso de la base de datos. El reporte matiza que la vulnerabilidad no otorga privilegios de root por sí sola: el impacto final en el sistema queda acotado por los privilegios de la cuenta mariadbd y por controles activos como SELinux, AppArmor, contenedores o el aislamiento de systemd.
Versiones afectadas
El fallo se reprodujo hasta ejecución de código en MariaDB 10.4.18, 11.8.8, 12.3.2 y 13.1.0 Preview. El investigador espera que la mayoría de versiones estén afectadas mientras no exista control sobre el límite superior de fieldnr, aunque no todas se probaron por completo.
Remediación
El reporte no cita el parche concreto. La causa raíz que describe es la ausencia de comprobación del límite superior de fieldnr antes de usarlo como índice de share->field[], ya que el código solo verificaba que no fuera cero; lo que falta es validar que fieldnr esté dentro del rango válido (mayor que cero y no superior a share->fields) antes de indexar el array. El reporte figura como resuelto en el programa de MariaDB.