alphascii clashing
4 minutos de lectura
Se nos proporciona el código fuente del servidor en Python:
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()
Análisis del código fuente
Básicamente implementa una base de datos para almacenar credenciales de usuarios. Usan el nombre de usuario como clave y el valor es una tupla que contiene el hash MD5 del nombre de usuario, y la contraseña en texto claro:
'''
Data format:
{
username: [md5(username).hexdigest(), password],
.
.
.
}
'''
users = {
'HTBUser132' : [md5(b'HTBUser132').hexdigest(), 'secure123!'],
'JohnMarcus' : [md5(b'JohnMarcus').hexdigest(), '0123456789']
}
Opción de inicio de sesión
La flag aparece en la opción de inicio de sesión:
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) :: '))
Para obtener la flag, necesitamos encontrar un nombre de usuario cuyo hash MD5 colisione con un nombre de usuario diferente que ya exista en la base de datos. En otras palabras, necesitamos $u_1$ y $u_2$ tales que $u_1 \ne u_2$ y $\mathrm{MD5}(u_1) = \mathrm{MD5}(u_2)$.
Opción de registro
Para esto, necesitamos registrar al menos un nuevo usuario:
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.')
El requisito aquí es que el nombre de usuario y la contraseña sean strings alfanuméricas, como es de esperar para este tipo de campos.
Solución
Entonces, el objetivo es encontrar dos strings alfanuméricas diferentes cuyos hash MD5 sean iguales. Una búsqueda rápida en Internet muestra un mensaje de X (Twitter) que contiene justo lo que necesitamos:
$ python3 -q
>>> from hashlib import md5
>>>
>>> u1 = b'TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak'
>>> u2 = b'TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak'
>>>
>>> u1 != u2 and md5(u1).digest() == md5(u2).digest()
True
Flag
Por lo tanto, solo necesitamos registrar uno de los nombres de usuario y usar el segundo para obtener la flag:
$ nc 94.237.53.112 51607
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) :: {"option":"register"}
enter credentials (json format) :: {"username":"TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak","password":"x"}
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) :: {"option":"login"}
enter credentials (json format) :: {"username":"TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak","password":"x"}
[+] what?! this was unexpected. shutting down the system :: HTB{f33ls_g00d_f1nd1ng_4lph4num3r1c_c0ll1s10ns_fr0m_tw1tt3r_p0sts} 👽