I am have created a hash cracking script and I would like to improve it's performance. What I am aiming to do now is use threads to be able to crack hashes and a faster speed, so i think this is called mutual exclusion. I am new to python and am having a hard time doing this. When I tried to implement this my safety pause feature stopped working and I can't figure out how to get it working again and also when I try to mutual exclude the threads I have printing issues where too many lines are printed. Here is my code for my script
#!/usr/bin/env python3
import psutil
import argparse
import hashlib
from itertools import product
import time
from passlib.hash import sha512_crypt, nthash
import threading
from colorama import Fore, init
print_lock = threading.Lock()
init(autoreset=True)
shutdown_event = threading.Event()
match_found_event = threading.Event()
def generate_combinations(chars, min_length, max_length=22):
for length in range(min_length, max_length + 1):
for combo in product(chars, repeat=length):
yield ''.join(combo)
def md5_hash(string):
return hashlib.md5(string.encode()).hexdigest()
def sha1_hash(string):
return hashlib.sha1(string.encode()).hexdigest()
def sha256_hash(string):
return hashlib.sha256(string.encode()).hexdigest()
def sha512_unix_hash(string):
return sha512_crypt.using(rounds=5000).hash(string)
def nt_hash(string):
return nthash.hash(string)
def print_current_password(hash_type, target_hash, current_word):
with print_lock:
print(f'\rTYPE: {hash_type} | TARGET: {target_hash} | TRYING: {current_word}', end='')
print("\033[K", end='', flush=True)
def brute_force(target_hash, hash_type, chars, min_length, max_length, success_event, safety_pause=None):
counter = 0
for word in generate_combinations(chars, min_length, max_length):
if shutdown_event.is_set() or success_event.is_set():
return
print_current_password(hash_type, target_hash, word)
if hash_type == 'md5':
computed_hash = md5_hash(word)
elif hash_type == 'sha1':
computed_hash = sha1_hash(word)
elif hash_type == 'sha256':
computed_hash = sha256_hash(word)
elif hash_type == 'sha512_unix':
if sha512_crypt.verify(word, target_hash):
success_event.set()
with print_lock:
print(f"\nMatch found for hash {target_hash}:{Fore.LIGHTBLUE_EX} {word}")
time.sleep(2)
return word
elif hash_type == 'nt':
computed_hash = nt_hash(word)
else:
raise ValueError("Unsupported hash type")
if computed_hash == target_hash:
success_event.set()
match_found_event.set()
time.sleep(1)
with print_lock:
print(f"\nMatch found for hash {target_hash}:{Fore.LIGHTBLUE_EX} {word}")
return word
counter += 1
if safety_pause:
if safety_pause == 1 and counter % 699999 == 0:
time.sleep(1.35)
elif safety_pause == 2 and counter % 699999 == 0:
time.sleep(2)
elif safety_pause == 3 and counter % 199999 == 0:
time.sleep(1.5)
def resource_printer():
while not shutdown_event.is_set():
cpu, mem = resource_usage()
with print_lock:
print(f'\n\rCPU Usage: {cpu}% Memory Usage: {mem}%', end='', flush=True)
print("\033[F", end='', flush=True)
time.sleep(1)
if match_found_event.is_set():
break
def resource_usage():
cpu_percent = psutil.cpu_percent(interval=1)
memory_info = psutil.virtual_memory()
return cpu_percent, memory_info.percent
def crack_hash(target_hash, hash_type, chars, min_length, max_length, safety_pause=None):
results = []
threads = []
try:
for _ in range(args.threads):
t = threading.Thread(target=brute_force,
args=(target_hash, hash_type, chars, min_length, max_length, safety_pause))
t.start()
threads.append(t)
for t in threads:
t.join()
except KeyboardInterrupt:
print("\nInitiating graceful shutdown. Please wait...")
shutdown_event.set()
for t in threads:
t.join()
finally:
if args.threads > 1:
t_printer.join()
results.append(brute_force(target_hash, args.hash_type, chars, min_length, 22, safety_pause))
return results
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Brute force a hash from a file. Supports MD5, SHA-1, SHA-256, SHA-512(UNIX), and Windows NT.")
parser.add_argument("--hash", required=True, help="File containing the hash to be brute-forced.")
parser.add_argument("--hash-type", required=True, choices=['md5', 'sha1', 'sha256', 'sha512_unix', 'nt'],
help="Type of hashing algorithm.")
parser.add_argument("--length", type=int, default=4, choices=range(4, 9),
help="Minimum password length to start brute-forcing. Default is 4, can be set between 4 and 8.")
parser.add_argument("--threads", type=int, default=1, choices=[1, 2, 3, 4],
help="Number of threads to use for brute-forcing. Default is 1. Max is 4.")
parser.add_argument("--safety", type=int, choices=[1, 2, 3], default=None,
help="Choose a safety level to reduce CPU usage during brute-forcing. Safety levels 1, 2, 3")
args = parser.parse_args()
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*'
min_length = args.length
safety_pause = 1.35 if args.safety else None
try:
with open(args.hash, 'r') as file:
target_hash = file.readline().strip()
except FileNotFoundError:
print("Error: Specified file not found.")
exit(1)
except PermissionError:
print("Error: No permission to read the file.")
exit(1)
if not target_hash:
print("Error: File is empty or contains no valid hash.")
exit(1)
try:
success_event = threading.Event() #success event to signal threads to stop
threads = []
for _ in range(args.threads):
t = threading.Thread(target=brute_force,
args=(target_hash, args.hash_type, chars, min_length, 22, success_event, safety_pause))
t.start()
threads.append(t)
if args.threads > 1:
t_printer = threading.Thread(target=resource_printer)
t_printer.start()
for t in threads:
t.join()
if args.threads > 1:
t_printer.join()
results = brute_force(target_hash, args.hash_type, chars, min_length, 22, success_event, safety_pause)
if results:
print(f"\nMatch found for hash {target_hash}:{Fore.LIGHTBLUE_EX} {results}")
except KeyboardInterrupt:
print("\nInitiating graceful shutdown. Please wait...")
success_event.set() #success event to stop threads
for t in threads:
t.join()
if args.threads > 1:
t_printer.join()
if not success_event.is_set():
print(f"\nNo match found for hash {target_hash}.")
My threads as of now do the same work as the others not improving performance at all. I have tried different things and each time it resulted in either the printing of new lines over and over again, when it should only be on one line. Also I don't know why safety pause no longer works, It worked before I introduced threads. I have a hard time understanding the threading module and would appreciate help on any solutions to be able to make sure each thread's attempt is only made once making cracking faster. Printing a new line for each thread would be acceptable, but when i try fix it makes hundreds of new lines.