Saltar al contenido

Investigación

Inyección SQL sin autenticar en Metabase

Todos los proyectos

ActivoDockerPostgreSQLBurp SuiteAnálisis de parches

Metabase publicó un aviso de puntuación máxima sin explicar el vector, solo con una firma para buscar en registros. Dos empresas conocidas ya habían reconocido ataques por el mismo fallo. Monté un laboratorio con tres contenedores, dos versiones vulnerables y una parcheada, y reconstruí el mecanismo comparando peticiones idénticas contra las dos: la vulnerable ejecutaba una consulta que la parcheada no, con un valor que yo no había puesto en ninguna parte.

Por qué no está el código

El laboratorio y la prueba de concepto no se publican. El fallo está parcheado, pero sigue habiendo miles de instancias expuestas sin actualizar, así que aquí se cuenta el mecanismo y no cómo se explota.

La cadena del fallo

Los tres a la vez dan lectura de la base de datos sin una sola credencial.

Uso responsableGHSA-vwf4-m7j8-wcjf

Este análisis se publica sobre una vulnerabilidad ya divulgada y corregida por su fabricante, y describe el mecanismo del fallo sin entregar nada ejecutable. No hay prueba de concepto, ni pasos reproducibles, ni material del laboratorio. Si administras un sistema afectado, el enlace al aviso oficial lleva a la versión que lo corrige.

Aviso oficial de Metabase

El punto de partida

Metabase publicó un aviso de puntuación máxima y no explicó cómo se explotaba. Dos frases y una firma para buscar en registros. Framework y Tally, dos empresas conocidas, ya habían reconocido que las habían atacado por ese mismo fallo. Y en ese momento no había ninguna prueba de concepto pública.

Si administras eso, sabes que estás en peligro y no tienes más que una firma para buscar. Me puse un fin de semana a reconstruir el mecanismo con lo que sí era público.

El laboratorio

Tres contenedores. Dos con versiones del rango afectado y uno con la versión parcheada, cada uno con su base de datos registrando todas las consultas que recibía. Enviar la misma petición a los tres y mirar en qué se diferenciaban los registros.

Dos versiones vulnerables y no una, a propósito. Si el comportamiento aparece en dos versiones distintas del rango, es el fallo. Si aparece en una sola, puede ser una peculiaridad de esa compilación y llevas medio día persiguiendo un fantasma.

El error del primer día

Perdí la tarde del primer día entero. Leí mal el rango de versiones afectadas y monté el laboratorio con una versión que ya estaba corregida, así que las peticiones que debían fallar no fallaban y las que debían diferenciarse salían idénticas. Estuve horas convencido de que el aviso exageraba o de que el vector necesitaba algo que yo no tenía.

Cuando bajé a la versión correcta, el fallo apareció en el primer intento. La instancia vulnerable ejecutaba una consulta que la parcheada no ejecutaba, y esa consulta contenía un valor que yo no había puesto en ninguna parte de la petición. A partir de ahí el trabajo dejó de ser adivinar.

El mecanismo

Son tres piezas encadenadas, y ninguna de las tres es un fallo grave por sí sola.

La primera está en la aplicación: un punto de entrada que no exige autenticación acepta claves adicionales en el cuerpo de la petición y las pasa hacia dentro sin filtrarlas. La segunda está en una biblioteca de construcción de consultas, que respeta sus propias vías de escape aunque el valor que las activa venga de fuera. Y la tercera es una opción por defecto del motor de base de datos, que permite ejecutar varias sentencias en un solo mensaje.

Con las tres alineadas, una única petición sin autenticar termina suplantando al administrador. Eso explica la puntuación máxima y también por qué el aviso no daba detalles: por separado cada pieza parece inofensiva, y la cadena entera se reproduce en un minuto cuando la has visto.

Lo que no publico es la petición, ni la cadena hasta la ejecución de código, ni la configuración del laboratorio. El fallo está parcheado desde hace semanas, pero según Shodan sigue habiendo más de cinco mil instancias expuestas, y no todas están al día.

El método

Metabase había retirado el código fuente de las versiones más recientes, así que comparar el antes y el después no era una opción directa. Descargué cuatro versiones y las descompilé.

Ese trabajo lo repartí. Hice un mapa de dónde podía estar el fallo y luego orquesté varios modelos de lenguaje en paralelo, con un presupuesto de quince euros. Dos descompilaban y buscaban diferencias entre versiones. Otros dos formulaban consultas contra la base de datos. Y yo revisaba registros y descartaba hipótesis. No es que los modelos encontraran el fallo. Es que yo pude mirar cuatro sitios a la vez en lugar de uno.

El recurso que hizo falta

Esto lo hizo alguien con conocimientos base, desde su casa, en dos días y con quince euros. No soy investigador y no llevo años analizando binarios.

Si con esos recursos sale, queda la pregunta de qué está haciendo quien tiene tiempo, dinero y un motivo. Y no sabría decir si el método funciona dos veces o esta salió bien por suerte.