Write out analysis files with passwords, as well as source password file

We need it to write out the source passwords as a reference as some are
removed while processing if they don't fit the model that rulegen is
good at (such as all-numerical passwords).
This commit is contained in:
xeals 2025-03-21 09:57:21 +11:00
parent 57aa4f8a00
commit 08915e0fee
Signed by: xeals
SSH Key Fingerprint: SHA256:a4XbrSGLzdf9/fVgzuMqfLCU/p8A0g8smg0njUqVyXM

View File

@ -746,7 +746,7 @@ class RuleGen:
else: else:
return True return True
def analyze_password(self,password, rules_queue=multiprocessing.Queue(), words_queue=multiprocessing.Queue()): def analyze_password(self,password, index=0, rules_queue=multiprocessing.Queue(), words_queue=multiprocessing.Queue()):
""" Analyze a single password. """ """ Analyze a single password. """
LOGGER.verbose("[*] Analyzing password: %s" % password) LOGGER.verbose("[*] Analyzing password: %s" % password)
@ -762,6 +762,7 @@ class RuleGen:
word["hashcat_rules"] = [[],] word["hashcat_rules"] = [[],]
word["pre_rule"] = [] word["pre_rule"] = []
word["best_rule_length"] = 9999 word["best_rule_length"] = 9999
word["index"] = index
words.append(word) words.append(word)
@ -776,6 +777,7 @@ class RuleGen:
# Generate a collection of hashcat_rules lists # Generate a collection of hashcat_rules lists
word["hashcat_rules"] = self.generate_hashcat_rules(word["suggestion"],word["password"]) word["hashcat_rules"] = self.generate_hashcat_rules(word["suggestion"],word["password"])
word["index"] = index
self.print_hashcat_rules(words, password, rules_queue, words_queue) self.print_hashcat_rules(words, password, rules_queue, words_queue)
@ -786,7 +788,7 @@ class RuleGen:
# Sorted list based on rule length # Sorted list based on rule length
for word in sorted(words, key=lambda word: len(word["hashcat_rules"][0])): for word in sorted(words, key=lambda word: len(word["hashcat_rules"][0])):
words_queue.put(word["suggestion"]) words_queue.put((word["index"], word["suggestion"]))
for hashcat_rule in word["hashcat_rules"]: for hashcat_rule in word["hashcat_rules"]:
@ -806,7 +808,7 @@ class RuleGen:
hashcat_rule_str = " ".join(hashcat_rule + word["pre_rule"] or [':']) hashcat_rule_str = " ".join(hashcat_rule + word["pre_rule"] or [':'])
LOGGER.verbose("[+] %s => %s => %s" % (word["suggestion"], hashcat_rule_str, password)) LOGGER.verbose("[+] %s => %s => %s" % (word["suggestion"], hashcat_rule_str, password))
rules_queue.put(hashcat_rule_str) rules_queue.put((word["index"], hashcat_rule_str))
def password_worker(self,i, passwords_queue, rules_queue, words_queue): def password_worker(self,i, passwords_queue, rules_queue, words_queue):
@ -818,7 +820,8 @@ class RuleGen:
# Interrupted by a Death Pill # Interrupted by a Death Pill
if password == None: break if password == None: break
self.analyze_password(password, rules_queue, words_queue) index, password = password
self.analyze_password(password, index, rules_queue, words_queue)
except (KeyboardInterrupt, SystemExit): except (KeyboardInterrupt, SystemExit):
LOGGER.debug("[*] Password analysis worker [%d] terminated." % i) LOGGER.debug("[*] Password analysis worker [%d] terminated." % i)
@ -837,7 +840,7 @@ class RuleGen:
# Interrupted by a Death Pill # Interrupted by a Death Pill
if rule == None: break if rule == None: break
f.write("%s\n" % rule) f.write("%d\t%s\n" % rule)
f.flush() f.flush()
except (KeyboardInterrupt, SystemExit): except (KeyboardInterrupt, SystemExit):
@ -859,7 +862,7 @@ class RuleGen:
# Interrupted by a Death Pill # Interrupted by a Death Pill
if word == None: break if word == None: break
f.write("%s\n" % word) f.write("%d\t%s\n" % word)
f.flush() f.flush()
except (KeyboardInterrupt, SystemExit): except (KeyboardInterrupt, SystemExit):
@ -890,6 +893,10 @@ class RuleGen:
f = open(passwords_file,'r', encoding=encoding) f = open(passwords_file,'r', encoding=encoding)
output_pwd_filename = "%s.password" % self.basename
LOGGER.info("[*] Saving analysed passwords to to %s" % output_pwd_filename)
o = open(output_pwd_filename, "w")
password_count = 0 password_count = 0
analysis_start = time.time() analysis_start = time.time()
segment_start = analysis_start segment_start = analysis_start
@ -909,7 +916,9 @@ class RuleGen:
# Perform preliminary checks and add password to the queue # Perform preliminary checks and add password to the queue
if self.check_reversible_password(password): if self.check_reversible_password(password):
passwords_queue.put(password) passwords_queue.put((password_count, password))
o.write("%d\t%s\n" % (password_count, password))
o.flush()
except (KeyboardInterrupt, SystemExit): except (KeyboardInterrupt, SystemExit):
LOGGER.warning("\n[!] Rulegen was interrupted.") LOGGER.warning("\n[!] Rulegen was interrupted.")
@ -927,11 +936,14 @@ class RuleGen:
rules_queue.put(None) rules_queue.put(None)
words_queue.put(None) words_queue.put(None)
o.close()
f.close() f.close()
analysis_time = time.time() - analysis_start analysis_time = time.time() - analysis_start
LOGGER.info("[*] Finished processing %d passwords in %.2f seconds at the rate of %.2f p/sec" % (password_count, analysis_time, float(password_count)/analysis_time )) LOGGER.info("[*] Finished processing %d passwords in %.2f seconds at the rate of %.2f p/sec" % (password_count, analysis_time, float(password_count)/analysis_time ))
return
LOGGER.info("[*] Generating statistics for [%s] rules and words." % self.basename) LOGGER.info("[*] Generating statistics for [%s] rules and words." % self.basename)
LOGGER.info("[-] Skipped %d all numeric passwords (%0.2f%%)" % \ LOGGER.info("[-] Skipped %d all numeric passwords (%0.2f%%)" % \
(self.numeric_stats_total, float(self.numeric_stats_total)*100.0/float(password_count))) (self.numeric_stats_total, float(self.numeric_stats_total)*100.0/float(password_count)))