Introduction to HackTheBox alphascii clashing
Designed for beginners, HackTheBox Alphascii Clashing is a very-easy-level challenge that offers a straightforward introduction to encryption reversal and file handling techniques.
HackTheBox Alphascii Clashing Description
The Frontier Board’s grip on the stars relies on a digital relic thought to be flawless. But in the depths of the void, anomalies can ripple through even the most secure systems. Do you have what it takes to expose the cracks in their so-called perfection?
Walkthrough
We are given the below python source code:
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()
Breakdown of the code:
Purpose:
The code implements a simple login application with a registration option. It uses JSON-formatted input to receive both the menu option and the user credentials.
User Data Format:
The users are stored in a dictionary where each key is a username and the associated value is a list containing two elements:
- The MD5 hash of the username
- The plaintext password
'HTBUser132' : [md5(b'HTBUser132').hexdigest(), 'secure123!']
Input Handling:
get_option()
Function:
Prompts the user to choose an action (login, register, or exit) in JSON format.- JSON Parsing:
Both the option and the credentials are expected as JSON strings (e.g.,{"option": "login"}
or{"username": "user", "password": "pass"}
).
Main Loop (in main()
):
The program continuously prompts the user to select an option:
- Login:
- The user inputs their credentials as JSON.
- The code computes
usr_hash
by hashing the provided username using MD5. - It then iterates over the
users
dictionary and compares the list[usr_hash, password]
with the stored value. - Crucial Logic:
- If a match is found and the input username exactly matches the dictionary key, a welcome message is printed.
- Vulnerability: If the MD5 hash and password match but the input username does not equal the key (i.e., it is a different string that produces the same MD5 hash as the key), the code prints the contents of
flag.txt
and exits. This is a hidden “backdoor” that hinges on MD5 collision.
- Register:
- The user inputs credentials in JSON format.
- The code enforces that both the username and password contain only alphanumeric characters (using
isalnum()
). - It then registers the user by storing the MD5 hash of the username along with the plaintext password.
- No check is performed to prevent different usernames with the same MD5 hash, which could later be exploited during login.
- Exit:
Simply breaks out of the loop and ends the program.
Code Seurity Analysis
- Insecure Use of MD5:
- MD5 is Weak: MD5 is a well-known cryptographic hash function that is vulnerable to collision attacks. The code uses MD5 on the username rather than on the password.
- Collision Attack Opportunity:
Since MD5 is applied only to the username, an attacker could potentially craft a different username (with different characters) that results in the same MD5 hash as an existing user.
- Flawed Authentication Logic:
- Comparison Mechanism:
During login, the application compares the list[md5(username).hexdigest(), password]
to the stored value. - Backdoor Trigger:
If an attacker manages to supply a username that has the same MD5 hash as a legitimate user (i.e., a collision), the check[usr_hash, pwd] == stored_value
might pass even if the string itself is different.- If
usr != db_user
, the code unexpectedly prints a flag (read fromflag.txt
) and exits. This behavior represents a hidden vulnerability where MD5 collisions directly lead to unauthorized access or leakage of sensitive information.
- If
- Comparison Mechanism:
- Plaintext Password Storage:
- Passwords are stored in plaintext alongside the MD5 hash of the username. This means that if the users dictionary is ever compromised, the passwords are immediately exposed.
- Input Format Rigidness:
- The program expects all user input (for both options and credentials) in JSON format. Incorrect formatting or invalid JSON will lead to runtime errors.
- Registration Limitations:
- The
isalnum()
check limits the username and password to ASCII letters and digits. While this might be intended to prevent injection attacks, it also restricts the set of potential usernames, which might make a collision attack slightly more challenging—but it does not eliminate the possibility.
- The
Solution
The goal is to identify two distinct alphanumeric strings that produce the same MD5 hash. A quick online search reveals a Twitter (X) post that provides exactly what we’re looking for.
From there, we just need to register one of the usernames and use the other to obtain the flag.
$ nc 83.136.254.140 45070
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} 👽
Contents
Source code analysis
Login option
Register option
Solution
Flag
🍺
Conclusion
This writeup provides an in-depth analysis of exploiting MD5 hash collisions within the context of the HackTheBox challenge “alphascii clashing” It demonstrates how vulnerabilities in the MD5 hashing algorithm can be leveraged to create two different files with identical hash values, a technique that can be exploited in various security scenarios.