Standardized on speed, rewrote statsgen, many bug fixes.
This commit is contained in:
parent
e041e7906d
commit
4ed47777b5
62
maskgen.py
62
maskgen.py
@ -46,12 +46,15 @@ class MaskGen:
|
||||
|
||||
self.minlength = None
|
||||
self.maxlength = None
|
||||
self.mintime = None
|
||||
self.maxtime = None
|
||||
self.mincomplexity = None
|
||||
self.maxcomplexity = None
|
||||
self.minoccurrence = None
|
||||
self.maxoccurrence = None
|
||||
|
||||
# PPS (Passwords per Second) Cracking Speed
|
||||
self.pps = 10000000000
|
||||
self.pps = 1000000000
|
||||
self.showmasks = False
|
||||
|
||||
# Counter for total masks coverage
|
||||
@ -81,20 +84,25 @@ class MaskGen:
|
||||
mask_occurrence = int(occurrence)
|
||||
mask_length = len(mask)/2
|
||||
mask_complexity = self.getcomplexity(mask)
|
||||
mask_time = mask_complexity/self.pps
|
||||
|
||||
self.total_occurrence += mask_occurrence
|
||||
|
||||
# Apply filters based on occurrence, length, complexity and time
|
||||
if (not self.minoccurrence or mask_occurrence >= self.minoccurrence) and \
|
||||
(not self.maxcomplexity or mask_complexity <= self.maxcomplexity) and \
|
||||
(not self.maxlength or mask_length <= self.maxlength) and \
|
||||
(not self.minlength or mask_length >= self.minlength):
|
||||
if (self.minoccurrence == None or mask_occurrence >= self.minoccurrence) and \
|
||||
(self.maxoccurrence == None or mask_occurrence <= self.maxoccurrence) and \
|
||||
(self.mincomplexity == None or mask_complexity <= self.mincomplexity) and \
|
||||
(self.maxcomplexity == None or mask_complexity <= self.maxcomplexity) and \
|
||||
(self.mintime == None or mask_time <= self.mintime) and \
|
||||
(self.maxtime == None or mask_time <= self.maxtime) and \
|
||||
(self.maxlength == None or mask_length <= self.maxlength) and \
|
||||
(self.minlength == None or mask_length >= self.minlength):
|
||||
|
||||
self.masks[mask] = dict()
|
||||
self.masks[mask]['length'] = mask_length
|
||||
self.masks[mask]['occurrence'] = mask_occurrence
|
||||
self.masks[mask]['complexity'] = 1 - mask_complexity
|
||||
self.masks[mask]['time'] = mask_complexity/self.pps
|
||||
self.masks[mask]['time'] = mask_time
|
||||
self.masks[mask]['optindex'] = 1 - mask_complexity/mask_occurrence
|
||||
|
||||
def generate_masks(self,sorting_mode):
|
||||
@ -132,13 +140,18 @@ class MaskGen:
|
||||
print " Masks runtime: %s" % time_human
|
||||
|
||||
def getmaskscoverage(self, checkmasks):
|
||||
|
||||
sample_count = 0
|
||||
sample_time = 0
|
||||
sample_occurrence = 0
|
||||
|
||||
total_complexity = 0
|
||||
|
||||
if self.showmasks: print "[L:] Mask: [ Occ: ] [ Time: ]"
|
||||
for mask in checkmasks:
|
||||
mask = mask.strip()
|
||||
mask_complexity = self.getcomplexity(mask)
|
||||
|
||||
total_complexity += mask_complexity
|
||||
|
||||
if mask in self.masks:
|
||||
|
||||
@ -150,17 +163,18 @@ class MaskGen:
|
||||
self.output_file.write("%s\n" % mask)
|
||||
|
||||
sample_occurrence += self.masks[mask]['occurrence']
|
||||
sample_time += self.masks[mask]['time']
|
||||
sample_count += 1
|
||||
|
||||
if self.target_time and sample_time > self.target_time:
|
||||
print "[!] Target time exceeded."
|
||||
break
|
||||
if self.target_time and total_complexity/self.pps > self.target_time:
|
||||
print "[!] Target time exceeded."
|
||||
break
|
||||
|
||||
# TODO: Something wrong here, complexity and time doesn't match with estimated from policygen
|
||||
total_time = total_complexity/self.pps
|
||||
time_human = ">1 year" if total_time > 60*60*24*365 else str(datetime.timedelta(seconds=total_time))
|
||||
print "[*] Finished matching masks:"
|
||||
print " Masks matched: %s" % sample_count
|
||||
print " Masks coverage: %d%% (%d/%d)" % (sample_occurrence*100/self.total_occurrence,sample_occurrence,self.total_occurrence)
|
||||
time_human = ">1 year" if sample_time > 60*60*24*365 else str(datetime.timedelta(seconds=sample_time))
|
||||
print " Masks runtime: %s" % time_human
|
||||
|
||||
|
||||
@ -182,11 +196,14 @@ if __name__ == "__main__":
|
||||
parser.add_option("-o", "--outputmasks", dest="output_masks", metavar="masks.hcmask", help="Save masks to a file")
|
||||
|
||||
filters = OptionGroup(parser, "Individual Mask Filter Options")
|
||||
filters.add_option("--minlength", dest="minlength", type="int", metavar="8", help="Minimum password length")
|
||||
filters.add_option("--maxlength", dest="maxlength", type="int", metavar="8", help="Maximum password length")
|
||||
filters.add_option("--maxtime", dest="maxtime", type="int", metavar="3600", help="Maximum runtime (seconds)")
|
||||
filters.add_option("--maxcomplexity", dest="maxcomplexity", type="int", metavar="", help="Maximum complexity")
|
||||
filters.add_option("--minoccurrence", dest="minoccurrence", type="int", metavar="", help="Minimum occurrence")
|
||||
filters.add_option("--minlength", dest="minlength", type="int", metavar="8", help="Minimum password length")
|
||||
filters.add_option("--maxlength", dest="maxlength", type="int", metavar="8", help="Maximum password length")
|
||||
filters.add_option("--mintime", dest="mintime", type="int", metavar="3600", help="Minimum mask runtime (seconds)")
|
||||
filters.add_option("--maxtime", dest="maxtime", type="int", metavar="3600", help="Maximum mask runtime (seconds)")
|
||||
filters.add_option("--mincomplexity", dest="mincomplexity", type="int", metavar="1", help="Minimum complexity")
|
||||
filters.add_option("--maxcomplexity", dest="maxcomplexity", type="int", metavar="100", help="Maximum complexity")
|
||||
filters.add_option("--minoccurrence", dest="minoccurrence", type="int", metavar="1", help="Minimum occurrence")
|
||||
filters.add_option("--maxoccurrence", dest="maxoccurrence", type="int", metavar="100", help="Maximum occurrence")
|
||||
parser.add_option_group(filters)
|
||||
|
||||
sorting = OptionGroup(parser, "Mask Sorting Options")
|
||||
@ -228,15 +245,20 @@ if __name__ == "__main__":
|
||||
maskgen.output_file = open(options.output_masks, 'w')
|
||||
|
||||
# Filters
|
||||
if options.minlength: maskgen.minlength = options.minlength
|
||||
if options.maxlength: maskgen.maxlength = options.maxlength
|
||||
if options.maxtime: maskgen.maxtime = options.maxtime
|
||||
if options.minlength: maskgen.minlength = options.minlength
|
||||
if options.maxlength: maskgen.maxlength = options.maxlength
|
||||
if options.mintime: maskgen.mintime = options.mintime
|
||||
if options.maxtime: maskgen.maxtime = options.maxtime
|
||||
if options.mincomplexity: maskgen.mincomplexity = options.mincomplexity
|
||||
if options.maxcomplexity: maskgen.maxcomplexity = options.maxcomplexity
|
||||
if options.minoccurrence: maskgen.minoccurrence = options.minoccurrence
|
||||
if options.maxoccurrence: maskgen.maxoccurrence = options.maxoccurrence
|
||||
|
||||
# Misc
|
||||
if options.pps: maskgen.pps = options.pps
|
||||
if options.showmasks: maskgen.showmasks = options.showmasks
|
||||
|
||||
print "[*] Using {:,d} keys/sec for calculations.".format(maskgen.pps)
|
||||
|
||||
# Load masks
|
||||
for arg in args:
|
||||
|
18
policygen.py
18
policygen.py
@ -35,13 +35,6 @@ import itertools
|
||||
|
||||
VERSION = "0.0.2"
|
||||
|
||||
# PPS (Passwords per Second) Cracking Speed
|
||||
pps = 1000000000
|
||||
|
||||
# Global Variables
|
||||
sample_time = 0
|
||||
total_time = 0
|
||||
|
||||
class PolicyGen:
|
||||
def __init__(self):
|
||||
self.output_file = None
|
||||
@ -57,7 +50,6 @@ class PolicyGen:
|
||||
self.maxupper = None
|
||||
self.maxspecial = None
|
||||
|
||||
|
||||
# PPS (Passwords per Second) Cracking Speed
|
||||
self.pps = 1000000000
|
||||
self.showmasks = False
|
||||
@ -82,7 +74,7 @@ class PolicyGen:
|
||||
sample_count = 0
|
||||
|
||||
# NOTE: It is better to collect total complexity
|
||||
# in order not to lose precision when dividing by pps
|
||||
# not to lose precision when dividing by pps
|
||||
total_complexity = 0
|
||||
sample_complexity = 0
|
||||
|
||||
@ -92,6 +84,7 @@ class PolicyGen:
|
||||
total_length_count = 0
|
||||
sample_length_count = 0
|
||||
|
||||
|
||||
total_length_complexity = 0
|
||||
sample_length_complexity = 0
|
||||
|
||||
@ -177,11 +170,11 @@ if __name__ == "__main__":
|
||||
group = OptionGroup(parser, "Password Policy", "Define the minimum (or maximum) password strength policy that you would like to test")
|
||||
group.add_option("--minlength", dest="minlength", type="int", metavar="8", default=8, help="Minimum password length")
|
||||
group.add_option("--maxlength", dest="maxlength", type="int", metavar="8", default=8, help="Maximum password length")
|
||||
group.add_option("--mindigit", dest="mindigit", type="int", metavar="1", help="Minimum number of digits")
|
||||
group.add_option("--mindigit", dest="mindigit", type="int", metavar="1", help="Minimum number of digits")
|
||||
group.add_option("--minlower", dest="minlower", type="int", metavar="1", help="Minimum number of lower-case characters")
|
||||
group.add_option("--minupper", dest="minupper", type="int", metavar="1", help="Minimum number of upper-case characters")
|
||||
group.add_option("--minspecial",dest="minspecial",type="int", metavar="1", help="Minimum number of special characters")
|
||||
group.add_option("--maxdigit", dest="maxdigit", type="int", metavar="3", help="Maximum number of digits")
|
||||
group.add_option("--maxdigit", dest="maxdigit", type="int", metavar="3", help="Maximum number of digits")
|
||||
group.add_option("--maxlower", dest="maxlower", type="int", metavar="3", help="Maximum number of lower-case characters")
|
||||
group.add_option("--maxupper", dest="maxupper", type="int", metavar="3", help="Maximum number of upper-case characters")
|
||||
group.add_option("--maxspecial",dest="maxspecial",type="int", metavar="3", help="Maximum number of special characters")
|
||||
@ -202,6 +195,7 @@ if __name__ == "__main__":
|
||||
print "[*] Saving generated masks to [%s]" % options.output_masks
|
||||
policygen.output_file = open(options.output_masks, 'w')
|
||||
|
||||
|
||||
# Password policy
|
||||
if options.minlength != None: policygen.minlength = options.minlength
|
||||
if options.maxlength != None: policygen.maxlength = options.maxlength
|
||||
@ -218,6 +212,8 @@ if __name__ == "__main__":
|
||||
if options.pps: policygen.pps = options.pps
|
||||
if options.showmasks: policygen.showmasks = options.showmasks
|
||||
|
||||
print "[*] Using {:,d} keys/sec for calculations.".format(policygen.pps)
|
||||
|
||||
# Print current password policy
|
||||
print "[*] Password policy:"
|
||||
print " Pass Lengths: min:%d max:%d" % (policygen.minlength, policygen.maxlength)
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
# This tool is part of PACK (Password Analysis and Cracking Kit)
|
||||
#
|
||||
# VERSION 0.0.1
|
||||
# VERSION 0.0.2
|
||||
#
|
||||
# Copyright (C) 2013 Peter Kacherginsky
|
||||
# All rights reserved.
|
||||
@ -44,8 +44,7 @@ from optparse import OptionParser, OptionGroup
|
||||
VERSION = "0.0.1"
|
||||
|
||||
# Testing rules with hashcat --stdout
|
||||
import subprocess
|
||||
HASHCAT_PATH = "hashcat-0.42/"
|
||||
HASHCAT_PATH = "hashcat/"
|
||||
|
||||
# Rule Generator class responsible for the complete cycle of rule generation
|
||||
class RuleGen:
|
||||
@ -713,7 +712,6 @@ class RuleGen:
|
||||
if self.verbose: print "[*] Analyzing password: %s" % password
|
||||
if self.verbose: start_time = time.clock()
|
||||
|
||||
|
||||
# Skip all numeric passwords
|
||||
if password.isdigit():
|
||||
if self.verbose: print "[!] %s => {skipping numeric} => %s" % (password,password)
|
||||
@ -836,7 +834,7 @@ class RuleGen:
|
||||
if __name__ == "__main__":
|
||||
|
||||
header = " _ \n"
|
||||
header += " RuleGen 0.0.1 | |\n"
|
||||
header += " RuleGen %s | |\n" % VERSION
|
||||
header += " _ __ __ _ ___| | _\n"
|
||||
header += " | '_ \ / _` |/ __| |/ /\n"
|
||||
header += " | |_) | (_| | (__| < \n"
|
||||
|
286
statsgen.py
286
statsgen.py
@ -30,79 +30,157 @@
|
||||
|
||||
import sys
|
||||
import re, operator, string
|
||||
from optparse import OptionParser
|
||||
from optparse import OptionParser, OptionGroup
|
||||
|
||||
VERSION = "0.0.2"
|
||||
|
||||
password_counter = 0
|
||||
class StatsGen:
|
||||
def __init__(self):
|
||||
self.output_file = None
|
||||
|
||||
# Constants
|
||||
chars_regex = list()
|
||||
chars_regex.append(('numeric',re.compile('^[0-9]+$')))
|
||||
chars_regex.append(('loweralpha',re.compile('^[a-z]+$')))
|
||||
chars_regex.append(('upperalpha',re.compile('^[A-Z]+$')))
|
||||
chars_regex.append(('mixedalpha',re.compile('^[a-zA-Z]+$')))
|
||||
chars_regex.append(('loweralphanum',re.compile('^[a-z0-9]+$')))
|
||||
chars_regex.append(('upperalphanum',re.compile('^[A-Z0-9]+$')))
|
||||
chars_regex.append(('mixedalphanum',re.compile('^[a-zA-Z0-9]+$')))
|
||||
chars_regex.append(('special',re.compile('^[^a-zA-Z0-9]+$')))
|
||||
chars_regex.append(('loweralphaspecial',re.compile('^[^A-Z0-9]+$')))
|
||||
chars_regex.append(('upperalphaspecial',re.compile('^[^a-z0-9]+$')))
|
||||
chars_regex.append(('mixedalphaspecial',re.compile('^[^0-9]+$')))
|
||||
chars_regex.append(('loweralphaspecialnum',re.compile('^[^A-Z]+$')))
|
||||
chars_regex.append(('upperalphaspecialnum',re.compile('^[^a-z]+$')))
|
||||
chars_regex.append(('mixedalphaspecialnum',re.compile('.*')))
|
||||
# Filters
|
||||
self.minlength = None
|
||||
self.maxlength = None
|
||||
self.simplemasks = None
|
||||
self.charsets = None
|
||||
|
||||
masks_regex = list()
|
||||
masks_regex.append(('alldigit',re.compile('^\d+$', re.IGNORECASE)))
|
||||
masks_regex.append(('allstring',re.compile('^[a-z]+$', re.IGNORECASE)))
|
||||
masks_regex.append(('stringdigit',re.compile('^[a-z]+\d+$', re.IGNORECASE)))
|
||||
masks_regex.append(('digitstring',re.compile('^\d+[a-z]+$', re.IGNORECASE)))
|
||||
masks_regex.append(('digitstringdigit',re.compile('^\d+[a-z]+\d+$', re.IGNORECASE)))
|
||||
masks_regex.append(('stringdigitstring',re.compile('^[a-z]+\d+[a-z]+$', re.IGNORECASE)))
|
||||
masks_regex.append(('allspecial',re.compile('^[^a-z0-9]+$', re.IGNORECASE)))
|
||||
masks_regex.append(('stringspecial',re.compile('^[a-z]+[^a-z0-9]+$', re.IGNORECASE)))
|
||||
masks_regex.append(('specialstring',re.compile('^[^a-z0-9]+[a-z]+$', re.IGNORECASE)))
|
||||
masks_regex.append(('stringspecialstring',re.compile('^[a-z]+[^a-z0-9]+[a-z]+$', re.IGNORECASE)))
|
||||
masks_regex.append(('stringspecialdigit',re.compile('^[a-z]+[^a-z0-9]+\d+$', re.IGNORECASE)))
|
||||
masks_regex.append(('specialstringspecial',re.compile('^[^a-z0-9]+[a-z]+[^a-z0-9]+$', re.IGNORECASE)))
|
||||
# Constants
|
||||
self.chars_regex = list()
|
||||
self.chars_regex.append(('numeric',re.compile('^[0-9]+$')))
|
||||
self.chars_regex.append(('loweralpha',re.compile('^[a-z]+$')))
|
||||
self.chars_regex.append(('upperalpha',re.compile('^[A-Z]+$')))
|
||||
self.chars_regex.append(('mixedalpha',re.compile('^[a-zA-Z]+$')))
|
||||
self.chars_regex.append(('loweralphanum',re.compile('^[a-z0-9]+$')))
|
||||
self.chars_regex.append(('upperalphanum',re.compile('^[A-Z0-9]+$')))
|
||||
self.chars_regex.append(('mixedalphanum',re.compile('^[a-zA-Z0-9]+$')))
|
||||
self.chars_regex.append(('special',re.compile('^[^a-zA-Z0-9]+$')))
|
||||
self.chars_regex.append(('loweralphaspecial',re.compile('^[^A-Z0-9]+$')))
|
||||
self.chars_regex.append(('upperalphaspecial',re.compile('^[^a-z0-9]+$')))
|
||||
self.chars_regex.append(('mixedalphaspecial',re.compile('^[^0-9]+$')))
|
||||
self.chars_regex.append(('loweralphaspecialnum',re.compile('^[^A-Z]+$')))
|
||||
self.chars_regex.append(('upperalphaspecialnum',re.compile('^[^a-z]+$')))
|
||||
self.chars_regex.append(('mixedalphaspecialnum',re.compile('.*')))
|
||||
|
||||
def length_check(password):
|
||||
return len(password)
|
||||
self.masks_regex = list()
|
||||
self.masks_regex.append(('alldigit',re.compile('^\d+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('allstring',re.compile('^[a-z]+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('stringdigit',re.compile('^[a-z]+\d+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('digitstring',re.compile('^\d+[a-z]+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('digitstringdigit',re.compile('^\d+[a-z]+\d+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('stringdigitstring',re.compile('^[a-z]+\d+[a-z]+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('allspecial',re.compile('^[^a-z0-9]+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('stringspecial',re.compile('^[a-z]+[^a-z0-9]+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('specialstring',re.compile('^[^a-z0-9]+[a-z]+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('stringspecialstring',re.compile('^[a-z]+[^a-z0-9]+[a-z]+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('stringspecialdigit',re.compile('^[a-z]+[^a-z0-9]+\d+$', re.IGNORECASE)))
|
||||
self.masks_regex.append(('specialstringspecial',re.compile('^[^a-z0-9]+[a-z]+[^a-z0-9]+$', re.IGNORECASE)))
|
||||
|
||||
def masks_check(password):
|
||||
for (name,regex) in masks_regex:
|
||||
if regex.match(password):
|
||||
return name
|
||||
else:
|
||||
return "othermask"
|
||||
# Stats dictionaries
|
||||
self.stats_length = dict()
|
||||
self.stats_simplemasks = dict()
|
||||
self.stats_advancedmasks = dict()
|
||||
self.stats_charactersets = dict()
|
||||
|
||||
def chars_check(password):
|
||||
for (name,regex) in chars_regex:
|
||||
if regex.match(password):
|
||||
return name
|
||||
else:
|
||||
return "otherchar"
|
||||
self.hiderare = False
|
||||
|
||||
def advmask_check(password):
|
||||
advmask = list()
|
||||
for letter in password:
|
||||
if letter in string.digits: advmask.append("?d")
|
||||
elif letter in string.lowercase: advmask.append("?l")
|
||||
elif letter in string.uppercase: advmask.append("?u")
|
||||
else: advmask.append("?s")
|
||||
return "".join(advmask)
|
||||
self.filter_counter = 0
|
||||
self.total_counter = 0
|
||||
|
||||
def main():
|
||||
password_length = dict()
|
||||
masks = dict()
|
||||
advmasks = dict()
|
||||
chars = dict()
|
||||
filter_counter = 0
|
||||
total_counter = 0
|
||||
def simplemasks_check(self, password):
|
||||
for (name,regex) in self.masks_regex:
|
||||
if regex.match(password):
|
||||
return name
|
||||
else:
|
||||
return "othermask"
|
||||
|
||||
def characterset_check(self, password):
|
||||
for (name,regex) in self.chars_regex:
|
||||
if regex.match(password):
|
||||
return name
|
||||
else:
|
||||
return "otherchar"
|
||||
|
||||
def advancedmask_check(self, password):
|
||||
mask = list()
|
||||
for letter in password:
|
||||
if letter in string.digits: mask.append("?d")
|
||||
elif letter in string.lowercase: mask.append("?l")
|
||||
elif letter in string.uppercase: mask.append("?u")
|
||||
else: mask.append("?s")
|
||||
return "".join(mask)
|
||||
|
||||
def generate_stats(self, filename):
|
||||
|
||||
f = open(filename,'r')
|
||||
|
||||
for password in f:
|
||||
password = password.rstrip('\r\n')
|
||||
self.total_counter += 1
|
||||
|
||||
pass_length = len(password)
|
||||
characterset = self.characterset_check(password)
|
||||
simplemask = self.simplemasks_check(password)
|
||||
advancedmask = self.advancedmask_check(password)
|
||||
|
||||
if (self.charsets == None or characterset in self.charsets) and \
|
||||
(self.simplemasks == None or simplemask in self.simplemasks) and \
|
||||
(self.maxlength == None or pass_length <= self.maxlength) and \
|
||||
(self.minlength == None or pass_length >= self.minlength):
|
||||
|
||||
self.filter_counter += 1
|
||||
|
||||
if pass_length in self.stats_length:
|
||||
self.stats_length[pass_length] += 1
|
||||
else:
|
||||
self.stats_length[pass_length] = 1
|
||||
|
||||
if characterset in self.stats_charactersets:
|
||||
self.stats_charactersets[characterset] += 1
|
||||
else:
|
||||
self.stats_charactersets[characterset] = 1
|
||||
|
||||
if simplemask in self.stats_simplemasks:
|
||||
self.stats_simplemasks[simplemask] += 1
|
||||
else:
|
||||
self.stats_simplemasks[simplemask] = 1
|
||||
|
||||
if advancedmask in self.stats_advancedmasks:
|
||||
self.stats_advancedmasks[advancedmask] += 1
|
||||
else:
|
||||
self.stats_advancedmasks[advancedmask] = 1
|
||||
|
||||
f.close()
|
||||
|
||||
def print_stats(self):
|
||||
print "[+] Analyzing %d%% (%d/%d) of passwords" % (self.filter_counter*100/self.total_counter, self.filter_counter, self.total_counter)
|
||||
print " NOTE: Statistics below is relative to the number of analyzed passwords, not total number of passwords"
|
||||
print "\n[*] Line Count Statistics..."
|
||||
for (length,count) in sorted(self.stats_length.iteritems(), key=operator.itemgetter(1), reverse=True):
|
||||
if self.hiderare and not count*100/self.filter_counter > 0: continue
|
||||
print "[+] %25d: %02d%% (%d)" % (length, count*100/self.filter_counter, count)
|
||||
|
||||
print "\n[*] Charset statistics..."
|
||||
for (char,count) in sorted(self.stats_charactersets.iteritems(), key=operator.itemgetter(1), reverse=True):
|
||||
if self.hiderare and not count*100/self.filter_counter > 0: continue
|
||||
print "[+] %25s: %02d%% (%d)" % (char, count*100/self.filter_counter, count)
|
||||
|
||||
print "\n[*] Simple Mask statistics..."
|
||||
for (simplemask,count) in sorted(self.stats_simplemasks.iteritems(), key=operator.itemgetter(1), reverse=True):
|
||||
if self.hiderare and not count*100/self.filter_counter > 0: continue
|
||||
print "[+] %25s: %02d%% (%d)" % (simplemask, count*100/self.filter_counter, count)
|
||||
|
||||
print "\n[*] Advanced Mask statistics..."
|
||||
for (advancedmask,count) in sorted(self.stats_advancedmasks.iteritems(), key=operator.itemgetter(1), reverse=True):
|
||||
if count*100/self.filter_counter > 0:
|
||||
print "[+] %25s: %02d%% (%d)" % (advancedmask, count*100/self.filter_counter, count)
|
||||
|
||||
if self.output_file:
|
||||
self.output_file.write("%s,%d\n" % (advancedmask,count))
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
header = " _ \n"
|
||||
header += " StatsGen 0.0.2 | |\n"
|
||||
header += " StatsGen %s | |\n" % VERSION
|
||||
header += " _ __ __ _ ___| | _\n"
|
||||
header += " | '_ \ / _` |/ __| |/ /\n"
|
||||
header += " | |_) | (_| | (__| < \n"
|
||||
@ -111,11 +189,18 @@ def main():
|
||||
header += " |_| iphelix@thesprawl.org\n"
|
||||
header += "\n"
|
||||
|
||||
parser = OptionParser("%prog [options] passwords.txt", version="%prog "+VERSION)
|
||||
parser.add_option("-l", "--length", dest="length_filter",help="Password length filter.",metavar="8")
|
||||
parser.add_option("-c", "--charset", dest="char_filter", help="Password charset filter.", metavar="loweralpha")
|
||||
parser.add_option("-m", "--mask", dest="mask_filter",help="Password mask filter", metavar="stringdigit")
|
||||
parser.add_option("-o", "--masksoutput", dest="mask_output",help="Generate and save masks db to a file", metavar="masks.csv")
|
||||
parser = OptionParser("%prog [options] passwords.txt\n\nType --help for more options", version="%prog "+VERSION)
|
||||
|
||||
filters = OptionGroup(parser, "Password Filters")
|
||||
filters.add_option("--minlength", dest="minlength", type="int", metavar="8", help="Minimum password length")
|
||||
filters.add_option("--maxlength", dest="maxlength", type="int", metavar="8", help="Maximum password length")
|
||||
filters.add_option("--charset", dest="charsets", help="Password charset filter (comma separated)", metavar="loweralpha,numeric")
|
||||
filters.add_option("--simplemask", dest="simplemasks",help="Password mask filter (comma separated)", metavar="stringdigit,allspecial")
|
||||
parser.add_option_group(filters)
|
||||
|
||||
parser.add_option("-o", "--output", dest="output_file",help="Save masks and stats to a file", metavar="password.masks")
|
||||
parser.add_option("--hiderare", action="store_true", dest="hiderare", default=False, help="Hide statistics covering less than 1% of the sample")
|
||||
|
||||
parser.add_option("-q", "--quiet", action="store_true", dest="quiet", default=False, help="Don't show headers.")
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
@ -126,66 +211,21 @@ def main():
|
||||
if len(args) != 1:
|
||||
parser.error("no passwords file specified")
|
||||
exit(1)
|
||||
|
||||
print "[*] Analyzing passwords: %s" % args[0]
|
||||
|
||||
f = open(args[0],'r')
|
||||
print "[*] Analyzing passwords in [%s]" % args[0]
|
||||
|
||||
for password in f:
|
||||
password = password.strip()
|
||||
total_counter += 1
|
||||
|
||||
pass_len = length_check(password)
|
||||
mask_set = masks_check(password)
|
||||
char_set = chars_check(password)
|
||||
advmask = advmask_check(password)
|
||||
statsgen = StatsGen()
|
||||
|
||||
if (not options.length_filter or str(pass_len) in options.length_filter.split(',')) and \
|
||||
(not options.char_filter or char_set in options.char_filter.split(',')) and \
|
||||
(not options.mask_filter or mask_set in options.mask_filter.split(',')):
|
||||
|
||||
filter_counter += 1
|
||||
if not options.minlength == None: statsgen.minlength = options.minlength
|
||||
if not options.maxlength == None: statsgen.maxlength = options.maxlength
|
||||
if not options.charsets == None: statsgen.charsets = [x.strip() for x in options.charsets.split(',')]
|
||||
if not options.simplemasks == None: statsgen.simplemasks = [x.strip() for x in options.simplemasks.split(',')]
|
||||
|
||||
try: password_length[pass_len] += 1
|
||||
except: password_length[pass_len] = 1
|
||||
if options.hiderare: statsgen.hiderare = options.hiderare
|
||||
|
||||
try: masks[mask_set] += 1
|
||||
except: masks[mask_set] = 1
|
||||
if options.output_file:
|
||||
print "[*] Saving advanced masks and occurrences to [%s]" % options.output_file
|
||||
statsgen.output_file = open(options.output_file, 'w')
|
||||
|
||||
try: chars[char_set] += 1
|
||||
except: chars[char_set] = 1
|
||||
|
||||
try: advmasks[advmask] += 1
|
||||
except: advmasks[advmask] = 1
|
||||
|
||||
f.close()
|
||||
|
||||
print "[+] Analyzing %d%% (%d/%d) passwords" % (filter_counter*100/total_counter, filter_counter, total_counter)
|
||||
print " NOTE: Statistics below is relative to the number of analyzed passwords, not total number of passwords"
|
||||
print "\n[*] Line Count Statistics..."
|
||||
for (length,count) in sorted(password_length.iteritems(), key=operator.itemgetter(1), reverse=True):
|
||||
if count*100/filter_counter > 0:
|
||||
print "[+] %25d: %02d%% (%d)" % (length, count*100/filter_counter, count)
|
||||
|
||||
print "\n[*] Charset statistics..."
|
||||
for (char,count) in sorted(chars.iteritems(), key=operator.itemgetter(1), reverse=True):
|
||||
print "[+] %25s: %02d%% (%d)" % (char, count*100/filter_counter, count)
|
||||
|
||||
print "\n[*] Mask statistics..."
|
||||
for (mask,count) in sorted(masks.iteritems(), key=operator.itemgetter(1), reverse=True):
|
||||
print "[+] %25s: %02d%% (%d)" % (mask, count*100/filter_counter, count)
|
||||
|
||||
print "\n[*] Advanced Mask statistics..."
|
||||
for (advmask,count) in sorted(advmasks.iteritems(), key=operator.itemgetter(1), reverse=True):
|
||||
if count*100/filter_counter > 0:
|
||||
print "[+] %25s: %02d%% (%d)" % (advmask, count*100/filter_counter, count)
|
||||
|
||||
if options.mask_output:
|
||||
print "\n[*] Saving Mask statistics to %s" % options.mask_output
|
||||
fmask = open(options.mask_output, "w")
|
||||
for (advmask,count) in sorted(advmasks.iteritems(), key=operator.itemgetter(1), reverse=True):
|
||||
fmask.write("%s,%d\n" % (advmask,count))
|
||||
fmask.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
statsgen.generate_stats(args[0])
|
||||
statsgen.print_stats()
|
Loading…
x
Reference in New Issue
Block a user