Tym razem opiszę zadanie PW Crack 3 z działu General Skills picoCTF.
Do zadania zostały dołączone trzy pliki level3.py, level3.hash.bin, level3.flag.txt.enc.
- mport hashlib
- ### THIS FUNCTION WILL NOT HELP YOU FIND THE FLAG --LT ########################
- def str_xor(secret, key):
- #extend key to secret length
- new_key = key
- i = 0
- while len(new_key) < len(secret):
- new_key = new_key + key[i]
- i = (i + 1) % len(key)
- return "".join([chr(ord(secret_c) ^ ord(new_key_c)) for (secret_c,new_key_c) in zip(secret,new_key)])
- ###############################################################################
- flag_enc = open('level3.flag.txt.enc', 'rb').read()
- correct_pw_hash = open('level3.hash.bin', 'rb').read()
- def hash_pw(pw_str):
- pw_bytes = bytearray()
- pw_bytes.extend(pw_str.encode())
- m = hashlib.md5()
- m.update(pw_bytes)
- return m.digest()
- def level_3_pw_check():
- user_pw = input("Please enter correct password for flag: ")
- user_pw_hash = hash_pw(user_pw)
- if( user_pw_hash == correct_pw_hash ):
- print("Welcome back... your flag, user:")
- decryption = str_xor(flag_enc.decode(), user_pw)
- print(decryption)
- return
- print("That password is incorrect")
- level_3_pw_check()
- # The strings below are 7 possibilities for the correct password.
- # (Only 1 is correct)
- pos_pw_list = ["6997", "3ac8", "f0ac", "4b17", "ec27", "4e66", "865e"]
Zadaniem programu jest sprawdzenie hasła i odszyfrowanie flagi, jeśli będzie ono poprawne.
Jako funkcja szyfrująca wykorzystano str_xor. Jej zadaniem jest szyfrowanie bądź deszyfrowanie przy użyciu operacji XOR. Plik flag_enc przechowuje zaszyfrowaną flagę, correct_pw_hash przechowuje hash hasła MD5.
MD5 jest to funkcja hashująca. Wynikiem takiej funkcji będzie 128 bitowy hash (16 bajtów). Bez względu na długość hasła, hash zawsze będzie miał zawsze 16 bajtów oraz jak można się domyślić dla tego samego tekstu zawsze dostaniemy ten sam hash. Nie jest to oczywiście zbyt dobre rozwiązanie do przechowywania haseł. Jest on podatny na brute force przez to, że jest szybki. Z powodu ograniczonej ilości danych w hashu, mogą występować kolizje, czyli ten sam hash dla różnych danych wejściowych.
Wobec tego, że mamy podaną listę haseł, najprostszą opcją będzie policzenie HASH dla każdego z nich. Można to wykonać w Pythonie następującym programem:
- import hashlib
- correct_pw_hash = open('level3.hash.bin', 'rb').read()
- #Lista haseł
- pos_pw_list = ["6997", "3ac8", "f0ac", "4b17", "ec27", "4e66", "865e"]
- #Przechodzi po każdym z haseł i liczy hash
- for pw in pos_pw_list:
- md5 = hashlib.md5(pw.encode()).digest()
- if md5 == correct_pw_hash:
- print("Poprawne hasło:", pw)
- break
W odpowiedzi dostaniemy konkretne hasło z pasującym hash'em:
Drugim sposobem jest skopiowanie hash'a z pliku i użycie jednego z serwisów online, które przechowują listę hash wraz z pasującymi do nich tekstami:
Dokładnie takie same techniki można zastosować dla pozostałych zadań z tej serii czyli PW Crack 4 oraz PW Crack 5. We wszystkich zadaniach wykorzystywane jest MD5.