├── .gitignore ├── simple-pass.txt ├── screens ├── ishot-141205-195328.png └── ishot-141206-093747.png ├── complex-pass.txt ├── README.md └── passtweaker.py /.gitignore: -------------------------------------------------------------------------------- 1 | complex-pass.txt -------------------------------------------------------------------------------- /simple-pass.txt: -------------------------------------------------------------------------------- 1 | password 2 | abc 3 | admin 4 | gandalf 5 | -------------------------------------------------------------------------------- /screens/ishot-141205-195328.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/PassTweaker/master/screens/ishot-141205-195328.png -------------------------------------------------------------------------------- /screens/ishot-141206-093747.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/PassTweaker/master/screens/ishot-141206-093747.png -------------------------------------------------------------------------------- /complex-pass.txt: -------------------------------------------------------------------------------- 1 | P@ssword 2 | P@ssw0rd 3 | P@5sword 4 | P@55word 5 | Passw0rd 6 | Pa5sw0rd 7 | Pa55w0rd 8 | P@5sw0rd 9 | P@55w0rd 10 | Pa5sword 11 | Pa55word 12 | Test1234 13 | T3st1234 14 | Te5t1234 15 | Test9876 16 | T3st9876 17 | Te5t9876 18 | Admin123 19 | Adm1n123 20 | Admin987 21 | Adm1n987 22 | G@ndalf! 23 | G@nd@lf! 24 | Gandalf! 25 | G@ndalf$ 26 | G@nd@lf$ 27 | Gandalf$ 28 | G@ndalf% 29 | G@nd@lf% 30 | Gandalf% 31 | G@ndalf? 32 | G@nd@lf? 33 | Gandalf? 34 | G@ndalf1 35 | G@nd@lf1 36 | Gandalf1 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PassTweaker 2 | =========== 3 | 4 | Tweaks password files to match modern password requirements. 5 | 6 | Basically it's turning this: 7 | ['password', 'test', 'admin', 'gandalf'] 8 | 9 | Into this: 10 | ['P@ssword', 'P@ssw0rd', 'P@5sword', 'P@55word', 'Passw0rd', 'Pa5sw0rd', 'Pa55w0rd', 'P@5sw0rd', 'P@55w0rd', 'Pa5sword', 'Pa55word', 'Test1234', 'T3st1234', 'Te5t1234', 'Test9876', 'T3st9876', 'Te5t9876', 'Admin123', 'Adm1n123', 'Admin987', 'Adm1n987', 'G@ndalf!', 'G@nd@lf!', 'Gandalf!', 'G@ndalf$', 'G@nd@lf$', 'Gandalf$', 'G@ndalf%', 'G@nd@lf%', 'Gandalf%', 'G@ndalf?', 'G@nd@lf?', 'Gandalf?', 'G@ndalf1', 'G@nd@lf1', 'Gandalf1'] 11 | 12 | 13 | Usage 14 | =========== 15 | usage: passtweaker.py [-h] -f wordlist [-o new-wordlist] [--intense] [--debug] 16 | 17 | PassTweaker 18 | 19 | optional arguments: 20 | -h, --help show this help message and exit 21 | -f wordlist File to transform 22 | -o new-wordlist Output file 23 | --intense Try even to improve words that already match the 24 | requirements 25 | --debug Debug output 26 | 27 | 28 | Screenshot 29 | ============ 30 | ![Alt text](/screens/ishot-141206-093747.png?raw=true "Screenshot") 31 | -------------------------------------------------------------------------------- /passtweaker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: iso-8859-1 -*- 3 | # -*- coding: utf-8 -*- 4 | # 5 | # Password Tweaker 6 | # Transforms password lists in list of passwords 7 | # that would meet the Windows 7/2008 complexity requirements 8 | 9 | import argparse 10 | import re 11 | import traceback 12 | 13 | def parse_words(words_file): 14 | 15 | print "Reading wordlist '%s' ... " % words_file 16 | 17 | try: 18 | # Read the wordlist 19 | with open(words_file, 'r') as file: 20 | lines = [line.rstrip() for line in file] 21 | 22 | print "Read wordlist '%s' with %s words." % ( words_file, len(lines) ) 23 | 24 | if args.debug: 25 | print "BEFORE" 26 | print lines 27 | 28 | except: 29 | traceback.print_exc() 30 | 31 | # Loop through the words 32 | for word in lines: 33 | 34 | # Initial Form 35 | #if args.debug: 36 | # print "FROM: %s" % word 37 | 38 | # Check if it matches the requirements 39 | if tryAppend(word): 40 | continue 41 | 42 | # Upper First Char 43 | uFirst = word[0].upper() 44 | word = uFirst + word[1:] 45 | 46 | # Check if it matches the requirements 47 | if tryAppend(word): 48 | continue 49 | 50 | # Fill up the space with numbers or special chars 51 | num_chars = len(word) 52 | if num_chars < 7: 53 | new_word = fill_up_inc(word) 54 | tryAppend(new_word) 55 | new_word = fill_up_dec(word) 56 | tryAppend(new_word) 57 | 58 | # Fill up with single char 59 | if num_chars == 7: 60 | for new_word in add_special_chars(word): 61 | tryAppend(new_word) 62 | 63 | # If 8 characters used try to replace chars with numbers 64 | if num_chars == 8: 65 | for new_word in replace_chars(word): 66 | tryAppend(new_word) 67 | 68 | if args.intense: 69 | # Remove one char and add a special character 70 | for new_word in add_special_chars(word[:7]): 71 | tryAppend(new_word) 72 | 73 | # Append year numbers and special chars 74 | if args.intense: 75 | # If word has 4 or 6 chars try to append a year 76 | if num_chars == 6: 77 | for new_word in (add_year_numbers(word, chars=2)): 78 | tryAppend(new_word) 79 | if num_chars == 4: 80 | for new_word in (add_year_numbers(word, chars=4)): 81 | tryAppend(new_word) 82 | 83 | # If word has 3 or 5 chars try to append a year and special character 84 | if num_chars == 5: 85 | for new_word in (add_year_numbers(word, chars=2)): 86 | for newer_word in (add_special_chars(new_word)): 87 | tryAppend(newer_word) 88 | if num_chars == 3: 89 | for new_word in (add_year_numbers(word, chars=4)): 90 | for newer_word in (add_special_chars(new_word)): 91 | tryAppend(newer_word) 92 | 93 | # If word is longer than 8 chars - cut it and add 1-2 extra chars 94 | 95 | 96 | def tryAppend(word): 97 | if meets_requirements(word): 98 | 99 | # Normal mode 100 | if not args.intense: 101 | complex_words.append(word) 102 | return 1 103 | 104 | # Intense mode 105 | else: 106 | for new_word in replace_chars(word): 107 | append_word(new_word) 108 | return 1 109 | 110 | return 0 111 | 112 | 113 | def append_word(word): 114 | if not word in complex_words: 115 | complex_words.append(word) 116 | 117 | 118 | def fill_up_inc(word): 119 | i = 1 120 | while len(word) < 8: 121 | word = word + str(i) 122 | i += 1 123 | return word 124 | 125 | def fill_up_dec(word): 126 | i = 9 127 | while len(word) < 8: 128 | word = word + str(i) 129 | i -= 1 130 | return word 131 | 132 | 133 | def replace_chars(word): 134 | yield word.replace("a", "@", 1) 135 | yield word.replace("a", "@") 136 | yield word.replace("o", "0", 1) 137 | yield word.replace("o", "0").replace("a", "@") 138 | yield word.replace("e", "3", 1) 139 | yield word.replace("e", "3") 140 | yield word.replace("s", "5", 1) 141 | yield word.replace("s", "5") 142 | yield word.replace("i", "1", 1) 143 | yield word.replace("i", "1") 144 | 145 | 146 | def add_special_chars(word): 147 | 148 | special_chars = ['!', '$', '$', '?', '+', '!', '%'] 149 | 150 | for char in special_chars: 151 | yield word + char 152 | 153 | def add_year_numbers(word, chars=2): 154 | 155 | startYear = 1970 156 | 157 | if chars == 2: 158 | startYearShort = int(str(startYear)[-2:]) 159 | for year in (range(startYearShort,99)): 160 | yield(word+str(year)) 161 | for year in range(0,15): 162 | if len(str(year)) == 1: 163 | yield(word + "0" + str(year)) 164 | else: 165 | yield(word + str(year)) 166 | 167 | if chars == 4: 168 | for year in (range(startYear,2015)): 169 | yield(word+str(year)) 170 | 171 | 172 | def meets_requirements(word): 173 | 174 | # 8 chars 175 | if len(word) < 8: 176 | return 0 177 | # Upper Case Char 178 | if not re.search(r'[A-Z]', word): 179 | return 0 180 | # Upper Case Char 181 | if not re.search(r'[a-z]', word): 182 | return 0 183 | # Upper Case Char 184 | if not re.search(r'[0-9\W]', word): 185 | return 0 186 | 187 | #if args.debug: 188 | #print "TO: %s" % word 189 | 190 | # Contains all necessary chars 191 | return 1 192 | 193 | def printWelcome(): 194 | print "###############################################################################" 195 | print " " 196 | print " PASSTWEAKER" 197 | print " " 198 | print " by Florian Roth" 199 | print " December 2014" 200 | print " Version 0.2" 201 | print " " 202 | print "###############################################################################" 203 | 204 | # MAIN ################################################################ 205 | if __name__ == '__main__': 206 | 207 | # Parse Arguments 208 | parser = argparse.ArgumentParser(description='PassTweaker') 209 | parser.add_argument('-f', metavar="wordlist", help='File to transform', required=True) 210 | parser.add_argument('-o', metavar="new-wordlist", help='Output file', default="complex-pass.txt") 211 | parser.add_argument('--intense', action='store_true', default=False, help='Try even to improve words that already match the requirements') 212 | parser.add_argument('--debug', action='store_true', default=False, help='Debug output') 213 | 214 | args = parser.parse_args() 215 | 216 | # Print Welcome 217 | printWelcome() 218 | 219 | global complex_words 220 | complex_words = [] 221 | # Parse words 222 | parse_words(args.f) 223 | 224 | if args.debug: 225 | print "AFTER" 226 | print complex_words 227 | 228 | # Write complex words 229 | try: 230 | outfile = open(args.o, "w") 231 | outfile.write("\n".join(complex_words)) 232 | outfile.close() 233 | 234 | print "%s words written to improved wordlist '%s'." % ( len(complex_words), args.o) 235 | 236 | except: 237 | traceback.print_exc() --------------------------------------------------------------------------------