Cracker de senha SHA256 - v2 com simultaneidade
Eu atualizei meu código anterior com as sugestões. Também implementei a simultaneidade para acelerar os resultados.
Gostaria de receber comentários sobre um uso mais eficiente em simultaneidade / processamento paralelo / hyper-threading
obrigado
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")
Respostas
Duas observações:
Os métodos em hashlibesperam receber bytes. Em make_next_guess(), use um em bytearrayvez de uma string. Isso evita as chamadas para ''.join(), ord(), ''.encode('UTF-8'), etc. Melhor ainda, fazer a função de um gerador que produz as suposições.
Usar a elsecláusula no for i, byte in enumerate(guess):loop simplifica um pouco a lógica. Quando o loop termina, a elsecláusula é executada. No entanto, a breakignora a elsecláusula. Aqui, se o loop não encontrar bytes para aumentar, a cláusula else adiciona outro byte ao comprimento da estimativa.
Algo como:
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)
Chamado como:
for guess in generate_guesses(bytearray(b'xzzzz')):
... do something with the guess ...
Possivelmente, adicione um argumento stopou countque diga quando o gerador deve parar ou quantas suposições ele deve gerar. Basta alterar a while True:linha para verificar a condição de parada.
A segunda observação é que o último trabalho submetido ao Pool é 90 vezes mais trabalho do que o trabalho anterior. Na verdade, é mais trabalho do que os 4 empregos anteriores combinados (talvez todos os outros empregos). Como resultado, você acaba com os outros trabalhos sendo concluídos mais cedo e um trabalho sendo executado em um núcleo do processador por um longo tempo. Tente dividir os trabalhos em pedaços de tamanhos mais iguais para manter todos os núcleos do processador ocupados. Por exemplo, as tarefas podem funcionar em partes de tamanhos iguais do espaço de pesquisa de senha:
'!' to 'zzz'
'!!!!' to 'zzz!'
'!!!"' to 'zzz"'
'!!!#' to 'zzz#' these are all chunks of 729k (90*90*90) guesses
...
'!!!z' to 'zzzz'