Cracker password SHA256 - v2 con concorrenza

Nov 17 2020

Ho aggiornato il mio codice precedente con i suggerimenti. Ho anche implementato la concorrenza per accelerare i risultati.

Sarei interessato a commenti su un uso più efficiente di concorrenza / elaborazione parallela / hyper-threading

Grazie

import concurrent.futures
import hashlib
import time


def make_next_guess(guess):
    carry = 0
    next_guess = guess
    for i, char in enumerate(next_guess):
        if ord(char) >= ord("z"):
            carry = 1
            next_guess[i] = "!"
        elif ord(char) < ord("z"):
            next_guess[i] = chr(ord(char) + 1)
            carry = 0
        if carry == 0: break
    if carry:
        next_guess.append("!")
    return next_guess


def hash_password(pwrd):
    # Generates hash of original password
    try:
        pwrd = pwrd.encode("UTF-8")
        password = hashlib.sha256()
        password.update(pwrd)
        return password.hexdigest()
    except:
        pass


def find_password(secure_password, guess, integer):
    list_cracked = []
    # Brute force to find original password
    for _ in range(90 ** integer):  # password maximum length 14 and there are 58 characters that can be used
        return_password = "".join(guess)
        if hash_password(return_password) in secure_password:
            # print(f"Another password has been cracked: '{return_password}'")
            list_cracked.append(return_password)
        guess = make_next_guess(guess)
    return f"Finished cracking all passwords of length {integer}", list_cracked, integer


def rainbow_table_check(secure_password):
    global hash
    list_cracked = []
    for password in open("Rainbow.txt", "r", encoding="utf8"):
        try:
            password = password.strip()
            hash = hash_password(password)
        except:
            pass
        if hash in secure_password:
            # print(f"Another password has been cracked: {password}")
            list_cracked.append(password)
    return "Rainbow attack complete - passwords: ", list_cracked, "Rainbow"


def dic_attack(secure_password):
    list_cracked = []
    for password in open("Dic.txt", "r", encoding="utf8"):
        password = password.strip()
        lst = [password.lower(), password.upper(), password.title()]
        for password in lst:
            hash = hash_password(password)
            if hash in secure_password:
                # print(f"Another password has been cracked: {password}")
                list_cracked.append(password)
    return "Dictionary attack complete - passwords: ", list_cracked, "Dictionary"


if __name__ == "__main__":
    all_passwords = []
    start = time.time()
    secure_password = set()
    print("Attempting to crack passwords....")
    password_list = ["ABd", "Abc", "lpo", "J*&", "Njl", "!!!!", "Aqz", "Apple", "Cake", "Biden", "password1"]
    for password in password_list:
        secure_password.add(hash_password(password))
    with concurrent.futures.ProcessPoolExecutor() as executor:
        results = [executor.submit(dic_attack, secure_password),
                   executor.submit(rainbow_table_check, secure_password),
                   executor.submit(find_password, secure_password, ['!'], 1),
                   executor.submit(find_password, secure_password, ['!', '!'], 2),
                   executor.submit(find_password, secure_password, ['!', '!', '!'], 3),
                   executor.submit(find_password, secure_password, ['!', '!', '!', '!'], 4),
                   executor.submit(find_password, secure_password, ['!', '!', '!', '!', '!'], 5)]
        for f in concurrent.futures.as_completed(results):
            message, cracked, method = f.result()
            time_run = f"{round((time.time() - start) // 60)} min {round((time.time() - start) % 60)} sec"
            print(f"{message} : {cracked} - {time_run}")
            all_passwords += cracked
    print(f"Complete list of cracked passwords: {set(tuple(all_passwords))}")
    print(f"This operation took: {round((time.time() - start) // 60)} min {round((time.time() - start) % 60)} sec")

Risposte

1 RootTwo Nov 17 2020 at 07:35

Due osservazioni:

I metodi hashlibprevedono di ricevere byte. In make_next_guess(), usa a bytearrayinvece di una stringa. Che evita le chiamate a ''.join(), ord(), ''.encode('UTF-8'), ecc Meglio ancora, rendono la funzione di un generatore che produce le congetture.

L'uso della elseclausola sul for i, byte in enumerate(guess):ciclo semplifica un po 'la logica. Quando il ciclo è finito, la elseclausola viene eseguita. Tuttavia, a breaksalta la elseclausola. Qui, se il ciclo non trova byte da aumentare, la clausola else aggiunge un altro byte alla lunghezza dell'ipotesi.

Qualcosa di simile a:

def generate_guesses(start):
    ORD_Z = ord('z')
    ORD_BANG = ord("!")
    
    guess = start[:]
    
    while True:
        yield guess
        for i, byte in enumerate(guess):
            if byte < ORD_Z:
                guess[i] += 1
                break
                
            else:
                guess[i] = ORD_BANG
                
        else:
            guess.append(ORD_BANG)

Chiamato come:

for guess in generate_guesses(bytearray(b'xzzzz')):
    ... do something with the guess ...

Eventualmente, aggiungi un argomento stopo countche indica quando il generatore deve fermarsi o quante ipotesi deve generare. Basta cambiare la while True:linea per controllare le condizioni di arresto.

La seconda osservazione è che l'ultimo lavoro presentato al Pool è 90 volte più lavoro del lavoro precedente. In effetti, è più lavoro rispetto ai precedenti 4 lavori messi insieme (forse tutti gli altri lavori). Di conseguenza, si finisce con gli altri lavori che terminano prima e un lavoro in esecuzione su un core del processore per molto tempo. Prova a suddividere i lavori in blocchi di dimensioni più uguali per mantenere occupati tutti i core del processore. Ad esempio, i lavori potrebbero funzionare su blocchi di dimensioni uguali dello spazio di ricerca delle password:

'!'    to 'zzz' 
'!!!!' to 'zzz!'
'!!!"' to 'zzz"'
'!!!#' to 'zzz#' these are all chunks of 729k (90*90*90) guesses
     ...
'!!!z' to 'zzzz'