NovaHacking
  • Whoami
  • Artículos
    • Panamá Papers
    • Tratamiento para la TTY
    • Introducción a la Ciberseguridad
    • Introducción al Buffer Overflow
    • Introducción al Pivoting
    • IDS - IPS (Suricata)
    • Colisión de Hash
    • RSA Cracker
  • Herramientas
    • Explotación
      • Hydra
      • pwncat-cs
    • Reconocimiento
      • Nmap
      • Arp scan
  • CTF
    • Dockerlabs
      • Amor
      • BreakMySSH
      • DockHackLab
      • FirstHacking
      • sjd
      • WhereIsMyWebShell
      • Dark
      • Queuemedic
      • Buffered
      • Pn
      • Canario
      • Domain
      • HereBash
  • Linux
    • 🐧Inicio Linux
Powered by GitBook
On this page
  • 🔓 Rompiendo la Ilusión de Seguridad con MD5
  • 🧠 ¿Qué es una función hash?
  • 🧨 El problema: Las colisiones de hash
  • ¿Qué significa esto?
  • 🧪 Ejemplo práctico: Challenge de HackTheBox (alphascii_clashing)
  • 🎭 Ataque por colisión de usuario
  • Solución del Challenge
  • 🔍 ¿Y cómo se consigue una colisión?
  • 🧯 ¿Cómo prevenir esto?
  • ✅ Buenas prácticas:
  1. Artículos

Colisión de Hash

TAG -> Artículos

🔓 Rompiendo la Ilusión de Seguridad con MD5

"Usar funciones hash como MD5 para almacenar información sensible puede parecer seguro, pero en realidad es como esconder una llave bajo el tapete de la entrada: fácil de encontrar si sabes dónde buscar."

🧠 ¿Qué es una función hash?

Una función hash es un algoritmo que toma una entrada (como una contraseña o nombre de usuario) y la transforma en una cadena de longitud fija, normalmente hexadecimal. Esta salida se llama hash. Las funciones hash se usan comúnmente para verificar la integridad de archivos, firmar digitalmente datos, y muy importante proteger contraseñas.

Por ejemplo:

from hashlib import md5

print(md5(b'HTBUser132').hexdigest())
# Salida: 'cdf16ba040ec2b7ecf2d1cda3289bba9'

🧨 El problema: Las colisiones de hash

Una colisión de hash ocurre cuando dos entradas diferentes generan el mismo hash. Si una función hash permite esto con facilidad, entonces deja de ser segura. Los algoritmos modernos (como SHA-256) hacen que encontrar una colisión sea extremadamente difícil, pero algoritmos antiguos como MD5 o SHA-1 ya están completamente rotos.

¿Qué significa esto?

Que un atacante puede generar una segunda entrada maliciosa que tenga el mismo hash que una original válida. Esto es devastador cuando se usa una función hash para verificar identidad, como veremos a continuación.


🧪 Ejemplo práctico: Challenge de HackTheBox (alphascii_clashing)

Aquí tenemos un ejemplo de una aplicación sencilla de login y registro escrita en Python. Esta aplicación almacena los usuarios como:

'username': [md5(username).hexdigest(), password]

⚠️ ¡Fíjate bien! No se hace hashing a la contraseña, solo al nombre de usuario. Esto ya es un error de seguridad, pero lo más grave viene con el uso de MD5.

Código completo

from hashlib import md5
import json

'''
Data format:
{
    username: [md5(username).hexdigest(), password],
    .
    .
    .
}
'''
users = {
    'HTBUser132' : [md5(b'HTBUser132').hexdigest(), 'secure123!'],
    'JohnMarcus' : [md5(b'JohnMarcus').hexdigest(), '0123456789']
}

def get_option():
    return input('''
    Welcome to my login application scaredy cat ! I am using MD5 to save the passwords in the database.
                          I am more than certain that this is secure.                       
                                   You can't prove me wrong!          
    
    [1] Login
    [2] Register
    [3] Exit

    Option (json format) :: ''')


def main():
    while True:
        option = json.loads(get_option())

        if 'option' not in option:
            print('[-] please, enter a valid option!')
            continue

        option = option['option']
        if option == 'login':
            creds = json.loads(input('enter credentials (json format) :: '))

            usr, pwd = creds['username'], creds['password']
            usr_hash = md5(usr.encode()).hexdigest()
            for db_user, v in users.items():
                if [usr_hash, pwd] == v:
                    if usr == db_user:
                        print(f'[+] welcome, {usr} 🤖!')
                    else:
                        print(f"[+] what?! this was unexpected. shutting down the system :: {open('flag.txt').read()} 👽")
                        exit()
                    break
            else:
                print('[-] invalid username and/or password!')
        
        elif option == 'register':
            creds = json.loads(input('enter credentials (json format) :: '))

            usr, pwd = creds['username'], creds['password']
            if usr.isalnum() and pwd.isalnum():
                usr_hash = md5(usr.encode()).hexdigest()
                if usr not in users.keys():
                    users[usr] = [md5(usr.encode()).hexdigest(), pwd]
                else:
                    print('[-] this user already exists!')
            else:
                print('[-] your credentials must contain only ascii letters and digits.')

        elif option == 'exit':
            print('byeee.')
            break

