Natas Nivel 28 a 29

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

Este nivel combina criptografia simetrica defectuosa con inyeccion SQL: la aplicacion cifra la consulta del usuario con AES-ECB antes de enviarla al servidor, creyendo que eso la protege. La debilidad no esta en la clave sino en el modo de operacion: ECB es maleable bloque a bloque, lo que permite construir un ciphertext arbitrario sin conocer la clave. Este es un entorno de practica legal y autorizado; todas las tecnicas aqui descritas son validas exclusivamente en wargames y sistemas con permiso explicito.

Objetivo

Manipular el parametro cifrado que la aplicacion envia como consulta de busqueda para que, al descifrarse en el servidor, ejecute una query SQL con una condicion siempre verdadera (OR 1=1) y devuelva todas las contrasenas de la base de datos, incluida la de natas29.

Que aprendes

Concepto / HerramientaPara que sirve
AES-ECB (Electronic Codebook)Modo de cifrado donde cada bloque de 16 bytes se cifra de forma independiente y determinista
Chosen-plaintext attackEl atacante controla el texto plano para deducir o fabricar bloques cifrados utiles
ECB block cut-and-pasteReordenar o duplicar bloques cifrados para alterar el texto plano descifrado
URL-decode / Base64-decodeExtraer el ciphertext real del parametro de la URL
Padding PKCS#7Relleno estandar para que el plaintext sea multiplo de 16 bytes
SQL injection (OWASP A03)Inyectar SQL en la query descifrada mediante bloques manipulados
Burp Suite / curlInterceptar, modificar y reenviar peticiones HTTP

Concepto clave

Por que ECB es maleable. En AES-ECB el servidor cifra el bloque N del plaintext con la misma clave siempre, sin depender de los bloques adyacentes (a diferencia de CBC, que encadena bloques con XOR). Esto implica:

  1. Si controlas el plaintext puedes alinear bytes arbitrarios para que caigan solos en un bloque.
  2. El ciphertext resultante de ese bloque es siempre el mismo para el mismo plaintext.
  3. Puedes copiar ese bloque cifrado y pegarlo en otra posicion del ciphertext total.
  4. El servidor descifrara el bloque manipulado obteniendo exactamente el plaintext que pusiste, aunque nunca haya cifrado ese mensaje completo.

Esto se llama ECB block cut-and-paste y es un ataque de chosen-plaintext sin necesidad de conocer la clave.

Plaintext:  [  bloque A (16B)  ][  bloque B (16B)  ][  bloque C (16B)  ]
Cifrado:    [     CT_A         ][     CT_B         ][     CT_C         ]

Si reordenamos: [CT_C][CT_A][CT_B] -> descifra como [C][A][B]

Paso a paso

1. Reconocimiento inicial

Accede con las credenciales de natas28 y observa el formulario de busqueda. Envia una busqueda de prueba (p. ej. test) y captura la URL resultante o la peticion con Burp Suite.

http://natas28.natas.labs.overthewire.org/search.php?query=<valor_base64_urlencode>

El parametro query contiene el ciphertext AES-ECB codificado en Base64 y luego URL-encodeado.

2. Decodificar el ciphertext

# Copia el valor del parametro query desde la URL y decodificalo
QUERY_ENCODED="<pega_aqui_el_valor_urlencode>"
QUERY_B64=$(python3 -c "import urllib.parse; print(urllib.parse.unquote('$QUERY_ENCODED'))")
echo "$QUERY_B64" | base64 -d | xxd | head -20

Esto te muestra los bytes crudos del ciphertext. Anota su longitud: debe ser multiplo de 16.

3. Entender la estructura del plaintext cifrado

El servidor construye algo parecido a:

SELECT * FROM users WHERE query LIKE '%<TU_INPUT>%'

La cadena completa (prefijo + tu input + sufijo) se cifra en bloques de 16 bytes. Tu objetivo es que la parte descifrada contenga ' OR 1=1 -- o similar para romper la logica de la query.

4. Medir el prefijo

Envia inputs de longitud creciente (1, 2, 3, … bytes) y observa cuando el ciphertext crece en 16 bytes. Ese salto indica que has llenado un bloque y has empujado un byte al siguiente. Con eso calculas cuantos bytes de padding necesitas para alinear tu payload al inicio de un nuevo bloque.

