Forrás

A feladathoz egy zip fájl és egy socket van megadva.

A zip-ben csupán egy server.py fájl van:

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()

Magyarázat

A socket túloldalán ez a program fut (netcat-el elérhető). A program egy szótárban tárol (users) felhasználókat és azok jelszavait, ahol a kulcs a felhasználónév, az érték pedig egy 2 hosszú tömb a név MD5 hashével és a felhasználó (cleartext) jelszavával. Kettő dolgot tudunk csinálni az alkalmazással: regisztrálni és belépni. Regisztrálásnál ({"option": "register"}) egy felhasználónevet és jelszót kell megadni ({"username": "...", "password": "..."}). A bejelentkezés ({"option": "login"}) ugyan így működik.

Cél

A cél az, hogy az 50. sorban lévő print utasítás lefusson, ami kiírja a flag.txt tartalmát. Ez úgy érhető el, ha van 2 felhasználó akiknek megegyező a user hash értéke és a jelszava, azonban eltérő névvel rendelkeznek. Röviden hash ütközést kell elérni, ami MD5 esetén nem egy nehéz dolog.

Megoldás

Kereshetnénk a már regisztrált felhasználók neveivel ütköző hasheket is, de mivel mi is be tudunk regisztrálni, így egyszerűbb már ismert ütközésekkel megoldani. Egy kis kutatás után tatáltam egy X bejegyzést, ahol megemlítenek 2 egyező MD5 hasht. Regisztrálunk két felhasználót a két különböző, ám azonos MD5 hashű felhasználónévvel. A jeszló értéke lényegtelen, de egyezniük kell. Ezután bejelentkezünk a másodjára regisztrált felhasználóval, ezzel a kívánt útra terelve a végrehajtást.

{"option": "register"}
{"username": "TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak", "password": "pws"}
{"option": "register"}
{"username": "TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak", "password": "pws"}
{"option": "login"}
{"username": "TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak", "password": "pws"}