if __name__ == '__main__':
    main()

Veamos cómo funciona la autenticación:

  1. El usuario ingresa su nombre y contraseña.

  2. El sistema compara el hash MD5 del nombre de usuario y la contraseña con los datos en la base.

  3. Si coinciden, y el nombre de usuario original también coincide exactamente, se inicia la sesión.

Pero… ¿y si alguien encuentra un nombre de usuario distinto que tenga el mismo hash MD5 que otro ya registrado? Eso es una colisión de hash.

Objetivo: obtener la flag.txt


🎭 Ataque por colisión de usuario

Hay cadenas ya bastante conocidas donde sabemos que 2 textos dan el mismo hash, aunque se cambie una letra, primero veamos como puede cambiar un hash si cambiamos una letra del texto original:

Como podemos ver, el hash es completamente diferente para user1 y para user2, pero como mencione anteriormente, hay textos que dan el mismo hash:

En el primer texto teníamos una A luego en el segundo texto se cambio a E, pero aun así dieron el mismo hash.

# Texto 1				  |
						  V
md5('TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak') = faad49866e9498fc1719f5289e7a0269

# Texto 2				  |
						  V
md5('TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak') = faad49866e9498fc1719f5289e7a0269

Ahora imaginemos que un atacante genera otro nombre de usuario, por ejemplo: TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak y una contraseña arbitraria, luego el atacante podría intente hacer login usando el nombre de usuario donde se cambia una letra, pasaría esta parte del código:

option = option['option']
if option == 'login':
    creds = json.loads(input('enter credentials (json format) :: '))
    
    usr, pwd = creds['username'], creds['password']
    # Se obtiene el hash md5 del usuario ingresado
    usr_hash = md5(usr.encode()).hexdigest()
    # Se recorre la base de datos
    for db_user, v in users.items():
        # El hash y la contraseña existen en la base de datos
        if [usr_hash, pwd] == v:
	        # El usuario no esta en la base de datos
            if usr == db_user:
                print(f'[+] welcome, {usr} 🤖!')
            else:
	            # ¡colisión! Mismo hash y misma contraseña pero el usuario no existe
                print(f"[+] what?! this was unexpected. shutting down the system :: {open('flag.txt').read()} 👽")
                exit()
            break
    else:
        print('[-] invalid username and/or password!')

Aquí está la bomba lógica:

  • El hash del nombre de usuario coincide.

  • La contraseña coincide.

  • Pero el nombre de usuario es diferente.

  • Esto activa el mensaje secreto del sistema y muestra el contenido de flag.txt.

Solución del Challenge

🔍 ¿Y cómo se consigue una colisión?

Generar colisiones para MD5 no es un misterio desde hace muchos años. De hecho, en 2004 ya se publicaron métodos efectivos para hacerlo. Desde entonces, se han desarrollado herramientas automáticas como:

  • Herramientas en línea que te permiten subir archivos diferentes con el mismo hash MD5

También existen ejemplos donde se crean dos archivos PDF distintos en contenido y forma pero con el mismo hash MD5. Esto puede usarse para engañar a verificadores de integridad, firmar digitalmente documentos falsos, o incluso ejecutar malware.

🧯 ¿Cómo prevenir esto?

La mejor solución es nunca usar MD5 para nada relacionado con seguridad. Algunas recomendaciones modernas:

✅ Buenas prácticas:

  1. Usa funciones hash seguras:

    • SHA-256 (aunque se recomienda SHA-3 si está disponible)

    • Para contraseñas: utiliza funciones especialmente diseñadas como bcrypt, scrypt o Argon2

  2. Siempre hashea las contraseñas, no los usuarios Almacena el hash de la contraseña, no el nombre de usuario. El nombre se puede mantener en texto plano.

  3. Usa un 'salt' por usuario Para evitar ataques por diccionario o rainbow tables, añade una cadena aleatoria única (salt) al hash.

  4. Valida la entrada y evita comparar directamente hashes con listas Asegúrate de que los datos sean consistentes y considera usar técnicas como verificación con claves HMAC.

El ejemplo que vimos muestra una lección clara: confiar ciegamente en funciones hash sin entender sus limitaciones puede exponer tu sistema a ataques críticos. En seguridad, la ilusión de protección es más peligrosa que la falta de ella.

Una colisión de hash, como hemos visto con MD5, puede usarse para burlar autenticaciones, firmar datos falsos, y manipular sistemas que dependen de hashes para integridad.

Así que la próxima vez que alguien diga "esto está protegido con MD5, no te preocupes", ya sabes qué responder.

PreviousIDS - IPS (Suricata)NextRSA Cracker

Last updated 1 month ago

HashClash