for i in $(seq 1 32); do
  INPUT=$(python3 -c "print('A' * $i)")
  # Envia la peticion y mide la longitud del ciphertext resultante
  curl -s -u natas28:<pass_natas28> \
    "http://natas28.natas.labs.overthewire.org/search.php?query=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$INPUT'))")" \
    | grep -o 'query=[^"&]*' | head -1
done

Anota para que longitud de input el ciphertext cambia de tamano: ahi esta el limite de bloque.

5. Aislar un bloque controlado

Una vez que sabes el offset del prefijo, construye un input tal que un bloque de 16 bytes contenga exactamente los bytes de tu payload SQL. Por ejemplo, si el prefijo ocupa 10 bytes, necesitas 6 bytes de relleno mas 16 bytes de payload para que el payload quede solo en el segundo bloque:

[prefijo (10B) + padding (6B)] [payload_sql (16B)] [sufijo...]
     bloque 0 (completo)           bloque 1          bloque 2+

El bloque 1 del ciphertext corresponde entonces a tu payload SQL cifrado.

6. Construir el ciphertext malicioso

Extrae el bloque 1 del ciphertext (bytes 16 a 31) y sustituyelo o concatenalo en el ciphertext de una peticion base donde el sufijo espera exactamente esos bytes.

Nota: el payload SQL exacto (longitud, caracteres de escape, comentario -- o #, espacios) depende de como el servidor construye la query y del motor SQL subyacente. Es probable que necesites experimentar con variantes como ' OR 1=1--, ' OR '1'='1, etc., cada una alineada correctamente a 16 bytes con padding PKCS#7 o espacios. El enfoque tecnico es correcto; el ajuste fino requiere iteracion contra el servidor real.

import base64
import urllib.parse
 
# Ciphertext original (bytes) de una busqueda de referencia
ct_referencia = base64.b64decode("<tu_ciphertext_base64>")
 
# Bloque con tu payload SQL aislado (bytes 16-31 del ciphertext de payload)
ct_payload = base64.b64decode("<ciphertext_del_bloque_payload>")
bloque_payload = ct_payload[16:32]
 
# Reemplaza o inserta el bloque en la posicion adecuada del ciphertext de referencia
ct_nuevo = ct_referencia[:16] + bloque_payload + ct_referencia[32:]
 
# Recodifica para enviarlo
query_param = urllib.parse.quote(base64.b64encode(ct_nuevo).decode())
print(f"http://natas28.natas.labs.overthewire.org/search.php?query={query_param}")

7. Enviar el ciphertext manipulado

curl -s -u natas28:<pass_natas28> \
  "http://natas28.natas.labs.overthewire.org/search.php?query=<ciphertext_manipulado_urlencode>"

Si el bloque esta bien alineado, la respuesta contendra todas las filas de la tabla, incluida la contrasena de natas29: <pass_natas29>.

Por que funciona

AES-ECB delega la seguridad semantica exclusivamente a la clave. Si el atacante puede enviar plaintexts arbitrarios y observar los ciphertexts correspondientes (chosen-plaintext), puede fabricar cualquier mensaje cifrado valido reordenando bloques, sin romper AES ni conocer la clave. El servidor descifra correctamente porque AES-ECB no tiene mecanismo de autenticacion ni integridad (no hay MAC, no hay IV encadenado). La aplicacion asume que “si esta cifrado, no puede haber sido manipulado”, lo cual es falso en ECB.

La inyeccion SQL funciona porque el plaintext descifrado se concatena directamente a la query sin prepared statements ni escape adecuado.

Errores comunes

ErrorCausaSolucion
El ciphertext manipulado da error de paddingLos bloques finales quedan con padding invalido tras el corteAsegurate de que el ciphertext total sigue siendo multiplo de 16 y que el ultimo bloque tiene PKCS#7 valido
La query no devuelve datos extraEl payload SQL no esta alineado al bloque correcto o tiene caracteres incorrectosAjusta el numero de bytes de relleno y prueba variantes del payload (--, #, espacios extra)
El servidor devuelve error 500La query descifrada tiene sintaxis SQL rotaVerifica que los comillas y comentarios SQL del payload cierran correctamente la query original
La URL con el ciphertext se corrompeBytes del ciphertext no estan correctamente URL-encodeadosUsa urllib.parse.quote(base64.b64encode(ct).decode(), safe='') sin caracteres safe

Pasar al siguiente nivel

La contrasena obtenida de la base de datos es la de natas29. Conéctate en:

http://natas29.natas.labs.overthewire.org
Usuario: natas29
Contrasena: <pass_natas29>

Conexiones