├── .gitignore ├── PACK ├── ChangeLog ├── LICENSE ├── README ├── maskgen.py ├── policygen.py └── statsgen.py ├── config.json.example ├── hashcat-utils ├── CHANGES ├── LICENSE ├── README.md └── bin │ ├── cleanup-rules.app │ ├── cleanup-rules.bin │ ├── cleanup-rules.exe │ ├── combinator.app │ ├── combinator.bin │ ├── combinator.exe │ ├── combinator3.app │ ├── combinator3.bin │ ├── combinator3.exe │ ├── combipow.app │ ├── combipow.bin │ ├── combipow.exe │ ├── cutb.app │ ├── cutb.bin │ ├── cutb.exe │ ├── expander.app │ ├── expander.bin │ ├── expander.exe │ ├── gate.app │ ├── gate.bin │ ├── gate.exe │ ├── generate-rules.app │ ├── generate-rules.bin │ ├── generate-rules.exe │ ├── hcstatgen.app │ ├── hcstatgen.bin │ ├── hcstatgen.exe │ ├── keyspace.app │ ├── keyspace.bin │ ├── keyspace.exe │ ├── len.app │ ├── len.bin │ ├── len.exe │ ├── mli2.app │ ├── mli2.bin │ ├── mli2.exe │ ├── morph.app │ ├── morph.bin │ ├── morph.exe │ ├── permute.app │ ├── permute.bin │ ├── permute.exe │ ├── permute_exist.app │ ├── permute_exist.bin │ ├── permute_exist.exe │ ├── prepare.app │ ├── prepare.bin │ ├── prepare.exe │ ├── req-exclude.app │ ├── req-exclude.bin │ ├── req-exclude.exe │ ├── req-include.app │ ├── req-include.bin │ ├── req-include.exe │ ├── rli.app │ ├── rli.bin │ ├── rli.exe │ ├── rli2.app │ ├── rli2.bin │ ├── rli2.exe │ ├── seprule.pl │ ├── splitlen.app │ ├── splitlen.bin │ ├── splitlen.exe │ ├── strip-bsn.app │ ├── strip-bsn.bin │ ├── strip-bsn.exe │ ├── strip-bsr.app │ ├── strip-bsr.bin │ ├── strip-bsr.exe │ ├── tmesis.pl │ └── topmorph.pl ├── hate_crack.py ├── masks ├── masks_10.hcmask ├── masks_8.hcmask ├── masks_9.hcmask └── pathwell.hcmask ├── princeprocessor ├── CHANGES ├── LICENSE ├── README.md ├── pp.save ├── pp64.app ├── pp64.bin ├── pp64.exe └── rules │ ├── prince_generated.rule │ └── prince_optimized.rule ├── pyproject.toml ├── readme.md ├── rules └── toggles-lm-ntlm.rule └── wordlist_optimizer.py /.gitignore: -------------------------------------------------------------------------------- 1 | config.json 2 | hashcat.pot 3 | -------------------------------------------------------------------------------- /PACK/ChangeLog: -------------------------------------------------------------------------------- 1 | PACK 0.0.4 August 8, 2013 2 | ------------------------- 3 | 4 | * Rewrote maskgen to generate optimized masks in addition to custom parameters. 5 | * Rewrote policygen to generate non-compliant masks. 6 | * Rewrote rulegen to use multiple processes for significant speed improvements on multi-core systems. 7 | * Renamed dictstat to statsgen and removed all regular expressions for performance enhancements. 8 | * Rewrote statsgen to attempt policy detection. -------------------------------------------------------------------------------- /PACK/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Peter Kacherginsky 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | Neither the name of the 'The Sprawl' nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /PACK/README: -------------------------------------------------------------------------------- 1 | Password Analysis and Cracking Kit by Peter Kacherginsky (iphelix) 2 | ================================================================== 3 | 4 | PACK (Password Analysis and Cracking Toolkit) is a collection of utilities developed to aid in analysis of password lists in order to enhance password cracking through pattern detection of masks, rules, character-sets and other password characteristics. The toolkit generates valid input files for Hashcat family of password crackers. 5 | 6 | NOTE: The toolkit itself is not able to crack passwords, but instead designed to make operation of password crackers more efficient. 7 | 8 | Selecting passwords lists for analysis 9 | ====================================== 10 | 11 | Before we can begin using the toolkit we must establish a selection criteria of password lists. Since we are looking to analyze the way people create their passwords, we must obtain as large of a sample of leaked passwords as possible. One such excellent list is based on RockYou.com compromise. This list both provides large and diverse enough collection that provides a good results for common passwords used by similar sites (e.g. social networking). The analysis obtained from this list may not work for organizations with specific password policies. As such, selecting sample input should be as close to your target as possible. In addition, try to avoid obtaining lists based on already cracked passwords as it will generate statistics bias of rules and masks used by individual(s) cracking the list and not actual users. 12 | 13 | StatsGen 14 | ======================================= 15 | 16 | The most basic analysis that you can perform is simply obtaining most common length, character-set and other characteristics of passwords in the provided list. In the example below, we will use 'rockyou.txt' containing approximately 14 million passwords. Launch `statsgen.py` with the following command line: 17 | 18 | $ python statsgen.py rockyou.txt 19 | 20 | Below is the output from the above command: 21 | 22 | _ 23 | StatsGen #.#.# | | 24 | _ __ __ _ ___| | _ 25 | | '_ \ / _` |/ __| |/ / 26 | | |_) | (_| | (__| < 27 | | .__/ \__,_|\___|_|\_\ 28 | | | 29 | |_| iphelix@thesprawl.org 30 | 31 | 32 | [*] Analyzing passwords in [rockyou.txt] 33 | [+] Analyzing 100% (14344390/14344390) of passwords 34 | NOTE: Statistics below is relative to the number of analyzed passwords, not total number of passwords 35 | 36 | [*] Length: 37 | [+] 8: 20% (2966037) 38 | [+] 7: 17% (2506271) 39 | [+] 9: 15% (2191039) 40 | [+] 10: 14% (2013695) 41 | [+] 6: 13% (1947798) 42 | ... 43 | 44 | [*] Character-set: 45 | [+] loweralphanum: 42% (6074867) 46 | [+] loweralpha: 25% (3726129) 47 | [+] numeric: 16% (2346744) 48 | [+] loweralphaspecialnum: 02% (426353) 49 | [+] upperalphanum: 02% (407431) 50 | ... 51 | 52 | [*] Password complexity: 53 | [+] digit: min(0) max(255) 54 | [+] lower: min(0) max(255) 55 | [+] upper: min(0) max(187) 56 | [+] special: min(0) max(255) 57 | 58 | [*] Simple Masks: 59 | [+] stringdigit: 37% (5339556) 60 | [+] string: 28% (4115314) 61 | [+] digit: 16% (2346744) 62 | [+] digitstring: 04% (663951) 63 | [+] othermask: 04% (576324) 64 | ... 65 | 66 | [*] Advanced Masks: 67 | [+] ?l?l?l?l?l?l?l?l: 04% (687991) 68 | [+] ?l?l?l?l?l?l: 04% (601152) 69 | [+] ?l?l?l?l?l?l?l: 04% (585013) 70 | [+] ?l?l?l?l?l?l?l?l?l: 03% (516830) 71 | [+] ?d?d?d?d?d?d?d: 03% (487429) 72 | ... 73 | 74 | 75 | NOTE: You can reduce the number of outliers displayed by including the --hiderare flag which will not show any items with occurrence of less than 1%. 76 | 77 | Here is what we can immediately learn from the above list: 78 | 79 | * Most of the passwords have length 6 to 10 characters. 80 | * The majority of passwords have loweralphanumeric character-set. 81 | * There is no obvious minimum or maximum password complexity. 82 | * Analyzed passwords tend to follow a simple masks "string followed by digits". 83 | 84 | The last section, "Advanced Masks", contains most frequently occurring masks using the Hashcat format. Individual symbols can be interpreted as follows: 85 | 86 | ?l - a single lowercase character 87 | ?u - a single uppercase character 88 | ?d - a single digit 89 | ?s - a single special character 90 | 91 | For example, the very first mask, "?l?l?l?l?l?l?l?l", will match all of the lowercase alpha passwords. Given the sample size you will be able to crack approximately 4% of passwords. However, after generating the initial output, you may be interested in using filters to narrow down on password data. 92 | 93 | Using filters 94 | ------------- 95 | 96 | Let's see how RockYou users tend to select their passwords using the "stringdigit" simple mask (a string followed by numbers): 97 | 98 | $ python statsgen.py ../PACK-0.0.3/archive/rockyou.txt --simplemask stringdigit -q --hiderare 99 | 100 | [*] Analyzing passwords in [rockyou.txt] 101 | [+] Analyzing 37% (5339556/14344390) of passwords 102 | NOTE: Statistics below is relative to the number of analyzed passwords, not total number of passwords 103 | 104 | [*] Length: 105 | [+] 8: 23% (1267260) 106 | [+] 7: 18% (981432) 107 | [+] 9: 17% (939971) 108 | [+] 10: 14% (750938) 109 | [+] 6: 11% (618983) 110 | [+] 11: 05% (294869) 111 | [+] 12: 03% (175875) 112 | [+] 13: 01% (103047) 113 | [+] 14: 01% (65958) 114 | 115 | [*] Character-set: 116 | [+] loweralphanum: 88% (4720184) 117 | [+] upperalphanum: 06% (325941) 118 | [+] mixedalphanum: 05% (293431) 119 | 120 | [*] Password complexity: 121 | [+] digit: min(1) max(252) 122 | [+] lower: min(0) max(46) 123 | [+] upper: min(0) max(31) 124 | [+] special: min(0) max(0) 125 | 126 | [*] Simple Masks: 127 | [+] stringdigit: 100% (5339556) 128 | 129 | [*] Advanced Masks: 130 | [+] ?l?l?l?l?l?l?d?d: 07% (420318) 131 | [+] ?l?l?l?l?l?d?d: 05% (292306) 132 | [+] ?l?l?l?l?l?l?l?d?d: 05% (273624) 133 | [+] ?l?l?l?l?d?d?d?d: 04% (235360) 134 | [+] ?l?l?l?l?d?d: 04% (215074) 135 | ... 136 | 137 | The very top of the output specifies what percentage of total passwords was analyzed. In this case, by cracking only passwords matching the "stringdigit" mask it is only possible to recover about 37% of the total set just as was displayed in the original output. Next, it appears that only 11% of this password type use anything other than lowercase. So it would be smart to concentrate on only lowercase strings matching this mask. At last, in the "Advanced Mask" section we can see that the majority of "stringdigit" passwords consist of a string with two or four digits following it. With the information gained from the above output, we can begin creating a mental image of target users' password generation patterns. 138 | 139 | There are a few other filters available for password length, mask, and character sets: 140 | 141 | **Length:** --minlength and/or --maxlength 142 | 143 | **Simple Mask:** --simplemask [numeric, loweralpha, upperalpha, mixedalpha, loweralphanum, etc.] 144 | 145 | **Character sets:** --charset [digit, string, stringdigit, digitstring, digitstringdigit, etc.] 146 | 147 | NOTE: More than one filter of the same class can be specified as a comma-separated list: 148 | 149 | --simplemask="stringdigit,digitstring" 150 | 151 | Saving advanced masks 152 | --------------------- 153 | 154 | While the "Advanced Mask" section only displays patterns matching greater than 1% of all passwords, you can obtain and save a full list of password masks matching a given dictionary by using the following command: 155 | 156 | $ python statsgen.py rockyou.txt -o rockyou.masks 157 | 158 | All of the password masks and their frequencies will be saved into the specified file in the CSV format. Naturally, you can provide filters to only generate masks file matching specified parameters. The output file can be used as an input to MaskGen tool covered in the next section. 159 | 160 | MaskGen 161 | ================== 162 | 163 | MaskGen allows you to craft pattern-based mask attacks for input into Hashcat family of password crackers. The tool uses output produced by statsgen above with the '-o' flag in order to produce the most optimal mask attack sorted by mask complexity, mask occurrence or ratio of the two (optimal index). 164 | 165 | Let's run MaskGen with only StatGen's output as an argument: 166 | 167 | $ python maskgen.py rockyou.masks 168 | 169 | _ 170 | MaskGen #.#.# | | 171 | _ __ __ _ ___| | _ 172 | | '_ \ / _` |/ __| |/ / 173 | | |_) | (_| | (__| < 174 | | .__/ \__,_|\___|_|\_\ 175 | | | 176 | |_| iphelix@thesprawl.org 177 | 178 | 179 | [*] Analyzing masks in [rockyou.masks] 180 | [*] Using 1,000,000,000 keys/sec for calculations. 181 | [*] Sorting masks by their [optindex]. 182 | [*] Finished generating masks: 183 | Masks generated: 146578 184 | Masks coverage: 100% (14344390/14344390) 185 | Masks runtime: >1 year 186 | 187 | There are several pieces of information that you should observe: 188 | 189 | * Default cracking speed used for calculations is 1,000,000,000 keys/sec 190 | * Default sorting mode is [optindex] equivalent to --optindex flag. 191 | * 146,578 unique masks were generated which have 100% coverage 192 | * Total runtime of all generated masks is more than 1 year. 193 | 194 | Specifying target time 195 | ---------------------- 196 | 197 | Since you are usually limited in time to perform and craft attacks, maskgen allows you to specify how much time you have to perform mask attacks and will generate the most optimal collection of masks based on the sorting mode. Let's play a bit with different sorting modes and target times: 198 | 199 | $ python maskgen.py rockyou.masks --targettime 600 --optindex -q 200 | [*] Analyzing masks in [rockyou.masks] 201 | [*] Using 1,000,000,000 keys/sec for calculations. 202 | [*] Sorting masks by their [optindex]. 203 | [!] Target time exceeded. 204 | [*] Finished generating masks: 205 | Masks generated: 779 206 | Masks coverage: 56% (8116195/14344390) 207 | Masks runtime: 0:11:36 208 | 209 | 210 | $ python maskgen.py rockyou.masks --targettime 600 --complexity -q 211 | [*] Analyzing masks in [rockyou.masks] 212 | [*] Using 1,000,000,000 keys/sec for calculations. 213 | [*] Sorting masks by their [complexity]. 214 | [!] Target time exceeded. 215 | [*] Finished generating masks: 216 | Masks generated: 5163 217 | Masks coverage: 31% (4572346/14344390) 218 | Masks runtime: 0:10:01 219 | 220 | 221 | $ python maskgen.py rockyou.masks --targettime 600 --occurrence -q 222 | [*] Analyzing masks in [rockyou.masks] 223 | [*] Using 1,000,000,000 keys/sec for calculations. 224 | [*] Sorting masks by their [occurrence]. 225 | [!] Target time exceeded. 226 | [*] Finished generating masks: 227 | Masks generated: 4 228 | Masks coverage: 16% (2390986/14344390) 229 | Masks runtime: 1:34:05 230 | 231 | All of the above runs have target time of 600 seconds (or 10 minutes) with different sorting modes. Based on our experiments, masks generated using OptIndex sorting mode can crack 56% of RockYou passwords in about 10 minutes. At the same time masks generated using Occurrence sorting mode not only have pretty weak coverage of only 16%, but also exceeded specified target time by more than an hour. 232 | 233 | NOTE: Masks sorted by complexity can be very effective when attacking policy based lists. 234 | 235 | Let's see some of the masks generated by maskgen in optindex mode using the --showmasks flag: 236 | 237 | $ python maskgen.py rockyou.masks --targettime 43200 --optindex -q --showmasks 238 | [*] Analyzing masks in [rockyou.masks] 239 | [*] Using 1,000,000,000 keys/sec for calculations. 240 | [*] Sorting masks by their [optindex]. 241 | [L:] Mask: [ Occ: ] [ Time: ] 242 | ... 243 | [ 7] ?l?d?s?l?l?d?d [6 ] [ 0:00:00] 244 | [ 8] ?s?l?l?l?l?l?l?s [3480 ] [ 0:05:36] 245 | [ 9] ?l?l?l?l?d?d?d?d?s [1553 ] [ 0:02:30] 246 | [ 8] ?d?l?d?d?d?l?l?l [47 ] [ 0:00:04] 247 | [ 8] ?d?l?l?d?l?d?d?l [47 ] [ 0:00:04] 248 | [ 8] ?d?l?l?d?d?l?d?l [47 ] [ 0:00:04] 249 | [ 8] ?d?l?d?l?d?d?l?l [47 ] [ 0:00:04] 250 | [ 8] ?d?d?l?l?d?l?d?l [47 ] [ 0:00:04] 251 | [ 8] ?d?l?d?d?l?l?l?l [122 ] [ 0:00:11] 252 | [ 8] ?u?u?d?u?d?d?d?d [18 ] [ 0:00:01] 253 | [ 6] ?d?s?s?s?s?s [4 ] [ 0:00:00] 254 | [10] ?l?l?l?l?l?l?l?l?d?d [213109 ] [ 5:48:02] 255 | [!] Target time exceeded. 256 | [*] Finished generating masks: 257 | Masks generated: 3970 258 | Masks coverage: 74% (10620959/14344390) 259 | Masks runtime: 16:10:38 260 | 261 | Displayed masks follow a pretty intuitive format: 262 | 263 | 264 | [ 9] ?l?l?l?l?d?d?d?d?s [1553 ] [ 0:02:30] 265 | \ \ \ \ 266 | \ \_ generated mask \ \_ mask runtime 267 | \ \ 268 | \_ mask length \_ mask occurrence 269 | 270 | 271 | In the above sample you can see some of the logic that goes into mask generation. For example, while '?s?l?l?l?l?l?l?s' mask has one of the longest runtimes in the sample (5 minutes), it still has higher priority because of its relatively higher occurrence to '?l?l?l?l?d?d?d?d?s'. At the same time, while '?l?d?s?l?l?d?d' has pretty low coverage it still gets a higher priority than other masks because as only a six character mask it executes very quickly. 272 | 273 | Specifying mask filters 274 | ----------------------- 275 | 276 | You can further optimize your generated mask attacks by using filters. For example, you may have sufficiently powerful hardware where you can simple bruteforce all of the passwords up to 8 characters. In this case, you can generate masks only greater than 8 characters using the --minlength flag as follows: 277 | 278 | $ python maskgen.py rockyou.masks --targettime 43200 --optindex -q --minlength 8 279 | [*] Analyzing masks in [rockyou.masks] 280 | [*] Using 1,000,000,000 keys/sec for calculations. 281 | [*] Sorting masks by their [optindex]. 282 | [!] Target time exceeded. 283 | [*] Finished generating masks: 284 | Masks generated: 585 285 | Masks coverage: 41% (5905182/14344390) 286 | Masks runtime: 15:50:36 287 | 288 | Naturally the generated mask coverage was reduced, but these filters become useful when preparing a collection of masks when attacking password lists other than the one used to generate them. 289 | 290 | The list below shows additional filters you can use: 291 | 292 | Individual Mask Filter Options: 293 | --minlength=8 Minimum password length 294 | --maxlength=8 Maximum password length 295 | --mintime=3600 Minimum mask runtime (seconds) 296 | --maxtime=3600 Maximum mask runtime (seconds) 297 | --mincomplexity=1 Minimum complexity 298 | --maxcomplexity=100 299 | Maximum complexity 300 | --minoccurrence=1 Minimum occurrence 301 | --maxoccurrence=100 302 | Maximum occurrence 303 | 304 | Occurrrence and complexity flags can be particularly powerful to fine-tune generated masks using different sorting modes. 305 | 306 | Saving generated masks 307 | ---------------------- 308 | 309 | Once you are satisfied with the above generated masks, you can save them using the -o flag: 310 | 311 | $ python maskgen.py rockyou.masks --targettime 43200 --optindex -q -o rockyou.hcmask 312 | [*] Analyzing masks in [rockyou.masks] 313 | [*] Saving generated masks to [rockyou.hcmask] 314 | [*] Using 1,000,000,000 keys/sec for calculations. 315 | [*] Sorting masks by their [optindex]. 316 | [!] Target time exceeded. 317 | [*] Finished generating masks: 318 | Masks generated: 3970 319 | Masks coverage: 74% (10620959/14344390) 320 | Masks runtime: 16:10:38 321 | 322 | This will produce 'rockyou.hcmask' file which can be directly used by Hashcat suite of tools or as part of a custom script that loops through them. 323 | 324 | Checking mask coverage 325 | ---------------------- 326 | 327 | It is often useful to see how well generated masks perform against already cracked lists. Maskgen can compare a collection of masks against others to see how well they would perform if masks from one password list would be attempted against another. Let's compare how well masks generated from RockYou list will perform against another compromised list such as Gawker: 328 | 329 | $ python statsgen.py ../PACK-0.0.3/archive/gawker.dic -o gawker.masks 330 | 331 | $ python maskgen.py gawker.masks --checkmasksfile rockyou.hcmask -q 332 | [*] Analyzing masks in [gawker.masks] 333 | [*] Using 1,000,000,000 keys/sec for calculations. 334 | [*] Checking coverage of masks in [rockyou.hcmask] 335 | [*] Finished matching masks: 336 | Masks matched: 1775 337 | Masks coverage: 96% (1048889/1084394) 338 | Masks runtime: 16:25:44 339 | 340 | Using the '--checkmasksfile' parameter we attempted to run masks inside 'rockyou.hcmask' file generated earlier against masks from a sample leaked list 'gawker.masks'. This results in a good 96% coverage where 1775 of the 3970 total generated RockYou-based masks matched masks in Gawker list. 341 | 342 | It is also possible to see the coverage of one or more masks by specifying them directly on the command-line as follows: 343 | 344 | $ python maskgen.py gawker.masks --checkmasks="?u?l?l?l?l?l?d,?l?l?l?l?l?d?d" -q 345 | [*] Analyzing masks in [gawker.masks] 346 | [*] Using 1,000,000,000 keys/sec for calculations. 347 | [*] Checking coverage of the these masks [?u?l?l?l?l?l?d, ?l?l?l?l?l?d?d] 348 | [*] Finished matching masks: 349 | Masks matched: 2 350 | Masks coverage: 1% (18144/1084394) 351 | Masks runtime: 0:00:04 352 | 353 | Both of the specified masks matched with only 1% coverage. 354 | 355 | Specifying speed 356 | ---------------- 357 | 358 | Depending on your exact hardware specs and target hash you may want to increase or decrease keys/sec speed used during calculations using the '--pps' parameter: 359 | 360 | $ python maskgen.py rockyou.masks --targettime 43200 --pps 50000000 -q 361 | [*] Analyzing masks in [rockyou.masks] 362 | [*] Using 50,000,000 keys/sec for calculations. 363 | [*] Sorting masks by their [optindex]. 364 | [!] Target time exceeded. 365 | [*] Finished generating masks: 366 | Masks generated: 1192 367 | Masks coverage: 61% (8754548/14344390) 368 | Masks runtime: 12:17:31 369 | 370 | Using the '--pps' parameter to match you actual performance makes target time more meaningful. 371 | 372 | PolicyGen 373 | ========= 374 | 375 | A lot of the mask and dictionary attacks will fail in the corporate environment with minimum password complexity requirements. Instead of resorting to a pure bruteforcing attack, we can leverage known or guessed password complexity rules to avoid trying password candidates that are not compliant with the policy or inversely only audit for noncompliant passwords. Using PolicyGen, you will be able to generate a collection of masks following the password complexity in order to significantly reduce the cracking time. 376 | 377 | Below is a sample session where we generate all valid password masks for an environment requiring at least one digit, one upper, and one special characters. 378 | 379 | $ python policygen.py --minlength 8 --maxlength 8 --minlower 1 --minupper 1 --mindigit 1 --minspecial 1 -o complexity.hcmask 380 | _ 381 | PolicyGen #.#.# | | 382 | _ __ __ _ ___| | _ 383 | | '_ \ / _` |/ __| |/ / 384 | | |_) | (_| | (__| < 385 | | .__/ \__,_|\___|_|\_\ 386 | | | 387 | |_| iphelix@thesprawl.org 388 | 389 | 390 | [*] Saving generated masks to [complexity.hcmask] 391 | [*] Using 1,000,000,000 keys/sec for calculations. 392 | [*] Password policy: 393 | Pass Lengths: min:8 max:8 394 | Min strength: l:1 u:1 d:1 s:1 395 | Max strength: l:None u:None d:None s:None 396 | [*] Generating [compliant] masks. 397 | [*] Generating 8 character password masks. 398 | [*] Total Masks: 65536 Time: 76 days, 18:50:04 399 | [*] Policy Masks: 40824 Time: 35 days, 0:33:09 400 | 401 | From the above output you can see that we have generated 40824 masks matching the specified complexity that will take about 35 days to run at the speed of 1,000,000,000 keys/sec. 402 | 403 | In case you are simply performing a password audit and tasked to discover only non-compliant passwords you can specify '--noncompliant' flag to invert generated masks: 404 | 405 | $ python policygen.py --minlength 8 --maxlength 8 --minlower 1 --minupper 1 --mindigit 1 --minspecial 1 -o noncompliant.hcmask -q --noncompliant 406 | [*] Saving generated masks to [noncompliant.hcmask] 407 | [*] Using 1,000,000,000 keys/sec for calculations. 408 | [*] Password policy: 409 | Pass Lengths: min:8 max:8 410 | Min strength: l:1 u:1 d:1 s:1 411 | Max strength: l:None u:None d:None s:None 412 | [*] Generating [non-compliant] masks. 413 | [*] Generating 8 character password masks. 414 | [*] Total Masks: 65536 Time: 76 days, 18:50:04 415 | [*] Policy Masks: 24712 Time: 41 days, 18:16:55 416 | 417 | Let's see some of the non-compliant masks generated above using the '--showmasks' flag: 418 | 419 | $ python policygen.py --minlength 8 --maxlength 8 --minlower 1 --minupper 1 --mindigit 1 --minspecial 1 -o noncompliant.hcmask -q --noncompliant --showmasks 420 | [*] Saving generated masks to [noncompliant.hcmask] 421 | [*] Using 1,000,000,000 keys/sec for calculations. 422 | [*] Password policy: 423 | Pass Lengths: min:8 max:8 424 | Min strength: l:1 u:1 d:1 s:1 425 | Max strength: l:None u:None d:None s:None 426 | [*] Generating [non-compliant] masks. 427 | [*] Generating 8 character password masks. 428 | [ 8] ?d?d?d?d?d?d?d?d [l: 0 u: 0 d: 8 s: 0] [ 0:00:00] 429 | [ 8] ?d?d?d?d?d?d?d?l [l: 1 u: 0 d: 7 s: 0] [ 0:00:00] 430 | [ 8] ?d?d?d?d?d?d?d?u [l: 0 u: 1 d: 7 s: 0] [ 0:00:00] 431 | [ 8] ?d?d?d?d?d?d?d?s [l: 0 u: 0 d: 7 s: 1] [ 0:00:00] 432 | ... 433 | [ 8] ?s?s?s?s?s?s?s?d [l: 0 u: 0 d: 1 s: 7] [ 0:07:06] 434 | [ 8] ?s?s?s?s?s?s?s?l [l: 1 u: 0 d: 0 s: 7] [ 0:18:28] 435 | [ 8] ?s?s?s?s?s?s?s?u [l: 0 u: 1 d: 0 s: 7] [ 0:18:28] 436 | [ 8] ?s?s?s?s?s?s?s?s [l: 0 u: 0 d: 0 s: 8] [ 0:23:26] 437 | [*] Total Masks: 65536 Time: 76 days, 18:50:04 438 | [*] Policy Masks: 24712 Time: 41 days, 18:16:55 439 | 440 | As you can see all of the masks have at least one missing password complexity requirement. Interestingly with fewer generated masks it takes longer to attack because of long running masks like '?s?s?s?s?s?s?s?s'. 441 | 442 | Specifying maximum complexity 443 | ----------------------------- 444 | 445 | It is also possible to specify maximum password complexity using --maxlower, --maxupper, --maxdigit and --maxspecial flags in order to fine-tune you attack. For example, below is a sample site which enforces password policy but does not allow any special characters: 446 | 447 | $ python policygen.py --minlength 8 --maxlength 8 --minlower 1 --minupper 1 --mindigit 1 --maxspecial 0 -o maxcomplexity.hcmask -q 448 | [*] Saving generated masks to [maxcomplexity.hcmask] 449 | [*] Using 1,000,000,000 keys/sec for calculations. 450 | [*] Password policy: 451 | Pass Lengths: min:8 max:8 452 | Min strength: l:1 u:1 d:1 s:None 453 | Max strength: l:None u:None d:None s:0 454 | [*] Generating [compliant] masks. 455 | [*] Generating 8 character password masks. 456 | [*] Total Masks: 65536 Time: 76 days, 18:50:04 457 | [*] Policy Masks: 5796 Time: 1 day, 20:20:55 458 | 459 | Rules Analysis 460 | ================== 461 | 462 | `rulegen.py` implements password analysis and rule generation for the Hashcat password cracker as described in the [Automatic Password Rule Analysis and Generation](http://thesprawl.org/research/automatic-password-rule-analysis-generation/) paper. Please review this document for detailed discussion on the theory of rule analysis and generation. 463 | 464 | Reversing source words and word mangling rules from already cracked passwords can be very effective in performing attacks against still encrypted hashes. By continuously recycling/expanding generated rules and words you may be able to crack a greater number of passwords. 465 | 466 | Prerequisites 467 | ----------------- 468 | There are several prerequisites for the effective use of `rulegen.py`. The tool utilizes Enchant spell-checking library to interface with a number of spell-checking engines such as Aspell, MySpell, etc. You must install these tools prior to use. It is also critical to install dictionaries for whatever spell-checking engine you end up using (alternatively it is possible to use a custom wordlist). At last, I have bundled PyEnchant for convenience which should interface directly with Enchant's shared libraries; however, should there be any issues, simply remove the bundled 'enchant' directory and install PyEnchant for your distribution. 469 | 470 | For additional details on specific Hashcat rule syntax see [Hashcat Rule Based Attack](http://hashcat.net/wiki/doku.php?id=rule_based_attack). 471 | 472 | Analyzing a Single Password 473 | ------------------------------- 474 | 475 | The most basic use of `rulegen.py` involves analysis of a single password to automatically detect rules. Let's detect rules and potential source word used to generate a sample password `P@55w0rd123`: 476 | 477 | $ python rulegen.py --verbose --password P@55w0rd123 478 | _ 479 | RuleGen #.#.# | | 480 | _ __ __ _ ___| | _ 481 | | '_ \ / _` |/ __| |/ / 482 | | |_) | (_| | (__| < 483 | | .__/ \__,_|\___|_|\_\ 484 | | | 485 | |_| iphelix@thesprawl.org 486 | 487 | 488 | [*] Using Enchant 'aspell' module. For best results please install 489 | 'aspell' module language dictionaries. 490 | [*] Analyzing password: P@55w0rd123 491 | [-] Pas sword => {edit distance suboptimal: 8 (7)} => P@55w0rd123 492 | [+] Password => sa@ ss5 so0 $1 $2 $3 => P@55w0rd123 493 | [+] Passwords => sa@ ss5 so0 o81 $2 $3 => P@55w0rd123 494 | [+] Passwords => sa@ ss5 so0 i81 o92 $3 => P@55w0rd123 495 | [+] Passwords => sa@ ss5 so0 i81 i92 oA3 => P@55w0rd123 496 | [+] Password's => sa@ ss5 so0 o81 o92 $3 => P@55w0rd123 497 | [+] Password's => sa@ ss5 so0 o81 i92 oA3 => P@55w0rd123 498 | [+] Password's => sa@ ss5 so0 i81 o92 oA3 => P@55w0rd123 499 | 500 | There are several flags that we have used for this example: 501 | 502 | * --password - specifies a single password to analyze. 503 | * --verbose - prints out verbose information such as generated rules and performance statistics. 504 | 505 | Processing password files is covered in a section below; however, let's first discuss some of the available fine tuning options using a single password as an example. 506 | 507 | Spell-checking provider 508 | --------------------------- 509 | 510 | Notice that we are using the `aspell` Enchant module for source word detection. The exact spell-checking engine can be changed using the `--provider` flag as follows: 511 | 512 | $ python rulegen.py --verbose --provider myspell --password P@55w0rd123 -q 513 | [*] Using Enchant 'myspell' module. For best results please install 514 | 'myspell' module language dictionaries. 515 | ... 516 | 517 | 518 | NOTE: Provider engine priority can be specified using a comma-separated list (e.g. --provider aspell,myspell). 519 | 520 | Forcing source word 521 | ----------------------- 522 | 523 | The use of the source word detection engine can be completely disabled by specifying a source word with the `--word` flag: 524 | 525 | $ python rulegen.py -q --verbose --word word --password P@55w0rd123 526 | [*] Analyzing password: P@55w0rd123 527 | [+] word => ^5 ^5 ^@ ^P so0 $1 $2 $3 => P@55w0rd123 528 | 529 | By specifying different source words you can have a lot of fun experimenting with the rule generation engine. 530 | 531 | Defining Custom Dictionary 532 | ------------------------------ 533 | 534 | Inevitably you will come across a point where generating rules using the standard spelling-engine wordlist is no longer sufficient. You can specify a custom wordlist using the `--wordlist` flag. This is particularly useful when reusing source words from a previous analysis session: 535 | 536 | $ python rulegen.py -q --verbose --wordlist rockyou.txt --password 1pa55w0rd1 537 | [*] Using Enchant 'Personal Wordlist' module. For best results please install 538 | 'Personal Wordlist' module language dictionaries. 539 | [*] Analyzing password: 1pa55w0rd1 540 | [+] password => ^1 ss5 so0 $1 => 1pa55w0rd1 541 | 542 | Custom wordlist can be particularly useful when using not normally found words such as slang as well as using already cracked passwords. 543 | 544 | Generating Suboptimal Rules and Words 545 | ----------------------------------------- 546 | 547 | While `rulegen.py` attempts to generate and record only the best source words and passwords, there may be cases when you are interested in more results. Use `--morewords` and `--morerules` flags to generate words and rules which may exceed optimal edit distance: 548 | 549 | $ python rulegen.py -q --verbose --password '$m0n3y$' --morerules --morewords 550 | [*] Using Enchant 'aspell' module. For best results please install 551 | 'aspell' module language dictionaries. 552 | [*] Analyzing password: $m0n3y$ 553 | [+] money => ^$ so0 se3 $$ => $m0n3y$ 554 | [+] moneys => ^$ so0 se3 o6$ => $m0n3y$ 555 | [+] mingy => ^$ si0 sg3 $$ => $m0n3y$ 556 | [+] many => ^$ sa0 i43 $$ => $m0n3y$ 557 | [+] Mooney => sM$ o1m so0 se3 $$ => $m0n3y$ 558 | 559 | It is possible to further expand generated words using `--maxworddist` and `--maxwords` flags. Similarly, you can produce more rules using `--maxrulelen` and `--maxrules` flags. 560 | 561 | Disabling Advanced Engines 562 | ------------------------------ 563 | 564 | `rulegen.py` includes a number of advanced engines to generate better quality words and rules. It is possible to disable them to observe the difference (or if they are causing issues) using `--simplewords` and `--simplerules` flags. Let's observe how both source words and rules change with these flags on: 565 | 566 | $ python rulegen.py -q --verbose --password '$m0n3y$' --simplewords --simplerules 567 | [*] Using Enchant 'aspell' module. For best results please install 568 | 'aspell' module language dictionaries. 569 | [*] Analyzing password: $m0n3y$ 570 | [-] Meany => {edit distance suboptimal: 5 (4)} => $m0n3y$ 571 | [+] many => i0$ o20 i43 i6$ => $m0n3y$ 572 | [+] mingy => i0$ o20 o43 i6$ => $m0n3y$ 573 | [+] money => i0$ o20 o43 i6$ => $m0n3y$ 574 | [+] mangy => i0$ o20 o43 i6$ => $m0n3y$ 575 | [+] manky => i0$ o20 o43 i6$ => $m0n3y$ 576 | 577 | Notice the quality of generated words and rules was reduced significantly with words like 'manky' having less relationship to the actual source word 'money'. At the same time, generated rules were reduced to simple insertions, deletions and replacements. 578 | 579 | Processing password lists 580 | ----------------------------- 581 | 582 | Now that you have mastered all of the different flags and switches, we can attempt to generate words and rules for a collection of passwords. Let's generate a text file `korelogic.txt` containing the following fairly complex test passwords: 583 | 584 | &~defcon 585 | '#(4)\ 586 | August19681 587 | '&a123456 588 | 10-D'Ann 589 | ~|Bailey 590 | Krist0f3r 591 | f@cebOOK 592 | Nuclear$( 593 | zxcvbn2010! 594 | 13Hark's 595 | NjB3qqm 596 | Sydney93? 597 | antalya%] 598 | Annl05de 599 | ;-Fluffy 600 | 601 | Now let's observe `rulegen.py` analysis by simply specifying the password file as the first argument: 602 | 603 | $ python rulegen.py korelogic.txt -q 604 | [*] Using Enchant 'aspell' module. For best results please install 605 | 'aspell' module language dictionaries. 606 | [*] Analyzing passwords file: korelogic.txt: 607 | [*] Press Ctrl-C to end execution and generate statistical analysis. 608 | [*] Saving rules to analysis.rule 609 | [*] Saving words to analysis.word 610 | [*] Finished processing 16 passwords in 1.00 seconds at the rate of 15.94 p/sec 611 | [*] Generating statistics for [analysis] rules and words. 612 | [-] Skipped 0 all numeric passwords (0.00%) 613 | [-] Skipped 2 passwords with less than 25% alpha characters (12.50%) 614 | [-] Skipped 0 passwords with non ascii characters (0.00%) 615 | 616 | [*] Top 10 rules 617 | [+] ^3 ^1 o4r - 3 (2.00%) 618 | [+] i61 i79 i86 i98 oA1 - 2 (1.00%) 619 | [+] ^- ^0 ^1 i4' o5A - 2 (1.00%) 620 | [+] sS1 i13 T2 - 1 (0.00%) 621 | [+] i61 se9 i86 i98 oA1 - 1 (0.00%) 622 | [+] o61 i79 i86 i98 oA1 - 1 (0.00%) 623 | [+] ^- ^0 ^1 so' i5A - 1 (0.00%) 624 | [+] D3 si0 i55 $e - 1 (0.00%) 625 | [+] i61 i79 se6 i98 oA1 - 1 (0.00%) 626 | [+] i3a o5y o6a i7% o8] - 1 (0.00%) 627 | 628 | [*] Top 10 words 629 | [+] Analyze - 1 (0.00%) 630 | [+] defcon - 1 (0.00%) 631 | [+] Kristen - 1 (0.00%) 632 | [+] Bailey - 1 (0.00%) 633 | [+] Augusts - 1 (0.00%) 634 | [+] Annelid - 1 (0.00%) 635 | [+] Hack's - 1 (0.00%) 636 | [+] antlers - 1 (0.00%) 637 | [+] antelope - 1 (0.00%) 638 | [+] xxxv - 1 (0.00%) 639 | 640 | Using all default settings we were able to produce several high quality rules. The application displays some basic Top 10 rules and words statistics. All of the generated rules and words are saved using basename 'analysis' by default: 641 | 642 | * analysis.word - unsorted and ununiqued source words 643 | * analysis-sorted.word - occurrence sorted and unique source words 644 | * analysis.rule - unsorted and ununiqued rules 645 | * analysis-sorted.rule - occurrence sorted and unique rules 646 | 647 | Notice that several passwords such as '#(4)\ and '&a123456 were skipped because they do not have sufficient characteristics to be processed. Other than alpha character count, the program will skip all numeric passwords and passwords containing non-ASCII characters. The latter is due to a bug in the Enchant engine which I hope to fix in the future thus allowing word processing of many languages. 648 | 649 | Specifying output basename 650 | ------------------------------ 651 | 652 | As previously mentioned `rulegen.py` saves output files using the 'analysis' basename by default. You can change file basename with the `--basename` or `-b` flag as follows: 653 | 654 | $ python rulegen.py korelogic.txt -q -b korelogic 655 | [*] Using Enchant 'aspell' module. For best results please install 656 | 'aspell' module language dictionaries. 657 | [*] Analyzing passwords file: korelogic.txt: 658 | [*] Press Ctrl-C to end execution and generate statistical analysis. 659 | [*] Saving rules to korelogic.rule 660 | [*] Saving words to korelogic.word 661 | 662 | 663 | Debugging rules 664 | -------------------- 665 | 666 | There may be situations where you run into issues generating rules for the Hashcat password cracker. `rulegen.py` includes the `--hashcat` flag to validate generated words and rules using hashcat itself running in --stdout mode. In order for this mode to work correctly, you must download the latest version of hashcat-cli and edit the `HASHCAT_PATH` variable in the source. For example, at the time of this writing I have placed the hashcat-0.## folder in the PACK directory and defined `HASHCAT_PATH` as 'hashcat-0.##/'. 667 | 668 | You can also observe the inner workings of the rule generation engine with the `--debug` flag. Don't worry about messages of certain rule failings, this is the result of the halting problem solver trying to find an optimal and valid solution. 669 | 670 | Conclusion 671 | ============== 672 | 673 | While this guide introduces a number of methods to analyze passwords, reverse rules and generate masks, there are a number of other tricks that are waiting for you to discover. I would be excited if you told me about some unusual use or suggestions for any of the covered tools. 674 | 675 | Happy Cracking! 676 | 677 | -Peter -------------------------------------------------------------------------------- /PACK/maskgen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # MaskGen - Generate Password Masks 3 | # 4 | # This tool is part of PACK (Password Analysis and Cracking Kit) 5 | # 6 | # VERSION 0.0.3 7 | # 8 | # Copyright (C) 2013 Peter Kacherginsky 9 | # All rights reserved. 10 | # 11 | # Please see the attached LICENSE file for additional licensing information. 12 | 13 | import sys 14 | import csv 15 | import datetime 16 | from operator import itemgetter 17 | from optparse import OptionParser, OptionGroup 18 | 19 | VERSION = "0.0.3" 20 | 21 | 22 | class MaskGen: 23 | def __init__(self): 24 | # Masks collections with meta data 25 | self.masks = dict() 26 | 27 | self.target_time = None 28 | self.output_file = None 29 | 30 | self.minlength = None 31 | self.maxlength = None 32 | self.mintime = None 33 | self.maxtime = None 34 | self.mincomplexity = None 35 | self.maxcomplexity = None 36 | self.minoccurrence = None 37 | self.maxoccurrence = None 38 | 39 | self.customcharset1len = None 40 | self.customcharset2len = None 41 | self.customcharset3len = None 42 | self.customcharset4len = None 43 | 44 | # PPS (Passwords per Second) Cracking Speed 45 | self.pps = 1000000000 46 | self.showmasks = False 47 | 48 | # Counter for total masks coverage 49 | self.total_occurrence = 0 50 | 51 | def getcomplexity(self, mask): 52 | """ Return mask complexity. """ 53 | count = 1 54 | for char in mask[1:].split("?"): 55 | if char == "l": 56 | count *= 26 57 | elif char == "u": 58 | count *= 26 59 | elif char == "d": 60 | count *= 10 61 | elif char == "s": 62 | count *= 33 63 | elif char == "a": 64 | count *= 95 65 | elif char == "b": 66 | count *= 256 67 | elif char == "h": 68 | count *= 16 69 | elif char == "H": 70 | count *= 16 71 | elif char == "1" and self.customcharset1len: 72 | count *= self.customcharset1len 73 | elif char == "2" and self.customcharset2len: 74 | count *= self.customcharset2len 75 | elif char == "3" and self.customcharset3len: 76 | count *= self.customcharset3len 77 | elif char == "4" and self.customcharset4len: 78 | count *= self.customcharset4len 79 | else: 80 | print("[!] Error, unknown mask ?%s in a mask %s" % 81 | (char, mask)) 82 | 83 | return count 84 | 85 | def loadmasks(self, filename): 86 | """ Load masks and apply filters. """ 87 | maskReader = csv.reader( 88 | open(args[0], 'r'), delimiter=',', quotechar='"') 89 | 90 | for (mask, occurrence) in maskReader: 91 | 92 | if mask == "": 93 | continue 94 | 95 | mask_occurrence = int(occurrence) 96 | mask_length = len(mask)/2 97 | mask_complexity = self.getcomplexity(mask) 98 | mask_time = mask_complexity/self.pps 99 | 100 | self.total_occurrence += mask_occurrence 101 | 102 | # Apply filters based on occurrence, length, complexity and time 103 | if (self.minoccurrence == None or mask_occurrence >= self.minoccurrence) and \ 104 | (self.maxoccurrence == None or mask_occurrence <= self.maxoccurrence) and \ 105 | (self.mincomplexity == None or mask_complexity >= self.mincomplexity) and \ 106 | (self.maxcomplexity == None or mask_complexity <= self.maxcomplexity) and \ 107 | (self.mintime == None or mask_time >= self.mintime) and \ 108 | (self.maxtime == None or mask_time <= self.maxtime) and \ 109 | (self.maxlength == None or mask_length <= self.maxlength) and \ 110 | (self.minlength == None or mask_length >= self.minlength): 111 | 112 | self.masks[mask] = dict() 113 | self.masks[mask]['length'] = mask_length 114 | self.masks[mask]['occurrence'] = mask_occurrence 115 | self.masks[mask]['complexity'] = 1 - mask_complexity 116 | self.masks[mask]['time'] = mask_time 117 | self.masks[mask]['optindex'] = 1 - \ 118 | mask_complexity/mask_occurrence 119 | 120 | def generate_masks(self, sorting_mode): 121 | """ Generate optimal password masks sorted by occurrence, complexity or optindex """ 122 | sample_count = 0 123 | sample_time = 0 124 | sample_occurrence = 0 125 | 126 | # TODO Group by time here 1 minutes, 1 hour, 1 day, 1 month, 1 year.... 127 | # Group by length 1,2,3,4,5,6,7,8,9,10.... 128 | # Group by occurrence 10%, 20%, 30%, 40%, 50%.... 129 | 130 | if self.showmasks: 131 | print("[L:] Mask: [ Occ: ] [ Time: ]") 132 | for mask in sorted(list(self.masks.keys()), key=lambda mask: self.masks[mask][sorting_mode], reverse=True): 133 | 134 | if self.showmasks: 135 | time_human = ">1 year" if self.masks[mask]['time'] > 60*60*24*365 else str( 136 | datetime.timedelta(seconds=self.masks[mask]['time'])) 137 | print("[{:>2}] {:<30} [{:<7}] [{:>8}] ".format( 138 | self.masks[mask]['length'], mask, self.masks[mask]['occurrence'], time_human)) 139 | 140 | if self.output_file: 141 | self.output_file.write("%s\n" % mask) 142 | 143 | sample_occurrence += self.masks[mask]['occurrence'] 144 | sample_time += self.masks[mask]['time'] 145 | sample_count += 1 146 | 147 | if self.target_time and sample_time > self.target_time: 148 | print("[!] Target time exceeded.") 149 | break 150 | 151 | print("[*] Finished generating masks:") 152 | print(" Masks generated: %s" % sample_count) 153 | print(" Masks coverage: %d%% (%d/%d)" % (sample_occurrence*100 / 154 | self.total_occurrence, sample_occurrence, self.total_occurrence)) 155 | time_human = ">1 year" if sample_time > 60*60*24 * \ 156 | 365 else str(datetime.timedelta(seconds=sample_time)) 157 | print(" Masks runtime: %s" % time_human) 158 | 159 | def getmaskscoverage(self, checkmasks): 160 | 161 | sample_count = 0 162 | sample_occurrence = 0 163 | 164 | total_complexity = 0 165 | 166 | if self.showmasks: 167 | print("[L:] Mask: [ Occ: ] [ Time: ]") 168 | for mask in checkmasks: 169 | mask = mask.strip() 170 | mask_complexity = self.getcomplexity(mask) 171 | 172 | total_complexity += mask_complexity 173 | 174 | if mask in self.masks: 175 | 176 | if self.showmasks: 177 | time_human = ">1 year" if self.masks[mask]['time'] > 60*60*24*365 else str( 178 | datetime.timedelta(seconds=self.masks[mask]['time'])) 179 | print("[{:>2}] {:<30} [{:<7}] [{:>8}] ".format( 180 | self.masks[mask]['length'], mask, self.masks[mask]['occurrence'], time_human)) 181 | 182 | if self.output_file: 183 | self.output_file.write("%s\n" % mask) 184 | 185 | sample_occurrence += self.masks[mask]['occurrence'] 186 | sample_count += 1 187 | 188 | if self.target_time and total_complexity/self.pps > self.target_time: 189 | print("[!] Target time exceeded.") 190 | break 191 | 192 | # TODO: Something wrong here, complexity and time doesn't match with estimated from policygen 193 | total_time = total_complexity/self.pps 194 | time_human = ">1 year" if total_time > 60*60*24 * \ 195 | 365 else str(datetime.timedelta(seconds=total_time)) 196 | print("[*] Finished matching masks:") 197 | print(" Masks matched: %s" % sample_count) 198 | print(" Masks coverage: %d%% (%d/%d)" % (sample_occurrence*100 / 199 | self.total_occurrence, sample_occurrence, self.total_occurrence)) 200 | print(" Masks runtime: %s" % time_human) 201 | 202 | 203 | if __name__ == "__main__": 204 | 205 | header = " _ \n" 206 | header += " MaskGen %s | |\n" % VERSION 207 | header += " _ __ __ _ ___| | _\n" 208 | header += " | '_ \ / _` |/ __| |/ /\n" 209 | header += " | |_) | (_| | (__| < \n" 210 | header += " | .__/ \__,_|\___|_|\_\\\n" 211 | header += " | | \n" 212 | header += " |_| iphelix@thesprawl.org\n" 213 | header += "\n" 214 | 215 | parser = OptionParser( 216 | "%prog pass0.masks [pass1.masks ...] [options]", version="%prog "+VERSION) 217 | 218 | parser.add_option("-t", "--targettime", dest="target_time", type="int", 219 | metavar="86400", help="Target time of all masks (seconds)") 220 | parser.add_option("-o", "--outputmasks", dest="output_masks", 221 | metavar="masks.hcmask", help="Save masks to a file") 222 | 223 | filters = OptionGroup(parser, "Individual Mask Filter Options") 224 | filters.add_option("--minlength", dest="minlength", 225 | type="int", metavar="8", help="Minimum password length") 226 | filters.add_option("--maxlength", dest="maxlength", 227 | type="int", metavar="8", help="Maximum password length") 228 | filters.add_option("--mintime", dest="mintime", type="int", 229 | metavar="3600", help="Minimum mask runtime (seconds)") 230 | filters.add_option("--maxtime", dest="maxtime", type="int", 231 | metavar="3600", help="Maximum mask runtime (seconds)") 232 | filters.add_option("--mincomplexity", dest="mincomplexity", 233 | type="int", metavar="1", help="Minimum complexity") 234 | filters.add_option("--maxcomplexity", dest="maxcomplexity", 235 | type="int", metavar="100", help="Maximum complexity") 236 | filters.add_option("--minoccurrence", dest="minoccurrence", 237 | type="int", metavar="1", help="Minimum occurrence") 238 | filters.add_option("--maxoccurrence", dest="maxoccurrence", 239 | type="int", metavar="100", help="Maximum occurrence") 240 | parser.add_option_group(filters) 241 | 242 | sorting = OptionGroup(parser, "Mask Sorting Options") 243 | sorting.add_option("--optindex", action="store_true", dest="optindex", 244 | help="sort by mask optindex (default)", default=False) 245 | sorting.add_option("--occurrence", action="store_true", dest="occurrence", 246 | help="sort by mask occurrence", default=False) 247 | sorting.add_option("--complexity", action="store_true", dest="complexity", 248 | help="sort by mask complexity", default=False) 249 | parser.add_option_group(sorting) 250 | 251 | coverage = OptionGroup(parser, "Check mask coverage") 252 | coverage.add_option("--checkmasks", dest="checkmasks", 253 | help="check mask coverage", metavar="?u?l?l?l?l?l?d,?l?l?l?l?l?d?d") 254 | coverage.add_option("--checkmasksfile", dest="checkmasks_file", 255 | help="check mask coverage in a file", metavar="masks.hcmask") 256 | parser.add_option_group(coverage) 257 | 258 | parser.add_option("--showmasks", dest="showmasks", 259 | help="Show matching masks", action="store_true", default=False) 260 | 261 | custom = OptionGroup(parser, "Custom charater set options") 262 | custom.add_option("--custom-charset1-len", dest="customcharset1len", 263 | type="int", metavar="26", help="Length of cutom character set 1") 264 | custom.add_option("--custom-charset2-len", dest="customcharset2len", 265 | type="int", metavar="26", help="Length of cutom character set 2") 266 | custom.add_option("--custom-charset3-len", dest="customcharset3len", 267 | type="int", metavar="26", help="Length of cutom character set 3") 268 | custom.add_option("--custom-charset4-len", dest="customcharset4len", 269 | type="int", metavar="26", help="Length of cutom character set 4") 270 | parser.add_option_group(custom) 271 | 272 | misc = OptionGroup(parser, "Miscellaneous options") 273 | misc.add_option("--pps", dest="pps", help="Passwords per Second", 274 | type="int", metavar="1000000000") 275 | misc.add_option("-q", "--quiet", action="store_true", 276 | dest="quiet", default=False, help="Don't show headers.") 277 | parser.add_option_group(misc) 278 | 279 | (options, args) = parser.parse_args() 280 | 281 | # Print program header 282 | if not options.quiet: 283 | print(header) 284 | 285 | if len(args) < 1: 286 | parser.error( 287 | "no masks file specified! Please provide statsgen output.") 288 | exit(1) 289 | 290 | print("[*] Analyzing masks in [%s]" % args[0]) 291 | 292 | maskgen = MaskGen() 293 | 294 | # Settings 295 | if options.target_time: 296 | maskgen.target_time = options.target_time 297 | if options.output_masks: 298 | print("[*] Saving generated masks to [%s]" % options.output_masks) 299 | maskgen.output_file = open(options.output_masks, 'w') 300 | 301 | # Filters 302 | if options.minlength: 303 | maskgen.minlength = options.minlength 304 | if options.maxlength: 305 | maskgen.maxlength = options.maxlength 306 | if options.mintime: 307 | maskgen.mintime = options.mintime 308 | if options.maxtime: 309 | maskgen.maxtime = options.maxtime 310 | if options.mincomplexity: 311 | maskgen.mincomplexity = options.mincomplexity 312 | if options.maxcomplexity: 313 | maskgen.maxcomplexity = options.maxcomplexity 314 | if options.minoccurrence: 315 | maskgen.minoccurrence = options.minoccurrence 316 | if options.maxoccurrence: 317 | maskgen.maxoccurrence = options.maxoccurrence 318 | 319 | # Custom 320 | if options.customcharset1len: 321 | maskgen.customcharset1len = options.customcharset1len 322 | if options.customcharset2len: 323 | maskgen.customcharset2len = options.customcharset2len 324 | if options.customcharset3len: 325 | maskgen.customcharset3len = options.customcharset3len 326 | if options.customcharset4len: 327 | maskgen.customcharset4len = options.customcharset4len 328 | 329 | # Misc 330 | if options.pps: 331 | maskgen.pps = options.pps 332 | if options.showmasks: 333 | maskgen.showmasks = options.showmasks 334 | 335 | print("[*] Using {:,d} keys/sec for calculations.".format(maskgen.pps)) 336 | 337 | # Load masks 338 | for arg in args: 339 | maskgen.loadmasks(arg) 340 | 341 | # Matching masks from the command-line 342 | if options.checkmasks: 343 | checkmasks = [m.strip() for m in options.checkmasks.split(',')] 344 | print("[*] Checking coverage of the these masks [%s]" % 345 | ", ".join(checkmasks)) 346 | maskgen.getmaskscoverage(checkmasks) 347 | 348 | # Matching masks from a file 349 | elif options.checkmasks_file: 350 | checkmasks_file = open(options.checkmasks_file, 'r') 351 | print("[*] Checking coverage of masks in [%s]" % 352 | options.checkmasks_file) 353 | maskgen.getmaskscoverage(checkmasks_file) 354 | 355 | # Printing masks in a file 356 | else: 357 | # Process masks according to specified sorting algorithm 358 | if options.occurrence: 359 | sorting_mode = "occurrence" 360 | elif options.complexity: 361 | sorting_mode = "complexity" 362 | else: 363 | sorting_mode = "optindex" 364 | 365 | print("[*] Sorting masks by their [%s]." % sorting_mode) 366 | maskgen.generate_masks(sorting_mode) 367 | -------------------------------------------------------------------------------- /PACK/policygen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # PolicyGen - Analyze and Generate password masks according to a password policy 3 | # 4 | # This tool is part of PACK (Password Analysis and Cracking Kit) 5 | # 6 | # VERSION 0.0.2 7 | # 8 | # Copyright (C) 2013 Peter Kacherginsky 9 | # All rights reserved. 10 | # 11 | # Please see the attached LICENSE file for additional licensing information. 12 | 13 | import sys 14 | import string 15 | import random 16 | import datetime 17 | from optparse import OptionParser, OptionGroup 18 | import itertools 19 | 20 | VERSION = "0.0.2" 21 | 22 | 23 | class PolicyGen: 24 | def __init__(self): 25 | self.output_file = None 26 | 27 | self.minlength = 8 28 | self.maxlength = 8 29 | self.mindigit = None 30 | self.minlower = None 31 | self.minupper = None 32 | self.minspecial = None 33 | self.maxdigit = None 34 | self.maxlower = None 35 | self.maxupper = None 36 | self.maxspecial = None 37 | 38 | # PPS (Passwords per Second) Cracking Speed 39 | self.pps = 1000000000 40 | self.showmasks = False 41 | 42 | def getcomplexity(self, mask): 43 | """ Return mask complexity. """ 44 | count = 1 45 | for char in mask[1:].split("?"): 46 | if char == "l": 47 | count *= 26 48 | elif char == "u": 49 | count *= 26 50 | elif char == "d": 51 | count *= 10 52 | elif char == "s": 53 | count *= 33 54 | elif char == "a": 55 | count *= 95 56 | else: 57 | print() 58 | "[!] Error, unknown mask ?%s in a mask %s" % (char, mask) 59 | 60 | return count 61 | 62 | def generate_masks(self, noncompliant): 63 | """ Generate all possible password masks matching the policy """ 64 | 65 | total_count = 0 66 | sample_count = 0 67 | 68 | # NOTE: It is better to collect total complexity 69 | # not to lose precision when dividing by pps 70 | total_complexity = 0 71 | sample_complexity = 0 72 | 73 | # TODO: Randomize or even statistically arrange matching masks 74 | for length in range(self.minlength, self.maxlength + 1): 75 | print() 76 | "[*] Generating %d character password masks." % length 77 | total_length_count = 0 78 | sample_length_count = 0 79 | 80 | total_length_complexity = 0 81 | sample_length_complexity = 0 82 | 83 | for masklist in itertools.product(['?d', '?l', '?u', '?s'], repeat=length): 84 | 85 | mask = ''.join(masklist) 86 | 87 | lowercount = 0 88 | uppercount = 0 89 | digitcount = 0 90 | specialcount = 0 91 | 92 | mask_complexity = self.getcomplexity(mask) 93 | 94 | total_length_count += 1 95 | total_length_complexity += mask_complexity 96 | 97 | # Count charachter types in a mask 98 | for char in mask[1:].split("?"): 99 | if char == "l": 100 | lowercount += 1 101 | elif char == "u": 102 | uppercount += 1 103 | elif char == "d": 104 | digitcount += 1 105 | elif char == "s": 106 | specialcount += 1 107 | 108 | # Filter according to password policy 109 | # NOTE: Perform exact opposite (XOR) operation if noncompliant 110 | # flag was set when calling the function. 111 | if ((self.minlower == None or lowercount >= self.minlower) and 112 | (self.maxlower == None or lowercount <= self.maxlower) and 113 | (self.minupper == None or uppercount >= self.minupper) and 114 | (self.maxupper == None or uppercount <= self.maxupper) and 115 | (self.mindigit == None or digitcount >= self.mindigit) and 116 | (self.maxdigit == None or digitcount <= self.maxdigit) and 117 | (self.minspecial == None or specialcount >= self.minspecial) and 118 | (self.maxspecial == None or specialcount <= self.maxspecial)) ^ noncompliant: 119 | 120 | sample_length_count += 1 121 | sample_length_complexity += mask_complexity 122 | 123 | if self.showmasks: 124 | mask_time = mask_complexity / self.pps 125 | time_human = ">1 year" if mask_time > 60 * 60 * 24 * 365 else str( 126 | datetime.timedelta(seconds=mask_time)) 127 | print("[{:>2}] {:<30} [l:{:>2} u:{:>2} d:{:>2} s:{:>2}] [{:>8}] ".format(length, mask, lowercount, 128 | uppercount, digitcount, 129 | specialcount, time_human)) 130 | 131 | if self.output_file: 132 | self.output_file.write("%s\n" % mask) 133 | 134 | total_count += total_length_count 135 | sample_count += sample_length_count 136 | 137 | total_complexity += total_length_complexity 138 | sample_complexity += sample_length_complexity 139 | 140 | total_time = total_complexity / self.pps 141 | total_time_human = ">1 year" if total_time > 60 * 60 * 24 * \ 142 | 365 else str(datetime.timedelta(seconds=total_time)) 143 | print("[*] Total Masks: %d Time: %s" % (total_count, total_time_human)) 144 | 145 | sample_time = sample_complexity / self.pps 146 | sample_time_human = ">1 year" if sample_time > 60 * 60 * 24 * 365 else str( 147 | datetime.timedelta(seconds=sample_time)) 148 | print("[*] Policy Masks: %d Time: %s" % (sample_count, sample_time_human)) 149 | 150 | 151 | if __name__ == "__main__": 152 | 153 | header = " _ \n" 154 | header += " PolicyGen %s | |\n" % VERSION 155 | header += " _ __ __ _ ___| | _\n" 156 | header += " | '_ \ / _` |/ __| |/ /\n" 157 | header += " | |_) | (_| | (__| < \n" 158 | header += " | .__/ \__,_|\___|_|\_\\\n" 159 | header += " | | \n" 160 | header += " |_| iphelix@thesprawl.org\n" 161 | header += "\n" 162 | 163 | # parse command line arguments 164 | parser = OptionParser( 165 | "%prog [options]\n\nType --help for more options", version="%prog " + VERSION) 166 | parser.add_option("-o", "--outputmasks", dest="output_masks", 167 | help="Save masks to a file", metavar="masks.hcmask") 168 | parser.add_option("--pps", dest="pps", help="Passwords per Second", 169 | type="int", metavar="1000000000") 170 | parser.add_option("--showmasks", dest="showmasks", 171 | help="Show matching masks", action="store_true", default=False) 172 | parser.add_option("--noncompliant", dest="noncompliant", help="Generate masks for noncompliant passwords", 173 | action="store_true", default=False) 174 | 175 | group = OptionGroup(parser, "Password Policy", 176 | "Define the minimum (or maximum) password strength policy that you would like to test") 177 | group.add_option("--minlength", dest="minlength", type="int", metavar="8", default=8, 178 | help="Minimum password length") 179 | group.add_option("--maxlength", dest="maxlength", type="int", metavar="8", default=8, 180 | help="Maximum password length") 181 | group.add_option("--mindigit", dest="mindigit", type="int", 182 | metavar="1", help="Minimum number of digits") 183 | group.add_option("--minlower", dest="minlower", type="int", metavar="1", 184 | help="Minimum number of lower-case characters") 185 | group.add_option("--minupper", dest="minupper", type="int", metavar="1", 186 | help="Minimum number of upper-case characters") 187 | group.add_option("--minspecial", dest="minspecial", type="int", metavar="1", 188 | help="Minimum number of special characters") 189 | group.add_option("--maxdigit", dest="maxdigit", type="int", 190 | metavar="3", help="Maximum number of digits") 191 | group.add_option("--maxlower", dest="maxlower", type="int", metavar="3", 192 | help="Maximum number of lower-case characters") 193 | group.add_option("--maxupper", dest="maxupper", type="int", metavar="3", 194 | help="Maximum number of upper-case characters") 195 | group.add_option("--maxspecial", dest="maxspecial", type="int", metavar="3", 196 | help="Maximum number of special characters") 197 | parser.add_option_group(group) 198 | 199 | parser.add_option("-q", "--quiet", action="store_true", 200 | dest="quiet", default=False, help="Don't show headers.") 201 | 202 | (options, args) = parser.parse_args() 203 | 204 | # Print program header 205 | if not options.quiet: 206 | print() 207 | header 208 | 209 | policygen = PolicyGen() 210 | 211 | # Settings 212 | if options.output_masks: 213 | print("[*] Saving generated masks to [%s]" % options.output_masks) 214 | policygen.output_file = open(options.output_masks, 'w') 215 | 216 | # Password policy 217 | if options.minlength != None: 218 | policygen.minlength = options.minlength 219 | if options.maxlength != None: 220 | policygen.maxlength = options.maxlength 221 | if options.mindigit != None: 222 | policygen.mindigit = options.mindigit 223 | if options.minlower != None: 224 | policygen.minlower = options.minlower 225 | if options.minupper != None: 226 | policygen.minupper = options.minupper 227 | if options.minspecial != None: 228 | policygen.minspecial = options.minspecial 229 | if options.maxdigit != None: 230 | policygen.maxdigits = options.maxdigit 231 | if options.maxlower != None: 232 | policygen.maxlower = options.maxlower 233 | if options.maxupper != None: 234 | policygen.maxupper = options.maxupper 235 | if options.maxspecial != None: 236 | policygen.maxspecial = options.maxspecial 237 | 238 | # Misc 239 | if options.pps: 240 | policygen.pps = options.pps 241 | if options.showmasks: 242 | policygen.showmasks = options.showmasks 243 | 244 | print("[*] Using {:,d} keys/sec for calculations.".format(policygen.pps)) 245 | 246 | # Print current password policy 247 | print("[*] Password policy:") 248 | print(" Pass Lengths: min:%d max:%d" % ( 249 | policygen.minlength, policygen.maxlength)) 250 | print(" Min strength: l:%s u:%s d:%s s:%s" % ( 251 | policygen.minlower, policygen.minupper, policygen.mindigit, policygen.minspecial)) 252 | print(" Max strength: l:%s u:%s d:%s s:%s" % ( 253 | policygen.maxlower, policygen.maxupper, policygen.maxdigit, policygen.maxspecial)) 254 | 255 | print("[*] Generating [%s] masks." % ( 256 | "compliant" if not options.noncompliant else "non-compliant")) 257 | policygen.generate_masks(options.noncompliant) 258 | -------------------------------------------------------------------------------- /PACK/statsgen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # StatsGen - Password Statistical Analysis tool 3 | # 4 | # This tool is part of PACK (Password Analysis and Cracking Kit) 5 | # 6 | # VERSION 0.0.3 7 | # 8 | # Copyright (C) 2013 Peter Kacherginsky 9 | # All rights reserved. 10 | # 11 | # Please see the attached LICENSE file for additional licensing information. 12 | 13 | import sys 14 | import re 15 | import operator 16 | import string 17 | from optparse import OptionParser, OptionGroup 18 | import time 19 | 20 | VERSION = "0.0.3" 21 | 22 | 23 | class StatsGen: 24 | def __init__(self): 25 | self.output_file = None 26 | 27 | # Filters 28 | self.minlength = None 29 | self.maxlength = None 30 | self.simplemasks = None 31 | self.charsets = None 32 | self.quiet = False 33 | self.debug = True 34 | 35 | # Stats dictionaries 36 | self.stats_length = dict() 37 | self.stats_simplemasks = dict() 38 | self.stats_advancedmasks = dict() 39 | self.stats_charactersets = dict() 40 | 41 | # Ignore stats with less than 1% coverage 42 | self.hiderare = False 43 | 44 | self.filter_counter = 0 45 | self.total_counter = 0 46 | 47 | # Minimum password complexity counters 48 | self.mindigit = None 49 | self.minupper = None 50 | self.minlower = None 51 | self.minspecial = None 52 | 53 | self.maxdigit = None 54 | self.maxupper = None 55 | self.maxlower = None 56 | self.maxspecial = None 57 | 58 | def analyze_password(self, password): 59 | 60 | # Password length 61 | pass_length = len(password) 62 | 63 | # Character-set and policy counters 64 | digit = 0 65 | lower = 0 66 | upper = 0 67 | special = 0 68 | 69 | simplemask = list() 70 | advancedmask_string = "" 71 | 72 | # Detect simple and advanced masks 73 | for letter in password: 74 | 75 | if letter in string.digits: 76 | digit += 1 77 | advancedmask_string += "?d" 78 | if not simplemask or not simplemask[-1] == 'digit': 79 | simplemask.append('digit') 80 | 81 | elif letter in string.ascii_lowercase: 82 | lower += 1 83 | advancedmask_string += "?l" 84 | if not simplemask or not simplemask[-1] == 'string': 85 | simplemask.append('string') 86 | 87 | elif letter in string.ascii_uppercase: 88 | upper += 1 89 | advancedmask_string += "?u" 90 | if not simplemask or not simplemask[-1] == 'string': 91 | simplemask.append('string') 92 | 93 | else: 94 | special += 1 95 | advancedmask_string += "?s" 96 | if not simplemask or not simplemask[-1] == 'special': 97 | simplemask.append('special') 98 | 99 | # String representation of masks 100 | simplemask_string = ''.join(simplemask) if len( 101 | simplemask) <= 3 else 'othermask' 102 | 103 | # Policy 104 | policy = (digit, lower, upper, special) 105 | 106 | # Determine character-set 107 | if digit and not lower and not upper and not special: 108 | charset = 'numeric' 109 | elif not digit and lower and not upper and not special: 110 | charset = 'loweralpha' 111 | elif not digit and not lower and upper and not special: 112 | charset = 'upperalpha' 113 | elif not digit and not lower and not upper and special: 114 | charset = 'special' 115 | 116 | elif not digit and lower and upper and not special: 117 | charset = 'mixedalpha' 118 | elif digit and lower and not upper and not special: 119 | charset = 'loweralphanum' 120 | elif digit and not lower and upper and not special: 121 | charset = 'upperalphanum' 122 | elif not digit and lower and not upper and special: 123 | charset = 'loweralphaspecial' 124 | elif not digit and not lower and upper and special: 125 | charset = 'upperalphaspecial' 126 | elif digit and not lower and not upper and special: 127 | charset = 'specialnum' 128 | 129 | elif not digit and lower and upper and special: 130 | charset = 'mixedalphaspecial' 131 | elif digit and not lower and upper and special: 132 | charset = 'upperalphaspecialnum' 133 | elif digit and lower and not upper and special: 134 | charset = 'loweralphaspecialnum' 135 | elif digit and lower and upper and not special: 136 | charset = 'mixedalphanum' 137 | else: 138 | charset = 'all' 139 | 140 | return (pass_length, charset, simplemask_string, advancedmask_string, policy) 141 | 142 | def generate_stats(self, filename): 143 | """ Generate password statistics. """ 144 | 145 | with open(filename, 'r') as f: 146 | 147 | for password in f: 148 | password = password.rstrip('\r\n') 149 | 150 | if len(password) == 0: 151 | continue 152 | 153 | self.total_counter += 1 154 | 155 | (pass_length, characterset, simplemask, advancedmask, 156 | policy) = self.analyze_password(password) 157 | (digit, lower, upper, special) = policy 158 | 159 | if (self.charsets == None or characterset in self.charsets) and \ 160 | (self.simplemasks == None or simplemask in self.simplemasks) and \ 161 | (self.maxlength == None or pass_length <= self.maxlength) and \ 162 | (self.minlength == None or pass_length >= self.minlength): 163 | 164 | self.filter_counter += 1 165 | 166 | if self.mindigit == None or digit < self.mindigit: 167 | self.mindigit = digit 168 | if self.maxdigit == None or digit > self.maxdigit: 169 | self.maxdigit = digit 170 | 171 | if self.minupper == None or upper < self.minupper: 172 | self.minupper = upper 173 | if self.maxupper == None or upper > self.maxupper: 174 | self.maxupper = upper 175 | 176 | if self.minlower == None or lower < self.minlower: 177 | self.minlower = lower 178 | if self.maxlower == None or lower > self.maxlower: 179 | self.maxlower = lower 180 | 181 | if self.minspecial == None or special < self.minspecial: 182 | self.minspecial = special 183 | if self.maxspecial == None or special > self.maxspecial: 184 | self.maxspecial = special 185 | 186 | if pass_length in self.stats_length: 187 | self.stats_length[pass_length] += 1 188 | else: 189 | self.stats_length[pass_length] = 1 190 | 191 | if characterset in self.stats_charactersets: 192 | self.stats_charactersets[characterset] += 1 193 | else: 194 | self.stats_charactersets[characterset] = 1 195 | 196 | if simplemask in self.stats_simplemasks: 197 | self.stats_simplemasks[simplemask] += 1 198 | else: 199 | self.stats_simplemasks[simplemask] = 1 200 | 201 | if advancedmask in self.stats_advancedmasks: 202 | self.stats_advancedmasks[advancedmask] += 1 203 | else: 204 | self.stats_advancedmasks[advancedmask] = 1 205 | 206 | def print_stats(self): 207 | """ Print password statistics. """ 208 | 209 | print("[+] Analyzing %d%% (%d/%d) of passwords" % (self.filter_counter * 210 | 100/self.total_counter, self.filter_counter, self.total_counter)) 211 | print(" NOTE: Statistics below is relative to the number of analyzed passwords, not total number of passwords") 212 | print("\n[*] Length:") 213 | for (length, count) in sorted(iter(self.stats_length.items()), key=operator.itemgetter(1), reverse=True): 214 | if self.hiderare and not count*100/self.filter_counter > 0: 215 | continue 216 | print("[+] %25d: %02d%% (%d)" % 217 | (length, count*100/self.filter_counter, count)) 218 | 219 | print("\n[*] Character-set:") 220 | for (char, count) in sorted(iter(self.stats_charactersets.items()), key=operator.itemgetter(1), reverse=True): 221 | if self.hiderare and not count*100/self.filter_counter > 0: 222 | continue 223 | print("[+] %25s: %02d%% (%d)" % 224 | (char, count*100/self.filter_counter, count)) 225 | 226 | print("\n[*] Password complexity:") 227 | print("[+] digit: min(%s) max(%s)" % 228 | (self.mindigit, self.maxdigit)) 229 | print("[+] lower: min(%s) max(%s)" % 230 | (self.minlower, self.maxlower)) 231 | print("[+] upper: min(%s) max(%s)" % 232 | (self.minupper, self.maxupper)) 233 | print("[+] special: min(%s) max(%s)" % 234 | (self.minspecial, self.maxspecial)) 235 | 236 | print("\n[*] Simple Masks:") 237 | for (simplemask, count) in sorted(iter(self.stats_simplemasks.items()), key=operator.itemgetter(1), reverse=True): 238 | if self.hiderare and not count*100/self.filter_counter > 0: 239 | continue 240 | print("[+] %25s: %02d%% (%d)" % 241 | (simplemask, count*100/self.filter_counter, count)) 242 | 243 | print("\n[*] Advanced Masks:") 244 | for (advancedmask, count) in sorted(iter(self.stats_advancedmasks.items()), key=operator.itemgetter(1), reverse=True): 245 | if count*100/self.filter_counter > 0: 246 | print("[+] %25s: %02d%% (%d)" % 247 | (advancedmask, count*100/self.filter_counter, count)) 248 | 249 | if self.output_file: 250 | self.output_file.write("%s,%d\n" % (advancedmask, count)) 251 | 252 | 253 | if __name__ == "__main__": 254 | 255 | header = " _ \n" 256 | header += " StatsGen %s | |\n" % VERSION 257 | header += " _ __ __ _ ___| | _\n" 258 | header += " | '_ \ / _` |/ __| |/ /\n" 259 | header += " | |_) | (_| | (__| < \n" 260 | header += " | .__/ \__,_|\___|_|\_\\\n" 261 | header += " | | \n" 262 | header += " |_| iphelix@thesprawl.org\n" 263 | header += "\n" 264 | 265 | parser = OptionParser( 266 | "%prog [options] passwords.txt\n\nType --help for more options", version="%prog "+VERSION) 267 | 268 | filters = OptionGroup(parser, "Password Filters") 269 | filters.add_option("--minlength", dest="minlength", 270 | type="int", metavar="8", help="Minimum password length") 271 | filters.add_option("--maxlength", dest="maxlength", 272 | type="int", metavar="8", help="Maximum password length") 273 | filters.add_option("--charset", dest="charsets", 274 | help="Password charset filter (comma separated)", metavar="loweralpha,numeric") 275 | filters.add_option("--simplemask", dest="simplemasks", 276 | help="Password mask filter (comma separated)", metavar="stringdigit,allspecial") 277 | parser.add_option_group(filters) 278 | 279 | parser.add_option("-o", "--output", dest="output_file", 280 | help="Save masks and stats to a file", metavar="password.masks") 281 | parser.add_option("--hiderare", action="store_true", dest="hiderare", 282 | default=False, help="Hide statistics covering less than 1% of the sample") 283 | 284 | parser.add_option("-q", "--quiet", action="store_true", 285 | dest="quiet", default=False, help="Don't show headers.") 286 | (options, args) = parser.parse_args() 287 | 288 | # Print program header 289 | if not options.quiet: 290 | print(header) 291 | 292 | if len(args) != 1: 293 | parser.error("no passwords file specified") 294 | exit(1) 295 | 296 | print("[*] Analyzing passwords in [%s]" % args[0]) 297 | 298 | statsgen = StatsGen() 299 | 300 | if not options.minlength == None: 301 | statsgen.minlength = options.minlength 302 | if not options.maxlength == None: 303 | statsgen.maxlength = options.maxlength 304 | if not options.charsets == None: 305 | statsgen.charsets = [x.strip() for x in options.charsets.split(',')] 306 | if not options.simplemasks == None: 307 | statsgen.simplemasks = [x.strip() 308 | for x in options.simplemasks.split(',')] 309 | 310 | if options.hiderare: 311 | statsgen.hiderare = options.hiderare 312 | 313 | if options.output_file: 314 | print("[*] Saving advanced masks and occurrences to [%s]" % 315 | options.output_file) 316 | statsgen.output_file = open(options.output_file, 'w') 317 | 318 | statsgen.generate_stats(args[0]) 319 | statsgen.print_stats() 320 | -------------------------------------------------------------------------------- /config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "hcatPath": "/Passwords/hashcat", 3 | "hcatBin": "hashcat", 4 | "hcatTuning": "--force --remove", 5 | "hcatWordlists": "/Passwords/wordlists", 6 | "hcatOptimizedWordlists": "/Passwords/optimized_wordlists", 7 | "hcatDictionaryWordlist": ["rockyou.txt"], 8 | "hcatCombinationWordlist": ["rockyou.txt","rockyou.txt"], 9 | "hcatHybridlist": ["rockyou.txt"], 10 | "hcatMiddleCombinatorMasks": ["2","4"," ","-","_","+",",",".","&"], 11 | "hcatMiddleBaseList": "rockyou.txt", 12 | "hcatThoroughCombinatorMasks": ["0","1","2","3","4","5","6","7","8","9"," ","-","_","+",",","!","#","$","\"","%","&","'","(",")","*",".","/",":",";","<","=",">","?","@","[","\\","]","^","`","{","|","}","~"], 13 | "hcatThoroughBaseList": "rockyou.txt", 14 | "hcatGoodMeasureBaseList": "rockyou.txt", 15 | "hcatPrinceBaseList": "rockyou.txt", 16 | "pipalPath": "/path/to/pipal", 17 | "pipal_count" : 10, 18 | "bandrelmaxruntime": 300, 19 | "bandrel_common_basedwords": "welcome,password,p@ssword,p@$$word,changeme,letmein,summer,winter,spring,springtime,fall,autumn,monday,tuesday,wednesday,thursday,friday,saturday,sunday,january,february,march,april,may,june,july,august,september,october,november,december,christmas,easter,covid19" 20 | } -------------------------------------------------------------------------------- /hashcat-utils/CHANGES: -------------------------------------------------------------------------------- 1 | * v1.1 -> v1.2 2 | 3 | - Open Source the project 4 | - License is MIT 5 | - Moved repository to github: https://github.com/hashcat/hashcat-utils 6 | - Added CHANGES 7 | - Added LICENSE 8 | - Added README.md 9 | 10 | -------------------------------------------------------------------------------- /hashcat-utils/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jens Steube 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /hashcat-utils/README.md: -------------------------------------------------------------------------------- 1 | hashcat-utils 2 | ============== 3 | 4 | Hashcat-utils are a set of small utilities that are useful in advanced password cracking 5 | 6 | Brief description 7 | -------------- 8 | 9 | They all are packed into multiple stand-alone binaries. 10 | 11 | All of these utils are designed to execute only one specific function. 12 | 13 | Since they all work with STDIN and STDOUT you can group them into chains. 14 | 15 | Detailed description 16 | -------------- 17 | 18 | tbd 19 | 20 | Compile 21 | -------------- 22 | 23 | Simply run make 24 | 25 | Binary distribution 26 | -------------- 27 | 28 | Binaries for Linux, Windows and OSX: https://github.com/hashcat/hashcat-utils/releases 29 | -------------------------------------------------------------------------------- /hashcat-utils/bin/cleanup-rules.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/cleanup-rules.app -------------------------------------------------------------------------------- /hashcat-utils/bin/cleanup-rules.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/cleanup-rules.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/cleanup-rules.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/cleanup-rules.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/combinator.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/combinator.app -------------------------------------------------------------------------------- /hashcat-utils/bin/combinator.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/combinator.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/combinator.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/combinator.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/combinator3.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/combinator3.app -------------------------------------------------------------------------------- /hashcat-utils/bin/combinator3.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/combinator3.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/combinator3.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/combinator3.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/combipow.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/combipow.app -------------------------------------------------------------------------------- /hashcat-utils/bin/combipow.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/combipow.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/combipow.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/combipow.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/cutb.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/cutb.app -------------------------------------------------------------------------------- /hashcat-utils/bin/cutb.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/cutb.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/cutb.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/cutb.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/expander.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/expander.app -------------------------------------------------------------------------------- /hashcat-utils/bin/expander.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/expander.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/expander.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/expander.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/gate.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/gate.app -------------------------------------------------------------------------------- /hashcat-utils/bin/gate.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/gate.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/gate.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/gate.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/generate-rules.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/generate-rules.app -------------------------------------------------------------------------------- /hashcat-utils/bin/generate-rules.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/generate-rules.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/generate-rules.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/generate-rules.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/hcstatgen.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/hcstatgen.app -------------------------------------------------------------------------------- /hashcat-utils/bin/hcstatgen.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/hcstatgen.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/hcstatgen.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/hcstatgen.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/keyspace.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/keyspace.app -------------------------------------------------------------------------------- /hashcat-utils/bin/keyspace.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/keyspace.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/keyspace.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/keyspace.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/len.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/len.app -------------------------------------------------------------------------------- /hashcat-utils/bin/len.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/len.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/len.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/len.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/mli2.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/mli2.app -------------------------------------------------------------------------------- /hashcat-utils/bin/mli2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/mli2.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/mli2.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/mli2.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/morph.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/morph.app -------------------------------------------------------------------------------- /hashcat-utils/bin/morph.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/morph.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/morph.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/morph.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/permute.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/permute.app -------------------------------------------------------------------------------- /hashcat-utils/bin/permute.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/permute.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/permute.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/permute.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/permute_exist.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/permute_exist.app -------------------------------------------------------------------------------- /hashcat-utils/bin/permute_exist.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/permute_exist.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/permute_exist.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/permute_exist.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/prepare.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/prepare.app -------------------------------------------------------------------------------- /hashcat-utils/bin/prepare.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/prepare.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/prepare.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/prepare.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/req-exclude.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/req-exclude.app -------------------------------------------------------------------------------- /hashcat-utils/bin/req-exclude.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/req-exclude.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/req-exclude.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/req-exclude.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/req-include.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/req-include.app -------------------------------------------------------------------------------- /hashcat-utils/bin/req-include.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/req-include.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/req-include.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/req-include.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/rli.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/rli.app -------------------------------------------------------------------------------- /hashcat-utils/bin/rli.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/rli.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/rli.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/rli.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/rli2.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/rli2.app -------------------------------------------------------------------------------- /hashcat-utils/bin/rli2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/rli2.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/rli2.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/rli2.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/seprule.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | ## Name........: seprule 4 | ## Autor.......: Jens Steube 5 | ## License.....: MIT 6 | 7 | use strict; 8 | use warnings; 9 | 10 | ## 11 | ## configuration 12 | ## 13 | 14 | my @rp = ('0'..'9', 'A'..'Z'); 15 | 16 | my $width = 3; 17 | my $rule = "i"; 18 | my $sep = " "; 19 | 20 | ## 21 | ## code 22 | ## 23 | 24 | my $rp_size = scalar @rp; 25 | 26 | my $total = $rp_size ** $width; 27 | 28 | my $db; 29 | 30 | for (my $i = 0; $i < $total; $i++) 31 | { 32 | my $left = $i; 33 | 34 | my @out; 35 | 36 | for (my $c = 0; $c < $width; $c++) 37 | { 38 | my $m = $left % $rp_size; 39 | my $d = $left / $rp_size; 40 | 41 | push (@out, $m); 42 | 43 | $left = $d; 44 | } 45 | 46 | @out = sort { $a <=> $b } @out; 47 | 48 | my $val = join ("", @out); 49 | 50 | next if (exists $db->{$val}); 51 | 52 | $db->{$val} = undef; 53 | 54 | my @final; 55 | 56 | for (my $c = 0; $c < $width; $c++) 57 | { 58 | my $s = sprintf ("T%s", $rp[$out[$c]]); 59 | 60 | push (@final, $s); 61 | } 62 | 63 | for (my $c = 0; $c < $width; $c++) 64 | { 65 | my $s = sprintf ("%s%s%s", $rule, $rp[$out[$c]], $sep); 66 | 67 | push (@final, $s); 68 | } 69 | 70 | print join (" ", "l", @final), "\n"; 71 | } 72 | -------------------------------------------------------------------------------- /hashcat-utils/bin/splitlen.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/splitlen.app -------------------------------------------------------------------------------- /hashcat-utils/bin/splitlen.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/splitlen.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/splitlen.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/splitlen.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/strip-bsn.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/strip-bsn.app -------------------------------------------------------------------------------- /hashcat-utils/bin/strip-bsn.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/strip-bsn.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/strip-bsn.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/strip-bsn.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/strip-bsr.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/strip-bsr.app -------------------------------------------------------------------------------- /hashcat-utils/bin/strip-bsr.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/strip-bsr.bin -------------------------------------------------------------------------------- /hashcat-utils/bin/strip-bsr.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/hashcat-utils/bin/strip-bsr.exe -------------------------------------------------------------------------------- /hashcat-utils/bin/tmesis.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | ## Name........: tmesis 4 | ## Autor.......: Jens Steube 5 | ## License.....: MIT 6 | 7 | use strict; 8 | use warnings; 9 | 10 | #tmesis will take a wordlist and produce insertion rules that would insert each word of the wordlist to preset positions. 11 | #For example: 12 | #Word ‘password’ will create insertion rules that would insert ‘password’ from position 0 to position F (15) and It will mutate the string ‘123456’ as follows. 13 | #password123456 14 | #1password23456 15 | #12password3456 16 | #123password456 17 | #1234password56 18 | #12345password6 19 | #123456password 20 | # 21 | #Hints: 22 | #*Use tmesis to create rules to attack hashlists the came from the source. Run initial analysis on the cracked passwords , collect the top 10 – 20 words appear on the passwords and use tmesis to generate rules. 23 | #*use tmesis generated rules in combination with best64.rules 24 | # 25 | # inspired by T0XlC 26 | 27 | my $min_rule_pos = 0; 28 | my $max_rule_pos = 15; 29 | 30 | my $db; 31 | 32 | my @intpos_to_rulepos = ('0'..'9', 'A'..'Z'); 33 | 34 | my $function = "i"; 35 | #my $function = "o"; 36 | 37 | while (my $word = <>) 38 | { 39 | chomp $word; 40 | 41 | my $word_len = length $word; 42 | 43 | my @word_buf = split "", $word; 44 | 45 | for (my $rule_pos = $min_rule_pos; $rule_pos < $max_rule_pos - $word_len; $rule_pos++) 46 | { 47 | my @rule; 48 | 49 | for (my $word_pos = 0; $word_pos < $word_len; $word_pos++) 50 | { 51 | my $function_full = $function . $intpos_to_rulepos[$rule_pos + $word_pos] . $word_buf[$word_pos]; 52 | 53 | push @rule, $function_full; 54 | } 55 | 56 | print join (" ", @rule), "\n"; 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /hashcat-utils/bin/topmorph.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | ## Name........: topmorph 4 | ## Autor.......: Jens Steube 5 | ## License.....: MIT 6 | 7 | use strict; 8 | use warnings; 9 | 10 | my @intpos_to_rulepos = ('0'..'9', 'A'..'Z'); 11 | 12 | my $function = "i"; 13 | #my $function = "o"; 14 | 15 | if (scalar @ARGV != 5) 16 | { 17 | print "usage: $0 dictionary depth width pos_min pos_max\n"; 18 | 19 | exit -1; 20 | } 21 | 22 | my ($dictionary, $depth, $width, $pos_min, $pos_max) = @ARGV; 23 | 24 | if ($width > 20) 25 | { 26 | print "width > 20\n"; 27 | 28 | exit -1; 29 | } 30 | 31 | for (my $pos = $pos_min; $pos <= $pos_max; $pos++) 32 | { 33 | my $db; 34 | 35 | open (IN, $dictionary) or die "$dictionary: $!\n"; 36 | 37 | while (my $line = ) 38 | { 39 | chomp $line; 40 | 41 | my $len = length $line; 42 | 43 | next if (($len - $pos) < $width); 44 | 45 | my $word = substr ($line, $pos, $width); 46 | 47 | next unless defined $word; 48 | 49 | $db->{$word}++; 50 | } 51 | 52 | close (IN); 53 | 54 | my @keys = sort { $db->{$b} <=> $db->{$a} } keys %{$db}; 55 | 56 | for (my $i = 0; $i < $depth; $i++) 57 | { 58 | my @chars = split "", $keys[$i]; 59 | 60 | my @rule; 61 | 62 | for (my $j = 0; $j < $width; $j++) 63 | { 64 | my $function_full = join "", $function, $intpos_to_rulepos[$pos + $j], $chars[$j]; 65 | 66 | push @rule, $function_full; 67 | } 68 | 69 | print join (" ", @rule), "\n"; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /hate_crack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Methodology provided by Martin Bos (pure_hate) - https://www.trustedsec.com/team/martin-bos/ 4 | # Original script created by Larry Spohn (spoonman) - https://www.trustedsec.com/team/larry-spohn/ 5 | # Python refactoring and general fixing, Justin Bollinger (bandrel) - https://www.trustedsec.com/team/justin-bollinger/ 6 | 7 | import subprocess 8 | import sys 9 | import os 10 | import random 11 | import re 12 | import json 13 | import binascii 14 | import shutil 15 | 16 | # python2/3 compatability 17 | try: 18 | input = raw_input 19 | except NameError: 20 | pass 21 | 22 | hate_path = os.path.dirname(os.path.realpath(__file__)) 23 | if not os.path.isfile(hate_path + '/config.json'): 24 | print('Initializing config.json from config.json.example') 25 | shutil.copy(hate_path + '/config.json.example',hate_path + '/config.json') 26 | 27 | with open(hate_path + '/config.json') as config: 28 | config_parser = json.load(config) 29 | 30 | with open(hate_path + '/config.json.example') as defaults: 31 | default_config = json.load(defaults) 32 | 33 | hcatPath = config_parser['hcatPath'] 34 | hcatBin = config_parser['hcatBin'] 35 | hcatTuning = config_parser['hcatTuning'] 36 | hcatWordlists = config_parser['hcatWordlists'] 37 | hcatOptimizedWordlists = config_parser['hcatOptimizedWordlists'] 38 | hcatRules = [] 39 | 40 | try: 41 | maxruntime = config_parser['bandrelmaxruntime'] 42 | except KeyError as e: 43 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 44 | maxruntime = default_config['bandrelmaxruntime'] 45 | 46 | try: 47 | bandrelbasewords = config_parser['bandrel_common_basedwords'] 48 | except KeyError as e: 49 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 50 | bandrelbasewords = default_config['bandrel_common_basedwords'] 51 | 52 | try: 53 | 54 | pipal_count = config_parser['pipal_count'] 55 | except KeyError as e: 56 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 57 | pipal_count = default_config['pipal_count'] 58 | 59 | try: 60 | pipalPath = config_parser['pipalPath'] 61 | except KeyError as e: 62 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 63 | pipalPath = default_config['pipalPath'] 64 | 65 | try: 66 | hcatDictionaryWordlist = config_parser['hcatDictionaryWordlist'] 67 | except KeyError as e: 68 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 69 | hcatDictionaryWordlist = default_config['hcatDictionaryWordlist'] 70 | try: 71 | hcatHybridlist = config_parser['hcatHybridlist'] 72 | except KeyError as e: 73 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 74 | hcatHybridlist = default_config[e.args[0]] 75 | try: 76 | hcatCombinationWordlist = config_parser['hcatCombinationWordlist'] 77 | except KeyError as e: 78 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 79 | hcatCombinationWordlist = default_config[e.args[0]] 80 | try: 81 | hcatMiddleCombinatorMasks = config_parser['hcatMiddleCombinatorMasks'] 82 | except KeyError as e: 83 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 84 | hcatMiddleCombinatorMasks = default_config[e.args[0]] 85 | try: 86 | hcatMiddleBaseList = config_parser['hcatMiddleBaseList'] 87 | except KeyError as e: 88 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 89 | hcatMiddleBaseList = default_config[e.args[0]] 90 | try: 91 | hcatThoroughCombinatorMasks = config_parser['hcatThoroughCombinatorMasks'] 92 | except KeyError as e: 93 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 94 | hcatThoroughCombinatorMasks = default_config[e.args[0]] 95 | try: 96 | hcatThoroughBaseList = config_parser['hcatThoroughBaseList'] 97 | except KeyError as e: 98 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 99 | hcatThoroughBaseList = default_config[e.args[0]] 100 | try: 101 | hcatPrinceBaseList = config_parser['hcatPrinceBaseList'] 102 | except KeyError as e: 103 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 104 | hcatPrinceBaseList = default_config[e.args[0]] 105 | try: 106 | hcatGoodMeasureBaseList = config_parser['hcatGoodMeasureBaseList'] 107 | except KeyError as e: 108 | print('{0} is not defined in config.json using defaults from config.json.example'.format(e)) 109 | hcatGoodMeasureBaseList = default_config[e.args[0]] 110 | 111 | 112 | if sys.platform == 'darwin': 113 | hcatExpanderBin = "expander.app" 114 | hcatCombinatorBin = "combinator.app" 115 | hcatPrinceBin = "pp64.app" 116 | else: 117 | hcatExpanderBin = "expander.bin" 118 | hcatCombinatorBin = "combinator.bin" 119 | hcatPrinceBin = "pp64.bin" 120 | 121 | def verify_wordlist_dir(directory, wordlist): 122 | if os.path.isfile(wordlist): 123 | return wordlist 124 | elif os.path.isfile(directory + '/' + wordlist): 125 | return directory + '/' + wordlist 126 | else: 127 | print('Invalid path for {0}. Please check configuration and try again.'.format(wordlist)) 128 | quit(1) 129 | 130 | # hashcat biniary checks for systems that install hashcat binary in different location than the rest of the hashcat files 131 | if os.path.isfile(hcatBin): 132 | pass 133 | elif os.path.isfile(hcatPath.rstrip('/') + '/' + hcatBin): 134 | hcatBin = hcatPath.rstrip('/') + '/' + hcatBin 135 | else: 136 | print('Invalid path for hashcat binary. Please check configuration and try again.') 137 | quit(1) 138 | 139 | #verify and convert wordlists to fully qualified paths 140 | hcatMiddleBaseList = verify_wordlist_dir(hcatWordlists, hcatMiddleBaseList) 141 | hcatThoroughBaseList = verify_wordlist_dir(hcatWordlists, hcatThoroughBaseList) 142 | hcatPrinceBaseList = verify_wordlist_dir(hcatWordlists, hcatPrinceBaseList) 143 | hcatGoodMeasureBaseList = verify_wordlist_dir(hcatWordlists, hcatGoodMeasureBaseList) 144 | for x in range(len(hcatDictionaryWordlist)): 145 | hcatDictionaryWordlist[x] = verify_wordlist_dir(hcatWordlists, hcatDictionaryWordlist[x]) 146 | for x in range(len(hcatHybridlist)): 147 | hcatHybridlist[x] = verify_wordlist_dir(hcatWordlists, hcatHybridlist[x]) 148 | hcatCombinationWordlist[0] = verify_wordlist_dir(hcatWordlists, hcatCombinationWordlist[0]) 149 | hcatCombinationWordlist[1] = verify_wordlist_dir(hcatWordlists, hcatCombinationWordlist[1]) 150 | 151 | 152 | hcatHashCount = 0 153 | hcatHashCracked = 0 154 | hcatBruteCount = 0 155 | hcatDictionaryCount = 0 156 | hcatMaskCount = 0 157 | hcatFingerprintCount = 0 158 | hcatCombinationCount = 0 159 | hcatHybridCount = 0 160 | hcatExtraCount = 0 161 | hcatRecycleCount = 0 162 | hcatProcess = 0 163 | 164 | 165 | # Help 166 | def usage(): 167 | print("usage: python hate_crack.py ") 168 | print("\nThe is attained by running \"{hcatBin} --help\"\n".format(hcatBin=hcatBin)) 169 | print("Example Hashes: http://hashcat.net/wiki/doku.php?id=example_hashes\n") 170 | 171 | 172 | def ascii_art(): 173 | print(r""" 174 | 175 | ___ ___ __ _________ __ 176 | / | \_____ _/ |_ ____ \_ ___ \____________ ____ | | __ 177 | / ~ \__ \\ __\/ __ \ / \ \/\_ __ \__ \ _/ ___\| |/ / 178 | \ Y // __ \| | \ ___/ \ \____| | \// __ \\ \___| < 179 | \___|_ /(____ /__| \___ >____\______ /|__| (____ /\___ >__|_ \ 180 | \/ \/ \/_____/ \/ \/ \/ \/ 181 | Version 1.09 182 | """) 183 | 184 | 185 | # Counts the number of lines in a file 186 | def lineCount(file): 187 | try: 188 | with open(file) as outFile: 189 | count = 0 190 | for line in outFile: 191 | count = count + 1 192 | return count 193 | except: 194 | return 0 195 | 196 | # Brute Force Attack 197 | def hcatBruteForce(hcatHashType, hcatHashFile, hcatMinLen, hcatMaxLen): 198 | global hcatBruteCount 199 | global hcatProcess 200 | hcatProcess = subprocess.Popen( 201 | "{hcbin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out --increment --increment-min={min} " 202 | "--increment-max={max} -a 3 ?a?a?a?a?a?a?a?a?a?a?a?a?a?a {tuning} --potfile-path={hate_path}/hashcat.pot".format( 203 | hcbin=hcatBin, 204 | hash_type=hcatHashType, 205 | hash_file=hcatHashFile, 206 | session_name=os.path.basename(hcatHashFile), 207 | min=hcatMinLen, 208 | max=hcatMaxLen, 209 | tuning=hcatTuning, 210 | hate_path=hate_path), shell=True) 211 | try: 212 | hcatProcess.wait() 213 | except KeyboardInterrupt: 214 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 215 | hcatProcess.kill() 216 | 217 | hcatBruteCount = lineCount(hcatHashFile + ".out") 218 | 219 | 220 | # Dictionary Attack 221 | def hcatDictionary(hcatHashType, hcatHashFile): 222 | global hcatDictionaryCount 223 | global hcatProcess 224 | hcatProcess = subprocess.Popen( 225 | "{hcatBin} -m {hcatHashType} {hash_file} --session {session_name} -o {hash_file}.out {optimized_wordlists}/* " 226 | "-r {hcatPath}/rules/best66.rule {tuning} --potfile-path={hate_path}/hashcat.pot".format( 227 | hcatPath=hcatPath, 228 | hcatBin=hcatBin, 229 | hcatHashType=hcatHashType, 230 | hash_file=hcatHashFile, 231 | session_name=os.path.basename(hcatHashFile), 232 | optimized_wordlists=hcatOptimizedWordlists, 233 | tuning=hcatTuning, 234 | hate_path=hate_path), shell=True) 235 | try: 236 | hcatProcess.wait() 237 | except KeyboardInterrupt: 238 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 239 | hcatProcess.kill() 240 | 241 | 242 | for wordlist in hcatDictionaryWordlist: 243 | hcatProcess = subprocess.Popen( 244 | "{hcatBin} -m {hcatHashType} {hash_file} --session {session_name} -o {hash_file}.out {hcatWordlist} " 245 | "-r {hcatPath}/rules/d3ad0ne.rule {tuning} --potfile-path={hate_path}/hashcat.pot".format( 246 | hcatPath=hcatPath, 247 | hcatBin=hcatBin, 248 | hcatHashType=hcatHashType, 249 | hash_file=hcatHashFile, 250 | session_name=os.path.basename(hcatHashFile), 251 | hcatWordlist=wordlist, 252 | tuning=hcatTuning, 253 | hate_path=hate_path), shell=True) 254 | try: 255 | hcatProcess.wait() 256 | except KeyboardInterrupt: 257 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 258 | hcatProcess.kill() 259 | 260 | 261 | hcatProcess = subprocess.Popen( 262 | "{hcatBin} -m {hcatHashType} {hash_file} --session {session_name} -o {hash_file}.out {hcatWordlist} " 263 | "-r {hcatPath}/rules/T0XlC.rule {tuning} --potfile-path={hate_path}/hashcat.pot".format( 264 | hcatPath=hcatPath, 265 | hcatBin=hcatBin, 266 | hcatHashType=hcatHashType, 267 | hash_file=hcatHashFile, 268 | session_name=os.path.basename(hcatHashFile), 269 | hcatWordlist=wordlist, 270 | tuning=hcatTuning, 271 | hate_path=hate_path), shell=True) 272 | try: 273 | hcatProcess.wait() 274 | except KeyboardInterrupt: 275 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 276 | hcatProcess.kill() 277 | 278 | hcatDictionaryCount = lineCount(hcatHashFile + ".out") - hcatBruteCount 279 | 280 | 281 | # Quick Dictionary Attack (Optional Chained Rules) 282 | def hcatQuickDictionary(hcatHashType, hcatHashFile, hcatChains, wordlists): 283 | global hcatProcess 284 | hcatProcess = subprocess.Popen( 285 | "{hcatBin} -m {hcatHashType} {hash_file} --session {session_name} -o {hash_file}.out " 286 | "'{wordlists}' {chains} {tuning} --potfile-path={hate_path}/hashcat.pot".format( 287 | hcatBin=hcatBin, 288 | hcatHashType=hcatHashType, 289 | hash_file=hcatHashFile, 290 | session_name=os.path.basename(hcatHashFile), 291 | wordlists=wordlists, 292 | chains=hcatChains, 293 | tuning=hcatTuning, 294 | hate_path=hate_path), shell=True) 295 | try: 296 | hcatProcess.wait() 297 | except KeyboardInterrupt: 298 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 299 | hcatProcess.kill() 300 | 301 | 302 | 303 | # Top Mask Attack 304 | def hcatTopMask(hcatHashType, hcatHashFile, hcatTargetTime): 305 | global hcatMaskCount 306 | global hcatProcess 307 | hcatProcess = subprocess.Popen( 308 | "cat {hash_file}.out | cut -d : -f 2 > {hash_file}.working".format( 309 | hash_file=hcatHashFile), shell=True).wait() 310 | hcatProcess = subprocess.Popen( 311 | "{hate_path}/PACK/statsgen.py {hash_file}.working -o {hash_file}.masks".format( 312 | hash_file=hcatHashFile, 313 | hate_path=hate_path), shell=True) 314 | try: 315 | hcatProcess.wait() 316 | except KeyboardInterrupt: 317 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 318 | hcatProcess.kill() 319 | 320 | hcatProcess = subprocess.Popen( 321 | "{hate_path}/PACK/maskgen.py {hash_file}.masks --targettime {target_time} --optindex -q --pps 14000000000 " 322 | "--minlength=7 -o {hash_file}.hcmask".format( 323 | hash_file=hcatHashFile, 324 | target_time=hcatTargetTime, 325 | hate_path=hate_path), shell=True) 326 | try: 327 | hcatProcess.wait() 328 | except KeyboardInterrupt: 329 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 330 | hcatProcess.kill() 331 | 332 | hcatProcess = subprocess.Popen( 333 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 3 {hash_file}.hcmask {tuning} " 334 | "--potfile-path={hate_path}/hashcat.pot".format( 335 | hcatBin=hcatBin, 336 | hash_type=hcatHashType, 337 | hash_file=hcatHashFile, 338 | session_name=os.path.basename(hcatHashFile), 339 | tuning=hcatTuning, 340 | hate_path=hate_path), shell=True) 341 | try: 342 | hcatProcess.wait() 343 | except KeyboardInterrupt: 344 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 345 | hcatProcess.kill() 346 | 347 | hcatMaskCount = lineCount(hcatHashFile + ".out") - hcatHashCracked 348 | 349 | 350 | # Fingerprint Attack 351 | def hcatFingerprint(hcatHashType, hcatHashFile): 352 | global hcatFingerprintCount 353 | global hcatProcess 354 | crackedBefore = lineCount(hcatHashFile + ".out") 355 | crackedAfter = 0 356 | while crackedBefore != crackedAfter: 357 | crackedBefore = lineCount(hcatHashFile + ".out") 358 | hcatProcess = subprocess.Popen("cat {hash_file}.out | cut -d : -f 2 > {hash_file}.working".format( 359 | hash_file=hcatHashFile), shell=True).wait() 360 | hcatProcess = subprocess.Popen( 361 | "{hate_path}/hashcat-utils/bin/{expander_bin} < {hash_file}.working | sort -u > {hash_file}.expanded".format( 362 | expander_bin=hcatExpanderBin, 363 | hash_file=hcatHashFile, 364 | hate_path=hate_path), shell=True) 365 | try: 366 | hcatProcess.wait() 367 | except KeyboardInterrupt: 368 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 369 | hcatProcess.kill() 370 | hcatProcess = subprocess.Popen( 371 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 {hash_file}.expanded " 372 | "{hash_file}.expanded {tuning} --potfile-path={hate_path}/hashcat.pot".format( 373 | hcatBin=hcatBin, 374 | hash_type=hcatHashType, 375 | hash_file=hcatHashFile, 376 | session_name=os.path.basename(hcatHashFile), 377 | tuning=hcatTuning, 378 | hate_path=hate_path), shell=True) 379 | try: 380 | hcatProcess.wait() 381 | except KeyboardInterrupt: 382 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 383 | hcatProcess.kill() 384 | crackedAfter = lineCount(hcatHashFile + ".out") 385 | hcatFingerprintCount = lineCount(hcatHashFile + ".out") - hcatHashCracked 386 | 387 | 388 | # Combinator Attack 389 | def hcatCombination(hcatHashType, hcatHashFile): 390 | global hcatCombinationCount 391 | global hcatProcess 392 | hcatProcess = subprocess.Popen( 393 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 {left} " 394 | "{right} {tuning} --potfile-path={hate_path}/hashcat.pot".format( 395 | hcatBin=hcatBin, 396 | hash_type=hcatHashType, 397 | hash_file=hcatHashFile, 398 | session_name=os.path.basename(hcatHashFile), 399 | word_lists=hcatWordlists, 400 | left=hcatCombinationWordlist[0], 401 | right=hcatCombinationWordlist[1], 402 | tuning=hcatTuning, 403 | hate_path=hate_path), 404 | shell=True) 405 | try: 406 | hcatProcess.wait() 407 | except KeyboardInterrupt: 408 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 409 | hcatProcess.kill() 410 | 411 | hcatCombinationCount = lineCount(hcatHashFile + ".out") - hcatHashCracked 412 | 413 | 414 | # Hybrid Attack 415 | def hcatHybrid(hcatHashType, hcatHashFile): 416 | global hcatHybridCount 417 | global hcatProcess 418 | for wordlist in hcatHybridlist: 419 | hcatProcess = subprocess.Popen( 420 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 6 -1 ?s?d {wordlist} ?1?1 " 421 | "{tuning} --potfile-path={hate_path}/hashcat.pot".format( 422 | hcatBin=hcatBin, 423 | hash_type=hcatHashType, 424 | hash_file=hcatHashFile, 425 | session_name=os.path.basename(hcatHashFile), 426 | wordlist=wordlist, 427 | tuning=hcatTuning, 428 | hate_path=hate_path), shell=True) 429 | try: 430 | hcatProcess.wait() 431 | except KeyboardInterrupt: 432 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 433 | hcatProcess.kill() 434 | 435 | hcatProcess = subprocess.Popen( 436 | "{hcatBin} -m {hash_type} {hash_file} -o {hash_file}.out -a 6 -1 ?s?d {wordlist} ?1?1?1 " 437 | "{tuning} --potfile-path={hate_path}/hashcat.pot".format( 438 | hcatBin=hcatBin, 439 | hash_type=hcatHashType, 440 | hash_file=hcatHashFile, 441 | session_name=os.path.basename(hcatHashFile), 442 | wordlist=wordlist, 443 | tuning=hcatTuning, 444 | hate_path=hate_path), shell=True) 445 | try: 446 | hcatProcess.wait() 447 | except KeyboardInterrupt: 448 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 449 | hcatProcess.kill() 450 | 451 | hcatProcess = subprocess.Popen( 452 | "{hcatBin} -m {hash_type} {hash_file} -o {hash_file}.out -a 6 -1 ?s?d {wordlist} " 453 | "?1?1?1?1 {tuning} --potfile-path={hate_path}/hashcat.pot".format( 454 | hcatBin=hcatBin, 455 | hash_type=hcatHashType, 456 | hash_file=hcatHashFile, 457 | session_name=os.path.basename(hcatHashFile), 458 | wordlist=wordlist, 459 | tuning=hcatTuning, 460 | hate_path=hate_path), shell=True) 461 | try: 462 | hcatProcess.wait() 463 | except KeyboardInterrupt: 464 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 465 | hcatProcess.kill() 466 | 467 | hcatProcess = subprocess.Popen( 468 | "{hcatBin} -m {hash_type} {hash_file} -o {hash_file}.out -a 7 -1 ?s?d ?1?1 {wordlist} " 469 | "{tuning} --potfile-path={hate_path}/hashcat.pot".format( 470 | hcatBin=hcatBin, 471 | hash_type=hcatHashType, 472 | hash_file=hcatHashFile, 473 | session_name=os.path.basename(hcatHashFile), 474 | wordlist=wordlist, 475 | tuning=hcatTuning, 476 | hate_path=hate_path), shell=True) 477 | try: 478 | hcatProcess.wait() 479 | except KeyboardInterrupt: 480 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 481 | hcatProcess.kill() 482 | 483 | hcatProcess = subprocess.Popen( 484 | "{hcatBin} -m {hash_type} {hash_file} -o {hash_file}.out -a 7 -1 ?s?d ?1?1?1 {wordlist} " 485 | "{tuning} --potfile-path={hate_path}/hashcat.pot".format( 486 | hcatBin=hcatBin, 487 | hash_type=hcatHashType, 488 | hash_file=hcatHashFile, 489 | session_name=os.path.basename(hcatHashFile), 490 | wordlist=wordlist, 491 | tuning=hcatTuning, 492 | hate_path=hate_path), shell=True) 493 | try: 494 | hcatProcess.wait() 495 | except KeyboardInterrupt: 496 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 497 | hcatProcess.kill() 498 | 499 | hcatProcess = subprocess.Popen( 500 | "{hcatBin} -m {hash_type} {hash_file} -o {hash_file}.out -a 7 -1 ?s?d ?1?1?1?1 {wordlist} " 501 | "{tuning} --potfile-path={hate_path}/hashcat.pot".format( 502 | hcatBin=hcatBin, 503 | hash_type=hcatHashType, 504 | hash_file=hcatHashFile, 505 | session_name=os.path.basename(hcatHashFile), 506 | wordlist=wordlist, 507 | tuning=hcatTuning, 508 | hate_path=hate_path), shell=True) 509 | try: 510 | hcatProcess.wait() 511 | except KeyboardInterrupt: 512 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 513 | hcatProcess.kill() 514 | 515 | hcatHybridCount = lineCount(hcatHashFile + ".out") - hcatHashCracked 516 | 517 | 518 | # YOLO Combination Attack 519 | def hcatYoloCombination(hcatHashType, hcatHashFile): 520 | global hcatProcess 521 | try: 522 | while 1: 523 | hcatLeft = random.choice(os.listdir(hcatOptimizedWordlists)) 524 | hcatRight = random.choice(os.listdir(hcatOptimizedWordlists)) 525 | hcatProcess = subprocess.Popen( 526 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 {optimized_lists}/{left} " 527 | "{optimized_lists}/{right} {tuning} --potfile-path={hate_path}/hashcat.pot".format( 528 | hcatBin=hcatBin, 529 | hash_type=hcatHashType, 530 | hash_file=hcatHashFile, 531 | session_name=os.path.basename(hcatHashFile), 532 | word_lists=hcatWordlists, 533 | optimized_lists=hcatOptimizedWordlists, 534 | tuning=hcatTuning, 535 | left=hcatLeft, 536 | right=hcatRight, 537 | hate_path=hate_path), shell=True) 538 | hcatProcess.wait() 539 | except KeyboardInterrupt: 540 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 541 | hcatProcess.kill() 542 | 543 | # Bandrel methodlogy 544 | def hcatBandrel(hcatHashType, hcatHashFile): 545 | global hcatProcess 546 | basewords = [] 547 | while True: 548 | company_name = input('What is the company name (Enter multiples comma separated)? ') 549 | if company_name: 550 | break 551 | for name in company_name.split(','): 552 | basewords.append(name) 553 | for word in bandrelbasewords.split(','): 554 | basewords.append(word) 555 | for name in basewords: 556 | mask1 = '-1{0}{1}'.format(name[0].lower(),name[0].upper()) 557 | mask2 = ' ?1{0}'.format(name[1:]) 558 | for x in range(6): 559 | mask2 += '?a' 560 | hcatProcess = subprocess.Popen( 561 | "{hcatBin} -m {hash_type} -a 3 --session {session_name} -o {hash_file}.out " 562 | "{tuning} --potfile-path={hate_path}/hashcat.pot --runtime {maxruntime} -i {hcmask1} {hash_file} {hcmask2}".format( 563 | hcatBin=hcatBin, 564 | hash_type=hcatHashType, 565 | hash_file=hcatHashFile, 566 | session_name=os.path.basename(hcatHashFile), 567 | tuning=hcatTuning, 568 | hcmask1=mask1, 569 | hcmask2=mask2, 570 | maxruntime=maxruntime, 571 | hate_path=hate_path), shell=True) 572 | try: 573 | hcatProcess.wait() 574 | except KeyboardInterrupt: 575 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 576 | hcatProcess.kill() 577 | print('Checking passwords against pipal for top {0} passwords and basewords'.format(pipal_count)) 578 | pipal_basewords = pipal() 579 | for word in pipal_basewords: 580 | mask1 = '-1={0}{1}'.format(word[0].lower(),word[0].upper()) 581 | mask2 = ' ?1{0}'.format(word[1:]) 582 | for x in range(6): 583 | mask2 += '?a' 584 | hcatProcess = subprocess.Popen( 585 | "{hcatBin} -m {hash_type} -a 3 --session {session_name} -o {hash_file}.out " 586 | "{tuning} --potfile-path={hate_path}/hashcat.pot --runtime {maxruntime} -i {hcmask1} {hash_file} {hcmask2}".format( 587 | hcatBin=hcatBin, 588 | hash_type=hcatHashType, 589 | hash_file=hcatHashFile, 590 | session_name=os.path.basename(hcatHashFile), 591 | tuning=hcatTuning, 592 | hcmask1=mask1, 593 | hcmask2=mask2, 594 | maxruntime=maxruntime, 595 | hate_path=hate_path), shell=True) 596 | try: 597 | hcatProcess.wait() 598 | except KeyboardInterrupt: 599 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 600 | hcatProcess.kill() 601 | 602 | # Middle fast Combinator Attack 603 | def hcatMiddleCombinator(hcatHashType, hcatHashFile): 604 | global hcatProcess 605 | masks = hcatMiddleCombinatorMasks 606 | # Added support for multiple character masks 607 | new_masks = [] 608 | for mask in masks: 609 | tmp = [] 610 | if len(mask) > 1: 611 | for character in mask: 612 | tmp.append(character) 613 | new_masks.append('$' + '$'.join(tmp)) 614 | else: 615 | new_masks.append('$'+mask) 616 | masks = new_masks 617 | 618 | try: 619 | for x in range(len(masks)): 620 | hcatProcess = subprocess.Popen( 621 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 -j '${middle_mask}' {left} " 622 | "{right} --potfile-path={hate_path}/hashcat.pot".format( 623 | hcatBin=hcatBin, 624 | hash_type=hcatHashType, 625 | hash_file=hcatHashFile, 626 | session_name=os.path.basename(hcatHashFile), 627 | left=hcatMiddleBaseList, 628 | right=hcatMiddleBaseList, 629 | tuning=hcatTuning, 630 | middle_mask=masks[x], 631 | hate_path=hate_path), 632 | shell=True) 633 | hcatProcess.wait() 634 | except KeyboardInterrupt: 635 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 636 | hcatProcess.kill() 637 | 638 | # Middle thorough Combinator Attack 639 | def hcatThoroughCombinator(hcatHashType, hcatHashFile): 640 | global hcatProcess 641 | masks = hcatThoroughCombinatorMasks 642 | # Added support for multiple character masks 643 | new_masks = [] 644 | for mask in masks: 645 | tmp = [] 646 | if len(mask) > 1: 647 | for character in mask: 648 | tmp.append(character) 649 | new_masks.append('$' + '$'.join(tmp)) 650 | else: 651 | new_masks.append('$'+mask) 652 | masks = new_masks 653 | 654 | try: 655 | hcatProcess = subprocess.Popen( 656 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 {left} " 657 | "{right} {tuning} --potfile-path={hate_path}/hashcat.pot".format( 658 | hcatBin=hcatBin, 659 | hash_type=hcatHashType, 660 | hash_file=hcatHashFile, 661 | session_name=os.path.basename(hcatHashFile), 662 | left=hcatThoroughBaseList, 663 | right=hcatThoroughBaseList, 664 | word_lists=hcatWordlists, 665 | tuning=hcatTuning, 666 | hate_path=hate_path), 667 | shell=True) 668 | hcatProcess.wait() 669 | except KeyboardInterrupt: 670 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 671 | hcatProcess.kill() 672 | 673 | try: 674 | for x in range(len(masks)): 675 | hcatProcess = subprocess.Popen( 676 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 " 677 | "-j '${middle_mask}' {left} {right} --potfile-path={hate_path}/hashcat.pot".format( 678 | hcatBin=hcatBin, 679 | hash_type=hcatHashType, 680 | hash_file=hcatHashFile, 681 | session_name=os.path.basename(hcatHashFile), 682 | left=hcatThoroughBaseList, 683 | right=hcatThoroughBaseList, 684 | word_lists=hcatWordlists, 685 | tuning=hcatTuning, 686 | middle_mask=masks[x], 687 | hate_path=hate_path), 688 | shell=True) 689 | hcatProcess.wait() 690 | except KeyboardInterrupt: 691 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 692 | hcatProcess.kill() 693 | try: 694 | for x in range(len(masks)): 695 | hcatProcess = subprocess.Popen( 696 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 " 697 | "-k '${end_mask}' {left} {right} {tuning} --potfile-path={hate_path}/hashcat.pot".format( 698 | hcatBin=hcatBin, 699 | hash_type=hcatHashType, 700 | hash_file=hcatHashFile, 701 | session_name=os.path.basename(hcatHashFile), 702 | left=hcatThoroughBaseList, 703 | right=hcatThoroughBaseList, 704 | word_lists=hcatWordlists, 705 | tuning=hcatTuning, 706 | end_mask=masks[x], 707 | hate_path=hate_path), 708 | shell=True) 709 | hcatProcess.wait() 710 | except KeyboardInterrupt: 711 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 712 | hcatProcess.kill() 713 | try: 714 | for x in range(len(masks)): 715 | hcatProcess = subprocess.Popen( 716 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 " 717 | "-j '${middle_mask}' -k '${end_mask}' {left} {right} {tuning} --potfile-path={hate_path}/hashcat.pot".format( 718 | hcatBin=hcatBin, 719 | hash_type=hcatHashType, 720 | hash_file=hcatHashFile, 721 | session_name=os.path.basename(hcatHashFile), 722 | left=hcatThoroughBaseList, 723 | right=hcatThoroughBaseList, 724 | word_lists=hcatWordlists, 725 | tuning=hcatTuning, 726 | middle_mask=masks[x], 727 | end_mask=masks[x], 728 | hate_path=hate_path), 729 | shell=True) 730 | hcatProcess.wait() 731 | except KeyboardInterrupt: 732 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 733 | hcatProcess.kill() 734 | 735 | # Pathwell Mask Brute Force Attack 736 | def hcatPathwellBruteForce(hcatHashType, hcatHashFile): 737 | global hcatProcess 738 | hcatProcess = subprocess.Popen( 739 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 3 {hate_path}/masks/pathwell.hcmask " 740 | "{tuning} --potfile-path={hate_path}/hashcat.pot".format( 741 | hcatBin=hcatBin, 742 | hash_type=hcatHashType, 743 | hash_file=hcatHashFile, 744 | session_name=os.path.basename(hcatHashFile), 745 | tuning=hcatTuning, 746 | hate_path=hate_path), shell=True) 747 | try: 748 | hcatProcess.wait() 749 | except KeyboardInterrupt: 750 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 751 | hcatProcess.kill() 752 | 753 | 754 | # PRINCE Attack 755 | def hcatPrince(hcatHashType, hcatHashFile): 756 | global hcatProcess 757 | hcatHashCracked = lineCount(hcatHashFile + ".out") 758 | hcatProcess = subprocess.Popen( 759 | "{hate_path}/princeprocessor/{prince_bin} --case-permute --elem-cnt-min=1 --elem-cnt-max=16 -c < " 760 | "{hcatPrinceBaseList} | {hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out " 761 | "-r {hate_path}/princeprocessor/rules/prince_optimized.rule {tuning} --potfile-path={hate_path}/hashcat.pot".format( 762 | hcatBin=hcatBin, 763 | prince_bin=hcatPrinceBin, 764 | hash_type=hcatHashType, 765 | hash_file=hcatHashFile, 766 | session_name=os.path.basename(hcatHashFile), 767 | hcatPrinceBaseList=hcatPrinceBaseList, 768 | tuning=hcatTuning, 769 | hate_path=hate_path), shell=True) 770 | try: 771 | hcatProcess.wait() 772 | except KeyboardInterrupt: 773 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 774 | hcatProcess.kill() 775 | 776 | # Extra - Good Measure 777 | def hcatGoodMeasure(hcatHashType, hcatHashFile): 778 | global hcatExtraCount 779 | global hcatProcess 780 | hcatProcess = subprocess.Popen( 781 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -r {hcatPath}/rules/combinator.rule " 782 | "-r {hcatPath}/rules/InsidePro-PasswordsPro.rule {hcatGoodMeasureBaseList} {tuning} " 783 | "--potfile-path={hate_path}/hashcat.pot".format( 784 | hcatPath=hcatPath, 785 | hcatBin=hcatBin, 786 | hash_type=hcatHashType, 787 | hash_file=hcatHashFile, 788 | hcatGoodMeasureBaseList=hcatGoodMeasureBaseList, 789 | session_name=os.path.basename(hcatHashFile), 790 | word_lists=hcatWordlists, 791 | tuning=hcatTuning, 792 | hate_path=hate_path), shell=True) 793 | try: 794 | hcatProcess.wait() 795 | except KeyboardInterrupt: 796 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 797 | hcatProcess.kill() 798 | 799 | hcatExtraCount = lineCount(hcatHashFile + ".out") - hcatHashCracked 800 | 801 | 802 | # LanMan to NT Attack 803 | def hcatLMtoNT(): 804 | global hcatProcess 805 | hcatProcess = subprocess.Popen( 806 | "{hcatBin} --show --potfile-path={hate_path}/hashcat.pot -m 3000 {hash_file}.lm > {hash_file}.lm.cracked".format( 807 | hcatBin=hcatBin, 808 | hash_file=hcatHashFile, 809 | hate_path=hate_path), shell=True) 810 | try: 811 | hcatProcess.wait() 812 | except KeyboardInterrupt: 813 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 814 | hcatProcess.kill() 815 | 816 | hcatProcess = subprocess.Popen( 817 | "{hcatBin} -m 3000 {hash_file}.lm --session {session_name} -o {hash_file}.lm.cracked -1 ?u?d?s --increment -a 3 ?1?1?1?1?1?1?1 " 818 | "{tuning} --potfile-path={hate_path}/hashcat.pot".format( 819 | hcatBin=hcatBin, 820 | hash_file=hcatHashFile, 821 | session_name=os.path.basename(hcatHashFile), 822 | tuning=hcatTuning, 823 | hate_path=hate_path), shell=True) 824 | try: 825 | hcatProcess.wait() 826 | except KeyboardInterrupt: 827 | hcatProcess.kill() 828 | 829 | hcatProcess = subprocess.Popen("cat {hash_file}.lm.cracked | cut -d : -f 2 > {hash_file}.working".format( 830 | hash_file=hcatHashFile), shell=True).wait() 831 | converted = convert_hex("{hash_file}.working".format(hash_file=hcatHashFile)) 832 | with open("{hash_file}.working".format(hash_file=hcatHashFile),mode='w') as working: 833 | working.writelines(converted) 834 | hcatProcess = subprocess.Popen( 835 | "{hate_path}/hashcat-utils/bin/{combine_bin} {hash_file}.working {hash_file}.working | sort -u > {hash_file}.combined".format( 836 | combine_bin=hcatCombinatorBin, 837 | hcatBin=hcatBin, 838 | hash_file=hcatHashFile, 839 | tuning=hcatTuning, 840 | hate_path=hate_path), shell=True) 841 | try: 842 | hcatProcess.wait() 843 | except KeyboardInterrupt: 844 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 845 | hcatProcess.kill() 846 | 847 | hcatProcess = subprocess.Popen( 848 | "{hcatBin} --show --potfile-path={hate_path}/hashcat.pot -m 1000 {hash_file}.nt > {hash_file}.nt.out".format( 849 | hcatBin=hcatBin, 850 | hash_file=hcatHashFile, 851 | tuning=hcatTuning, 852 | hate_path=hate_path), shell=True) 853 | try: 854 | hcatProcess.wait() 855 | except KeyboardInterrupt: 856 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 857 | hcatProcess.kill() 858 | 859 | hcatProcess = subprocess.Popen( 860 | "{hcatBin} -m 1000 {hash_file}.nt --session {session_name} -o {hash_file}.nt.out {hash_file}.combined " 861 | "-r {hate_path}/rules/toggles-lm-ntlm.rule {tuning} --potfile-path={hate_path}/hashcat.pot".format( 862 | hcatBin=hcatBin, 863 | hash_file=hcatHashFile, 864 | session_name=os.path.basename(hcatHashFile), 865 | tuning=hcatTuning, 866 | hate_path=hate_path), shell=True) 867 | try: 868 | hcatProcess.wait() 869 | except KeyboardInterrupt: 870 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 871 | hcatProcess.kill() 872 | 873 | # toggle-lm-ntlm.rule by Didier Stevens https://blog.didierstevens.com/2016/07/16/tool-to-generate-hashcat-toggle-rules/ 874 | 875 | 876 | # Recycle Cracked Passwords 877 | def hcatRecycle(hcatHashType, hcatHashFile, hcatNewPasswords): 878 | global hcatProcess 879 | working_file = hcatHashFile + '.working' 880 | if hcatNewPasswords > 0: 881 | hcatProcess = subprocess.Popen("cat {hash_file}.out | cut -d : -f 2 > {working_file}".format( 882 | hash_file=hcatHashFile, working_file=working_file), shell=True) 883 | try: 884 | hcatProcess.wait() 885 | except KeyboardInterrupt: 886 | print('Killing PID {0}...'.format(str(hcatProcess.pid))) 887 | hcatProcess.kill() 888 | 889 | converted = convert_hex(working_file) 890 | 891 | # Overwrite working file with updated converted words 892 | with open(working_file, 'w') as f: 893 | f.write("\n".join(converted)) 894 | for rule in hcatRules: 895 | hcatProcess = subprocess.Popen( 896 | "{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out {hash_file}.working " 897 | "-r {hcatPath}/rules/{rule} {tuning} --potfile-path={hate_path}/hashcat.pot".format( 898 | rule=rule, 899 | hcatBin=hcatBin, 900 | hash_type=hcatHashType, 901 | hash_file=hcatHashFile, 902 | session_name=os.path.basename(hcatHashFile), 903 | hcatPath=hcatPath, 904 | tuning=hcatTuning, 905 | hate_path=hate_path), shell=True) 906 | try: 907 | hcatProcess.wait() 908 | except KeyboardInterrupt: 909 | hcatProcess.kill() 910 | 911 | def check_potfile(): 912 | print("Checking POT file for already cracked hashes...") 913 | subprocess.Popen( 914 | "{hcatBin} --show --potfile-path={hate_path}/hashcat.pot -m {hash_type} {hash_file} > {hash_file}.out".format( 915 | hcatBin=hcatBin, 916 | hash_type=hcatHashType, 917 | hash_file=hcatHashFile, 918 | hate_path=hate_path), shell=True) 919 | hcatHashCracked = lineCount(hcatHashFile + ".out") 920 | if hcatHashCracked > 0: 921 | print("Found %d hashes already cracked.\nCopied hashes to %s.out" % (hcatHashCracked, hcatHashFile)) 922 | else: 923 | print("No hashes found in POT file.") 924 | 925 | 926 | # creating the combined output for pwdformat + cleartext 927 | def combine_ntlm_output(): 928 | hashes = {} 929 | check_potfile() 930 | with open(hcatHashFile + ".out", "r") as hcatCrackedFile: 931 | for crackedLine in hcatCrackedFile: 932 | hash, password = crackedLine.split(':') 933 | hashes[hash] = password.rstrip() 934 | with open(hcatHashFileOrig + ".out", "w+") as hcatCombinedHashes: 935 | with open(hcatHashFileOrig, "r") as hcatOrigFile: 936 | for origLine in hcatOrigFile: 937 | if origLine.split(':')[3] in hashes: 938 | password = hashes[origLine.split(':')[3]] 939 | hcatCombinedHashes.write(origLine.strip()+password+'\n') 940 | 941 | # Cleanup Temp Files 942 | def cleanup(): 943 | global pwdump_format 944 | global hcatHashFileOrig 945 | try: 946 | if hcatHashType == "1000" and pwdump_format: 947 | print("\nComparing cracked hashes to original file...") 948 | combine_ntlm_output() 949 | print("\nCracked passwords combined with original hashes in %s" % (hcatHashFileOrig + ".out")) 950 | print('\nCleaning up temporary files...') 951 | if os.path.exists(hcatHashFile + ".masks"): 952 | os.remove(hcatHashFile + ".masks") 953 | if os.path.exists(hcatHashFile + ".working"): 954 | os.remove(hcatHashFile + ".working") 955 | if os.path.exists(hcatHashFile + ".expanded"): 956 | os.remove(hcatHashFile + ".expanded") 957 | if os.path.exists(hcatHashFileOrig + ".combined"): 958 | os.remove(hcatHashFileOrig + ".combined") 959 | if os.path.exists(hcatHashFileOrig + ".lm"): 960 | os.remove(hcatHashFileOrig + ".lm") 961 | if os.path.exists(hcatHashFileOrig + ".lm.cracked"): 962 | os.remove(hcatHashFileOrig + ".lm.cracked") 963 | if os.path.exists(hcatHashFileOrig + ".working"): 964 | os.remove(hcatHashFileOrig + ".working") 965 | if os.path.exists(hcatHashFileOrig + ".passwords"): 966 | os.remove(hcatHashFileOrig + ".passwords") 967 | except KeyboardInterrupt: 968 | #incase someone mashes the Control+C it will still cleanup 969 | cleanup() 970 | 971 | # Quick Dictionary Attack with Optional Chained Rules 972 | def quick_crack(): 973 | # Rules Attack 974 | wordlist_choice = None 975 | rule_choice = None 976 | selected_hcatRules = [] 977 | 978 | wordlist_files = sorted(os.listdir(hcatWordlists)) 979 | print("\nWordlists:") 980 | for i, file in enumerate(wordlist_files, start=1): 981 | print(f"{i}. {file}") 982 | 983 | while wordlist_choice is None: 984 | try: 985 | raw_choice = input("\nEnter path of wordlist or wordlist directory.\n" 986 | "Press Enter for default optimized wordlists [{0}]: ".format(hcatOptimizedWordlists)) 987 | if raw_choice == '': 988 | wordlist_choice = hcatOptimizedWordlists 989 | elif os.path.exists(raw_choice): 990 | wordlist_choice = raw_choice 991 | elif 1 <= int(raw_choice) <= len(wordlist_files): 992 | if os.path.exists(hcatWordlists + '/' + wordlist_files[int(raw_choice) - 1]): 993 | wordlist_choice = hcatWordlists + '/' + wordlist_files[int(raw_choice) - 1] 994 | print(wordlist_choice) 995 | else: 996 | wordlist_choice = None 997 | print('Please enter a valid wordlist or wordlist directory.') 998 | except ValueError: 999 | print("Please enter a valid number.") 1000 | 1001 | rule_files = sorted(os.listdir(hcatPath + '/rules')) 1002 | print("\nWhich rule(s) would you like to run?") 1003 | print('0. To run without any rules') 1004 | for i, file in enumerate(rule_files, start=1): 1005 | print(f"{i}. {file}") 1006 | print('99. YOLO...run all of the rules') 1007 | 1008 | while rule_choice is None: 1009 | raw_choice = input('Enter Comma separated list of rules you would like to run. To run rules chained use the + symbol.\n' 1010 | 'For example 1+1 will run {0} chained twice and 1,2 would run {0} and then {1} sequentially.\n' 1011 | 'Choose wisely: '.format(rule_files[0], rule_files[1])) 1012 | if raw_choice != '': 1013 | rule_choice = raw_choice.split(',') 1014 | 1015 | if '99' in rule_choice: 1016 | for rule in rule_files: 1017 | selected_hcatRules.append('-r {hcatPath}/rules/{selected_rule}'.format(selected_rule=rule, hcatPath=hcatPath)) 1018 | elif '0' in rule_choice: 1019 | selected_hcatRules = [''] 1020 | else: 1021 | for choice in rule_choice: 1022 | if '+' in choice: 1023 | combined_choice = '' 1024 | choices = choice.split('+') 1025 | for rule in choices: 1026 | try: 1027 | combined_choice = '{0} {1}'.format(combined_choice, '-r {hcatPath}/rules/{selected_rule}'.format(selected_rule=rule_files[int(rule) - 1], 1028 | hcatPath=hcatPath)) 1029 | except: 1030 | continue 1031 | selected_hcatRules.append(combined_choice) 1032 | else: 1033 | try: 1034 | selected_hcatRules.append('-r {hcatPath}/rules/{selected_rule}'.format(selected_rule=rule_files[int(choice) - 1],hcatPath=hcatPath)) 1035 | except IndexError: 1036 | continue 1037 | 1038 | #Run Quick Crack with each selected rule 1039 | for chain in selected_hcatRules: 1040 | hcatQuickDictionary(hcatHashType, hcatHashFile, chain, wordlist_choice) 1041 | 1042 | 1043 | # Extensive Pure_Hate Methodology 1044 | def extensive_crack(): 1045 | # Brute Force Attack 1046 | hcatBruteForce(hcatHashType, hcatHashFile, "1", "7") 1047 | 1048 | # Recycle Cracked Passwords 1049 | hcatRecycle(hcatHashType, hcatHashFile, hcatBruteCount) 1050 | 1051 | # Dictionary Attack 1052 | hcatDictionary(hcatHashType, hcatHashFile) 1053 | 1054 | # Recycle Cracked Passwords 1055 | hcatRecycle(hcatHashType, hcatHashFile, hcatDictionaryCount) 1056 | 1057 | # Top Mask Attack 1058 | hcatTargetTime = 4 * 60 * 60 # 4 Hours 1059 | hcatTopMask(hcatHashType, hcatHashFile, hcatTargetTime) 1060 | 1061 | # Recycle Cracked Passwords 1062 | hcatRecycle(hcatHashType, hcatHashFile, hcatMaskCount) 1063 | 1064 | # Fingerprint Attack 1065 | hcatFingerprint(hcatHashType, hcatHashFile) 1066 | 1067 | # Recycle Cracked Passwords 1068 | hcatRecycle(hcatHashType, hcatHashFile, hcatFingerprintCount) 1069 | 1070 | # Combination Attack 1071 | hcatCombination(hcatHashType, hcatHashFile) 1072 | 1073 | # Recycle Cracked Passwords 1074 | hcatRecycle(hcatHashType, hcatHashFile, hcatCombinationCount) 1075 | 1076 | # Hybrid Attack 1077 | hcatHybrid(hcatHashType, hcatHashFile) 1078 | 1079 | # Recycle Cracked Passwords 1080 | hcatRecycle(hcatHashType, hcatHashFile, hcatHybridCount) 1081 | 1082 | # Extra - Just For Good Measure 1083 | hcatGoodMeasure(hcatHashType, hcatHashFile) 1084 | 1085 | # Recycle Cracked Passwords 1086 | hcatRecycle(hcatHashType, hcatHashFile, hcatExtraCount) 1087 | 1088 | 1089 | # Brute Force 1090 | def brute_force_crack(): 1091 | hcatMinLen = int(input("\nEnter the minimum password length to brute force (1): ") or 1) 1092 | hcatMaxLen = int(input("\nEnter the maximum password length to brute force (7): ") or 7) 1093 | hcatBruteForce(hcatHashType, hcatHashFile, hcatMinLen, hcatMaxLen) 1094 | 1095 | 1096 | # Top Mask 1097 | def top_mask_crack(): 1098 | hcatTargetTime = int(input("\nEnter a target time for completion in hours (4): ") or 4) 1099 | hcatTargetTime = hcatTargetTime * 60 * 60 1100 | hcatTopMask(hcatHashType, hcatHashFile, hcatTargetTime) 1101 | 1102 | 1103 | # Fingerprint 1104 | def fingerprint_crack(): 1105 | hcatFingerprint(hcatHashType, hcatHashFile) 1106 | 1107 | 1108 | # Combinator 1109 | def combinator_crack(): 1110 | hcatCombination(hcatHashType, hcatHashFile) 1111 | 1112 | 1113 | # Hybrid 1114 | def hybrid_crack(): 1115 | hcatHybrid(hcatHashType, hcatHashFile) 1116 | 1117 | 1118 | # Pathwell Top 100 Bruteforce Mask 1119 | def pathwell_crack(): 1120 | # Bruteforce Mask Attack 1121 | hcatPathwellBruteForce(hcatHashType, hcatHashFile) 1122 | 1123 | 1124 | # PRINCE Attack 1125 | def prince_attack(): 1126 | hcatPrince(hcatHashType, hcatHashFile) 1127 | 1128 | 1129 | # YOLO Combination 1130 | def yolo_combination(): 1131 | hcatYoloCombination(hcatHashType, hcatHashFile) 1132 | 1133 | # Thorough Combinator 1134 | def thorough_combinator(): 1135 | hcatThoroughCombinator(hcatHashType, hcatHashFile) 1136 | 1137 | # Middle Combinator 1138 | def middle_combinator(): 1139 | hcatMiddleCombinator(hcatHashType, hcatHashFile) 1140 | 1141 | # Bandrel Methodology 1142 | def bandrel_method(): 1143 | hcatBandrel(hcatHashType, hcatHashFile) 1144 | 1145 | 1146 | # convert hex words for recycling 1147 | def convert_hex(working_file): 1148 | processed_words = [] 1149 | regex = r'^\$HEX\[(\S+)\]' 1150 | with open(working_file, 'r') as f: 1151 | for line in f: 1152 | match = re.search(regex, line.rstrip('\n')) 1153 | if match: 1154 | try: 1155 | processed_words.append(binascii.unhexlify(match.group(1)).decode('iso-8859-9')) 1156 | except UnicodeDecodeError: 1157 | pass 1158 | else: 1159 | processed_words.append(line.rstrip('\n')) 1160 | 1161 | return processed_words 1162 | 1163 | # Display Cracked Hashes 1164 | def show_results(): 1165 | if os.path.isfile(hcatHashFile + ".out"): 1166 | with open(hcatHashFile + ".out") as hcatOutput: 1167 | for cracked_hash in hcatOutput: 1168 | print(cracked_hash.strip()) 1169 | else: 1170 | print("No hashes were cracked :(") 1171 | 1172 | # Analyze Hashes with Pipal 1173 | def pipal(): 1174 | hcatHashFilePipal = hcatHashFile 1175 | if hcatHashType == "1000": 1176 | combine_ntlm_output() 1177 | hcatHashFilePipal = hcatHashFileOrig 1178 | 1179 | if os.path.isfile(pipalPath): 1180 | if os.path.isfile(hcatHashFilePipal + ".out"): 1181 | pipalFile = open(hcatHashFilePipal + ".passwords", 'w') 1182 | with open(hcatHashFilePipal + ".out") as hcatOutput: 1183 | for cracked_hash in hcatOutput: 1184 | password = cracked_hash.split(':') 1185 | clearTextPass = password[-1] 1186 | match = re.search(r'^\$HEX\[(\S+)\]', clearTextPass) 1187 | if match: 1188 | clearTextPass = binascii.unhexlify(match.group(1)).decode('iso-8859-9') 1189 | pipalFile.write(clearTextPass) 1190 | pipalFile.close() 1191 | 1192 | pipalProcess = subprocess.Popen( 1193 | "{pipal_path} {pipal_file} -t {pipal_count} --output {pipal_out}".format( 1194 | pipal_path=pipalPath, 1195 | pipal_file=hcatHashFilePipal + ".passwords", 1196 | pipal_out=hcatHashFilePipal + ".pipal", 1197 | pipal_count=pipal_count), 1198 | shell=True) 1199 | try: 1200 | pipalProcess.wait() 1201 | except KeyboardInterrupt: 1202 | print('Killing PID {0}...'.format(str(pipalProcess.pid))) 1203 | pipalProcess.kill() 1204 | print("Pipal file is at " + hcatHashFilePipal + ".pipal\n") 1205 | with open(hcatHashFilePipal + ".pipal") as pipalfile: 1206 | pipal_content = pipalfile.readlines() 1207 | raw_pipal = '\n'.join(pipal_content) 1208 | raw_pipal = re.sub('\n+', '\n', raw_pipal) 1209 | raw_regex = r'Top [0-9]+ base words\n' 1210 | for word in range(pipal_count): 1211 | raw_regex += r'(\S+).*\n' 1212 | basewords_re = re.compile(raw_regex) 1213 | results = re.search(basewords_re,raw_pipal) 1214 | top_basewords = [] 1215 | for i in range(1, results.lastindex + 1): 1216 | top_basewords.append(results.group(i)) 1217 | return(top_basewords) 1218 | else: 1219 | print("No hashes were cracked :(") 1220 | else: 1221 | print("The path to pipal.rb is either not set, or is incorrect.") 1222 | 1223 | 1224 | 1225 | # Exports output to excel file 1226 | def export_excel(): 1227 | 1228 | # Check for openyxl dependancy for export 1229 | try: 1230 | import openpyxl 1231 | except: 1232 | sys.stderr.write('You must install openpyxl first using \'pip install openpyxl\' or \'pip3 install openpyxl\'\n') 1233 | return 1234 | 1235 | if hcatHashType == "1000": 1236 | combine_ntlm_output() 1237 | output = openpyxl.Workbook() 1238 | current_ws = output.create_sheet(title='hate_crack output', index=0) 1239 | current_row = 2 1240 | current_ws['A1'] = 'Username' 1241 | current_ws['B1'] = 'SID' 1242 | current_ws['C1'] = 'LM Hash' 1243 | current_ws['D1'] = 'NTLM Hash' 1244 | current_ws['E1'] = 'Clear-Text Password' 1245 | with open(hcatHashFileOrig+'.out') as input_file: 1246 | for line in input_file: 1247 | matches = re.match(r'(^[^:]+):([0-9]+):([a-z0-9A-Z]{32}):([a-z0-9A-Z]{32}):::(.*)',line.rstrip('\r\n')) 1248 | username = matches.group(1) 1249 | sid = matches.group(2) 1250 | lm = matches.group(3) 1251 | ntlm = matches.group(4) 1252 | try: 1253 | clear_text = matches.group(5) 1254 | match = re.search(r'^\$HEX\[(\S+)\]', clear_text) 1255 | if match: 1256 | clear_text = binascii.unhexlify(match.group(1)).decode('iso-8859-9') 1257 | except: 1258 | clear_text = '' 1259 | current_ws['A' + str(current_row)] = username 1260 | current_ws['B' + str(current_row)] = sid 1261 | current_ws['C' + str(current_row)] = lm 1262 | current_ws['D' + str(current_row)] = ntlm 1263 | current_ws['E' + str(current_row)] = clear_text 1264 | current_row += 1 1265 | output.save(hcatHashFile+'.xlsx') 1266 | print("Output exported succesfully to {0}".format(hcatHashFile+'.xlsx')) 1267 | else: 1268 | sys.stderr.write('Excel output only supported for pwdformat for NTLM hashes') 1269 | return 1270 | 1271 | 1272 | # Show README 1273 | def show_readme(): 1274 | with open(hate_path + "/readme.md") as hcatReadme: 1275 | print(hcatReadme.read()) 1276 | 1277 | 1278 | # Exit Program 1279 | def quit_hc(): 1280 | cleanup() 1281 | sys.exit(0) 1282 | 1283 | 1284 | # The Main Guts 1285 | def main(): 1286 | global pwdump_format 1287 | global hcatHashFile 1288 | global hcatHashType 1289 | global hcatHashFileOrig 1290 | global lmHashesFound 1291 | 1292 | try: 1293 | hcatHashFile = sys.argv[1] 1294 | hcatHashType = sys.argv[2] 1295 | 1296 | except IndexError: 1297 | usage() 1298 | sys.exit() 1299 | 1300 | hcatHashFileOrig = hcatHashFile 1301 | ascii_art() 1302 | 1303 | # Get Initial Input Hash Count 1304 | hcatHashCount = lineCount(hcatHashFile) 1305 | 1306 | # If LM or NT Mode Selected and pwdump Format Detected, Prompt For LM to NT Attack 1307 | if hcatHashType == "1000": 1308 | lmHashesFound = False 1309 | pwdump_format = False 1310 | hcatHashFileLine = open(hcatHashFile, "r").readline() 1311 | if re.search(r"[a-f0-9A-F]{32}:[a-f0-9A-F]{32}:::", hcatHashFileLine): 1312 | pwdump_format = True 1313 | print("PWDUMP format detected...") 1314 | print("Parsing NT hashes...") 1315 | subprocess.Popen( 1316 | "cat {hash_file} | cut -d : -f 4 |sort -u > {hash_file}.nt".format(hash_file=hcatHashFile), 1317 | shell=True).wait() 1318 | print("Parsing LM hashes...") 1319 | subprocess.Popen("cat {hash_file} | cut -d : -f 3 |sort -u > {hash_file}.lm".format(hash_file=hcatHashFile), 1320 | shell=True).wait() 1321 | if ((lineCount(hcatHashFile + ".lm") == 1) and ( 1322 | hcatHashFileLine.split(":")[2].lower() != "aad3b435b51404eeaad3b435b51404ee")) or ( 1323 | lineCount(hcatHashFile + ".lm") > 1): 1324 | lmHashesFound = True 1325 | lmChoice = input("LM hashes identified. Would you like to brute force the LM hashes first? (Y) ") or "Y" 1326 | if lmChoice.upper() == 'Y': 1327 | hcatLMtoNT() 1328 | hcatHashFileOrig = hcatHashFile 1329 | hcatHashFile = hcatHashFile + ".nt" 1330 | elif re.search(r"^[a-f0-9A-F]{32}$", hcatHashFileLine): 1331 | pwdump_format = False 1332 | print("PWDUMP format was not detected...") 1333 | print("Hash only detected") 1334 | elif re.search(r"^.+:[a-f0-9A-F]{32}$", hcatHashFileLine): 1335 | pwdump_format = False 1336 | print("PWDUMP format was not detected...") 1337 | print("username with Hash detected") 1338 | subprocess.Popen( 1339 | "cat {hash_file} | cut -d : -f 2 |sort -u > {hash_file}.nt".format(hash_file=hcatHashFile), 1340 | shell=True).wait() 1341 | hcatHashFileOrig = hcatHashFile 1342 | hcatHashFile = hcatHashFile + ".nt" 1343 | else: 1344 | print("unknown format....does it have usernames?") 1345 | exit(1) 1346 | # Check POT File for Already Cracked Hashes 1347 | if not os.path.isfile(hcatHashFile + ".out"): 1348 | hcatOutput = open(hcatHashFile + ".out", "w+") 1349 | hcatOutput.close() 1350 | print("Checking POT file for already cracked hashes...") 1351 | subprocess.Popen( 1352 | "{hcatBin} --show --potfile-path={hate_path}/hashcat.pot -m {hash_type} {hash_file} > {hash_file}.out".format( 1353 | hcatBin=hcatBin, 1354 | hash_type=hcatHashType, 1355 | hash_file=hcatHashFile, 1356 | hate_path=hate_path), shell=True).wait() 1357 | hcatHashCracked = lineCount(hcatHashFile + ".out") 1358 | if hcatHashCracked > 0: 1359 | print("Found %d hashes already cracked.\nCopied hashes to %s.out" % (hcatHashCracked, hcatHashFile)) 1360 | else: 1361 | print("No hashes found in POT file.") 1362 | 1363 | # Display Options 1364 | try: 1365 | while 1: 1366 | print("\n\t(1) Quick Crack") 1367 | print("\t(2) Extensive Pure_Hate Methodology Crack") 1368 | print("\t(3) Brute Force Attack") 1369 | print("\t(4) Top Mask Attack") 1370 | print("\t(5) Fingerprint Attack") 1371 | print("\t(6) Combinator Attack") 1372 | print("\t(7) Hybrid Attack") 1373 | print("\t(8) Pathwell Top 100 Mask Brute Force Crack") 1374 | print("\t(9) PRINCE Attack") 1375 | print("\t(10) YOLO Combinator Attack") 1376 | print("\t(11) Middle Combinator Attack") 1377 | print("\t(12) Thorough Combinator Attack") 1378 | print("\t(13) Bandrel Methodology") 1379 | print("\n\t(95) Analyze hashes with Pipal") 1380 | print("\t(96) Export Output to Excel Format") 1381 | print("\t(97) Display Cracked Hashes") 1382 | print("\t(98) Display README") 1383 | print("\t(99) Quit") 1384 | options = {"1": quick_crack, 1385 | "2": extensive_crack, 1386 | "3": brute_force_crack, 1387 | "4": top_mask_crack, 1388 | "5": fingerprint_crack, 1389 | "6": combinator_crack, 1390 | "7": hybrid_crack, 1391 | "8": pathwell_crack, 1392 | "9": prince_attack, 1393 | "10": yolo_combination, 1394 | "11": middle_combinator, 1395 | "12": thorough_combinator, 1396 | "13": bandrel_method, 1397 | "95": pipal, 1398 | "96": export_excel, 1399 | "97": show_results, 1400 | "98": show_readme, 1401 | "99": quit_hc 1402 | } 1403 | try: 1404 | task = input("\nSelect a task: ") 1405 | options[task]() 1406 | except KeyError: 1407 | pass 1408 | except KeyboardInterrupt: 1409 | quit_hc() 1410 | 1411 | # Boilerplate 1412 | if __name__ == '__main__': 1413 | main() 1414 | -------------------------------------------------------------------------------- /masks/pathwell.hcmask: -------------------------------------------------------------------------------- 1 | ?u?l?l?l?l?l?d?d 2 | ?u?l?l?l?l?l?l?d?d 3 | ?u?l?l?l?d?d?d?d 4 | ?l?l?l?l?l?l?l?d 5 | ?u?l?l?l?l?l?l?l?d?d 6 | ?u?l?l?l?l?l?l?d 7 | ?u?l?l?l?l?l?d?d?d?d 8 | ?u?l?l?l?l?d?d?d?d 9 | ?l?l?l?l?l?l?d?d 10 | ?u?l?l?l?l?l?l?l?d 11 | ?u?l?l?l?l?d?d?d 12 | ?u?l?l?d?d?d?d?s 13 | ?l?l?l?l?l?l?l?l 14 | ?u?l?l?l?l?l?d?d?d 15 | ?l?l?l?l?l?l?l?d?d 16 | ?l?l?s?d?d?l?d?d?l 17 | ?l?l?l?l?l?l?l?l?d 18 | ?u?l?l?l?l?l?d?d?s 19 | ?u?l?l?l?l?l?l?d?d?d?d 20 | ?u?l?l?l?l?l?l?l?l?d?d 21 | ?u?l?l?l?l?l?d?s 22 | ?u?l?l?l?l?l?l?l?l?d 23 | ?u?l?l?l?l?l?d?d?d?d?s 24 | ?l?l?l?l?l?l?l?l?l 25 | ?l?l?l?l?l?l?l?l?d?d 26 | ?u?l?l?l?l?l?l?d?d?d 27 | ?l?l?l?l?l?d?d?d 28 | ?u?l?l?l?d?d?d?d?s 29 | ?u?l?l?l?l?l?l?l?d?d?d?d 30 | ?u?l?l?l?l?l?s?d?d 31 | ?u?u?u?u?u?u?d?l 32 | ?l?l?l?l?d?d?d?d 33 | ?d?d?u?l?l?l?l?l?l?l 34 | ?u?l?l?s?d?d?d?d 35 | ?u?l?l?l?l?d?d?s 36 | ?u?l?l?l?l?l?l?d?s 37 | ?d?d?u?l?l?l?l?l?l 38 | ?l?l?l?l?s?d?d?d 39 | ?l?l?l?l?l?l?l?l?l?d 40 | ?l?l?l?l?l?d?d?d?d 41 | ?l?l?l?l?l?l?l?l?l?l 42 | ?l?l?l?l?l?l?d?d?d 43 | ?u?l?l?l?l?l?l?l?l?l?d?d 44 | ?u?l?l?l?l?l?l?l?l?l?d 45 | ?d?d?d?d?d?d?u?l 46 | ?u?l?l?l?l?l?l?l?d?d?d 47 | ?u?l?l?l?l?l?l?d?d?s 48 | ?u?u?u?u?u?u?d?s 49 | ?u?u?d?l?l?l?d?d?d?u 50 | ?u?l?l?l?l?s?d?d 51 | ?u?l?l?l?l?l?s?d 52 | ?l?l?l?s?d?d?d?d 53 | ?l?l?l?l?l?l?d?d?d?d 54 | ?u?l?l?l?l?l?l?l?d?d?s 55 | ?d?d?u?l?l?l?l?l 56 | ?u?l?l?l?l?l?l?l?d?s 57 | ?u?l?l?l?l?d?d?d?s 58 | ?u?l?l?l?l?d?d?d?d?s 59 | ?u?l?l?l?s?d?d?d?d 60 | ?u?l?l?l?l?s?d?d?d 61 | ?u?l?l?l?l?l?l?d?d?d?d?s 62 | ?u?l?l?l?d?d?d?s 63 | ?l?l?l?l?s?d?d?d?d 64 | ?l?l?l?l?l?l?s?d?d 65 | ?l?l?l?l?l?l?d?d?s 66 | ?d?d?d?d?u?l?l?l 67 | ?d?d?d?d?d?d?d?d 68 | ?u?l?l?l?l?l?l?s?d 69 | ?u?l?d?d?d?d?d?d 70 | ?l?l?l?l?l?l?s?d 71 | ?u?d?l?l?l?l?l?l?l?d 72 | ?l?l?l?l?l?l?l?l?l?l?l 73 | ?l?l?l?l?l?l?l?l?l?l?d 74 | ?l?l?l?l?l?d?d?s 75 | ?l?l?l?l?d?d?d?s 76 | ?u?l?l?l?l?l?l?l?l?d?d?d?d 77 | ?u?u?u?u?u?u?u?u 78 | ?u?l?l?l?s?d?d?d 79 | ?u?l?l?l?l?l?l?s?d?d 80 | ?u?l?l?l?l?l?d?d?d?s 81 | ?l?l?l?l?l?s?d?d 82 | ?u?l?l?l?l?s?d?d?d?d 83 | ?u?l?l?l?d?d?d?d?d 84 | ?u?l?l?d?d?d?d?d?d 85 | ?u?l?l?d?d?d?d?d 86 | ?l?l?l?l?l?l?l?l?l?d?d 87 | ?l?l?l?l?l?l?l?d?d?s 88 | ?l?l?l?l?l?l?l?d?d?d 89 | ?l?l?l?l?l?l?d?s 90 | ?l?l?l?d?d?d?d?s 91 | ?u?u?u?l?l?l?d?d?d?d 92 | ?u?l?l?l?l?l?s?d?d?d 93 | ?u?l?l?l?l?l?l?l?s?d 94 | ?l?l?l?l?l?l?l?l?s?d 95 | ?l?l?l?l?l?l?l?d?d?d?d 96 | ?u?l?l?l?l?l?s?d?d?d?d 97 | ?l?l?l?l?l?l?l?d?s 98 | ?l?l?l?l?d?d?d?d?s 99 | ?d?d?d?d?u?l?l?l?l 100 | ?u?u?d?l?l?l?d?d?d?d 101 | -------------------------------------------------------------------------------- /princeprocessor/CHANGES: -------------------------------------------------------------------------------- 1 | * v0.20 -> v0.21: 2 | 3 | - Exit if stdout is closed or has a error 4 | - Fix for "Bug --pw-min" issue 5 | - Print position when stopped 6 | - Allow wordlist as fileparameter 7 | - Load only NUM words from input wordlist or use 0 to disable 8 | 9 | * v0.19 -> v0.20: 10 | 11 | - Add dupe suppression 12 | - Add a fake-GMP header using uint128_t macros. This is to replace depency on GMP 13 | - Add --case-permute amplifier option, default is disabled 14 | - Fixed buffer overflow 15 | - Fixed accidental reverted changes 16 | - Fixed a bug where ee actually couldn't correctly support output longer than 31 but 32 is supported 17 | - More memory savings: Use only the actual space needed for each word 18 | 19 | * v0.18 -> v0.19: 20 | 21 | - Fixed missing free() in shutdown section 22 | - Fixed wrong version number in source 23 | - Fixed discrepancies with logic and error messages 24 | - Added validation check pw-max > elem-cnt-max 25 | - Untie IN_LEN_* from PW_* to allow --pw-max > 16 without recompilation 26 | - If out of memory, tell how much we tried to allocate 27 | - Allow hex input for --skip and --limit 28 | - Optimized output performance 29 | 30 | * v0.17 -> v0.18: 31 | 32 | - Fixed major bug where all candidates are of the same length till chain changes 33 | 34 | * v0.16 -> v0.17: 35 | 36 | - Fixed download url for binaries in README 37 | - Fixed copy paste bug in input verification 38 | - Fixed bug where pw_orders is not sorted 39 | - Fixed memory leak 40 | - Removed O_BINARY for stderr 41 | - Removed some unused code 42 | - Renamed variables so that they match the meaning from the presentation slides 43 | - Optimized seeking performance 44 | - Optimized output performance 45 | 46 | * v0.15 -> v0.16: 47 | 48 | - Open Source the project 49 | - License is MIT 50 | - Moved repository to github: https://github.com/jsteube/princeprocessor 51 | - Added CHANGES 52 | - Added LICENSE 53 | - Added README.md 54 | - Changed default value for --pw-max from 24 to 16 for faster startup time 55 | 56 | -------------------------------------------------------------------------------- /princeprocessor/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jens Steube, 4 | Copyright (c) 2015 magnum 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | ------ 25 | 26 | malloc_tiny() and the hashed dupe suppression are based on code from John the 27 | Ripper password cracker: 28 | Copyright (c) 1996-99,2002-2003,2005-2006,2010-2012 by Solar Designer 29 | 30 | Redistribution and use in source and binary forms, with or without 31 | modification, are permitted. 32 | 33 | There's ABSOLUTELY NO WARRANTY, express or implied. 34 | -------------------------------------------------------------------------------- /princeprocessor/README.md: -------------------------------------------------------------------------------- 1 | princeprocessor 2 | ============== 3 | 4 | Standalone password candidate generator using the PRINCE algorithm 5 | 6 | The name PRINCE is used as an acronym and stands for PRobability INfinite Chained Elements, which are the building blocks of the algorithm 7 | 8 | Brief description 9 | -------------- 10 | 11 | The princeprocessor is a password candidate generator and can be thought of as an advanced combinator attack. Rather than taking as input two different wordlists and then outputting all the possible two word combinations though, princeprocessor only has one input wordlist and builds "chains" of combined words. These chains can have 1 to N words from the input wordlist concatenated together. So for example if it is outputting guesses of length four, it could generate them using combinations from the input wordlist such as: 12 | 13 | - 4 letter word 14 | - 2 letter word + 2 letter word 15 | - 1 letter word + 3 letter word 16 | - 3 letter word + 1 letter word 17 | - 1 letter word + 1 letter word + 2 letter word 18 | - 1 letter word + 2 letter word + 1 letter word 19 | - 2 letter word + 1 letter word + 1 letter word 20 | - 1 letter word + 1 letter word + 1 letter word + 1 letter word 21 | 22 | Detailed description 23 | -------------- 24 | 25 | I'm going to write a detailed description in case I'm extremely bored. Till that, use the following resources: 26 | 27 | - My talk about princeprocessor on Passwords^14 conference in Trondheim, Norway. Slides: https://hashcat.net/events/p14-trondheim/prince-attack.pdf 28 | - Thanks to Matt Weir, he made a nice analysis of princeprocessor. You can find the post on his blog: http://reusablesec.blogspot.de/2014/12/tool-deep-dive-prince.html 29 | 30 | Compile 31 | -------------- 32 | 33 | Simply run make 34 | 35 | Binary distribution 36 | -------------- 37 | 38 | Binaries for Linux, Windows and OSX: https://github.com/jsteube/princeprocessor/releases 39 | -------------------------------------------------------------------------------- /princeprocessor/pp.save: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /princeprocessor/pp64.app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/princeprocessor/pp64.app -------------------------------------------------------------------------------- /princeprocessor/pp64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/princeprocessor/pp64.bin -------------------------------------------------------------------------------- /princeprocessor/pp64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustedsec/hate_crack/58c7ec8a3be24f9e81031939169fcc8beea74692/princeprocessor/pp64.exe -------------------------------------------------------------------------------- /princeprocessor/rules/prince_optimized.rule: -------------------------------------------------------------------------------- 1 | ## Name: prince.rule 2 | ## Version: 1.00 3 | ## Compatibility: hashcat v0.48+, oclHashcat v1.31+ 4 | ## 5 | ## Description: 6 | ## 7 | ## Handwritten ruleset, documented, optimized rule for use with princeprocessor 8 | ## This rule can be used as amplifier in case you're attacking a fast hash 9 | 10 | : 11 | 12 | ## Global cases 13 | 14 | l 15 | u 16 | c 17 | C 18 | t 19 | E 20 | 21 | ## Reverse the entire word, Duplicate entire word, Duplicate word reversed 22 | 23 | r 24 | d 25 | f 26 | 27 | ## Duplicate every character, multiple times 28 | 29 | q 30 | qq 31 | qqq 32 | 33 | ## Swaps first two characters, Swaps last two characters, both 34 | 35 | k 36 | K 37 | kK 38 | 39 | ## Deletes character at position N, up to length 15 40 | 41 | D1 42 | D2 43 | D3 44 | D4 45 | D5 46 | D6 47 | D7 48 | D8 49 | D9 50 | DA 51 | DB 52 | DC 53 | DD 54 | DE 55 | 56 | ## Truncate word at position N, positions 8 - 15 57 | 58 | '9 59 | 'A 60 | 'B 61 | 'C 62 | 'D 63 | 'E 64 | 65 | ## Duplicates first character N times, up to 6 times 66 | 67 | z1 68 | z2 69 | z3 70 | z4 71 | z5 72 | z6 73 | 74 | ## Duplicates last character N times, up to 6 times 75 | 76 | Z1 77 | Z2 78 | Z3 79 | Z4 80 | Z5 81 | Z6 82 | 83 | ## Duplicates first N characters, up to 6 times 84 | 85 | y1 86 | y2 87 | y3 88 | y4 89 | y5 90 | y6 91 | 92 | ## Duplicates last N characters, up to 6 times 93 | 94 | Y1 95 | Y2 96 | Y3 97 | Y4 98 | Y5 99 | Y6 100 | 101 | ## Deletes first character, Deletes last character, both combined (remove mutations) 102 | 103 | [ 104 | [ [ 105 | [ [ [ 106 | ] 107 | ] ] 108 | ] ] ] 109 | [ ] 110 | [ ] [ ] 111 | [ ] [ ] [ ] 112 | 113 | ## Deletes first character, Deletes last character, both combined (remove mutations), Capitalize word 114 | 115 | [ c 116 | [ [ c 117 | [ [ [ c 118 | ] c 119 | ] ] c 120 | ] ] ] c 121 | [ ] c 122 | [ ] [ ] c 123 | [ ] [ ] [ ] c 124 | 125 | ## Deletes first character, Deletes last character, both combined (remove mutations), Uppercase word 126 | 127 | [ u 128 | [ [ u 129 | [ [ [ u 130 | ] u 131 | ] ] u 132 | ] ] ] u 133 | [ ] u 134 | [ ] [ ] u 135 | [ ] [ ] [ ] u 136 | 137 | ## Rotates the word left and right 138 | 139 | { 140 | { { 141 | { { { 142 | } 143 | } } 144 | } } } 145 | 146 | ## Rotates the word left and right, Capitalize word 147 | 148 | { c 149 | { { c 150 | { { { c 151 | } c 152 | } } c 153 | } } } c 154 | 155 | ## Rotates the word left and right, Uppercase word 156 | 157 | [ u 158 | [ [ u 159 | [ [ [ u 160 | ] u 161 | ] ] u 162 | ] ] ] u 163 | [ ] u 164 | [ ] [ ] u 165 | [ ] [ ] [ ] u 166 | 167 | ## Increment character @ N by 1 ascii value, one char, up to length 15 168 | 169 | +0 170 | +1 171 | +2 172 | +3 173 | +4 174 | +5 175 | +6 176 | +7 177 | +8 178 | +9 179 | +A 180 | +B 181 | +C 182 | +D 183 | +E 184 | 185 | ## Increment character @ N by 1 ascii value, two chars, up to length 15 186 | 187 | +0 +1 188 | +0 +2 189 | +0 +3 190 | +0 +4 191 | +0 +5 192 | +0 +6 193 | +0 +7 194 | +0 +8 195 | +0 +9 196 | +0 +A 197 | +0 +B 198 | +0 +C 199 | +0 +D 200 | +0 +E 201 | +1 +2 202 | +1 +3 203 | +1 +4 204 | +1 +5 205 | +1 +6 206 | +1 +7 207 | +1 +8 208 | +1 +9 209 | +1 +A 210 | +1 +B 211 | +1 +C 212 | +1 +D 213 | +1 +E 214 | +2 +3 215 | +2 +4 216 | +2 +5 217 | +2 +6 218 | +2 +7 219 | +2 +8 220 | +2 +9 221 | +2 +A 222 | +2 +B 223 | +2 +C 224 | +2 +D 225 | +2 +E 226 | +3 +4 227 | +3 +5 228 | +3 +6 229 | +3 +7 230 | +3 +8 231 | +3 +9 232 | +3 +A 233 | +3 +B 234 | +3 +C 235 | +3 +D 236 | +3 +E 237 | +4 +5 238 | +4 +6 239 | +4 +7 240 | +4 +8 241 | +4 +9 242 | +4 +A 243 | +4 +B 244 | +4 +C 245 | +4 +D 246 | +4 +E 247 | +5 +6 248 | +5 +7 249 | +5 +8 250 | +5 +9 251 | +5 +A 252 | +5 +B 253 | +5 +C 254 | +5 +D 255 | +5 +E 256 | +6 +7 257 | +6 +8 258 | +6 +9 259 | +6 +A 260 | +6 +B 261 | +6 +C 262 | +6 +D 263 | +6 +E 264 | +7 +8 265 | +7 +9 266 | +7 +A 267 | +7 +B 268 | +7 +C 269 | +7 +D 270 | +7 +E 271 | +8 +9 272 | +8 +A 273 | +8 +B 274 | +8 +C 275 | +8 +D 276 | +8 +E 277 | +9 +A 278 | +9 +B 279 | +9 +C 280 | +9 +D 281 | +9 +E 282 | +A +B 283 | +A +C 284 | +A +D 285 | +A +E 286 | +B +C 287 | +B +D 288 | +B +E 289 | +C +D 290 | +C +E 291 | +D +E 292 | 293 | ## Decrement character @ N by 1 ascii value, one char, up to length 15 294 | 295 | -0 296 | -1 297 | -2 298 | -3 299 | -4 300 | -5 301 | -6 302 | -7 303 | -8 304 | -9 305 | -A 306 | -B 307 | -C 308 | -D 309 | -E 310 | 311 | ## Decrement character @ N by 1 ascii value, two chars, up to length 15 312 | 313 | -0 -1 314 | -0 -2 315 | -0 -3 316 | -0 -4 317 | -0 -5 318 | -0 -6 319 | -0 -7 320 | -0 -8 321 | -0 -9 322 | -0 -A 323 | -0 -B 324 | -0 -C 325 | -0 -D 326 | -0 -E 327 | -1 -2 328 | -1 -3 329 | -1 -4 330 | -1 -5 331 | -1 -6 332 | -1 -7 333 | -1 -8 334 | -1 -9 335 | -1 -A 336 | -1 -B 337 | -1 -C 338 | -1 -D 339 | -1 -E 340 | -2 -3 341 | -2 -4 342 | -2 -5 343 | -2 -6 344 | -2 -7 345 | -2 -8 346 | -2 -9 347 | -2 -A 348 | -2 -B 349 | -2 -C 350 | -2 -D 351 | -2 -E 352 | -3 -4 353 | -3 -5 354 | -3 -6 355 | -3 -7 356 | -3 -8 357 | -3 -9 358 | -3 -A 359 | -3 -B 360 | -3 -C 361 | -3 -D 362 | -3 -E 363 | -4 -5 364 | -4 -6 365 | -4 -7 366 | -4 -8 367 | -4 -9 368 | -4 -A 369 | -4 -B 370 | -4 -C 371 | -4 -D 372 | -4 -E 373 | -5 -6 374 | -5 -7 375 | -5 -8 376 | -5 -9 377 | -5 -A 378 | -5 -B 379 | -5 -C 380 | -5 -D 381 | -5 -E 382 | -6 -7 383 | -6 -8 384 | -6 -9 385 | -6 -A 386 | -6 -B 387 | -6 -C 388 | -6 -D 389 | -6 -E 390 | -7 -8 391 | -7 -9 392 | -7 -A 393 | -7 -B 394 | -7 -C 395 | -7 -D 396 | -7 -E 397 | -8 -9 398 | -8 -A 399 | -8 -B 400 | -8 -C 401 | -8 -D 402 | -8 -E 403 | -9 -A 404 | -9 -B 405 | -9 -C 406 | -9 -D 407 | -9 -E 408 | -A -B 409 | -A -C 410 | -A -D 411 | -A -E 412 | -B -C 413 | -B -D 414 | -B -E 415 | -C -D 416 | -C -E 417 | -D -E 418 | 419 | ## Swaps character X with Y, one char, up to length 15 420 | 421 | *01 422 | *02 423 | *03 424 | *04 425 | *05 426 | *06 427 | *07 428 | *08 429 | *09 430 | *0A 431 | *0B 432 | *0C 433 | *0D 434 | *0E 435 | *12 436 | *13 437 | *14 438 | *15 439 | *16 440 | *17 441 | *18 442 | *19 443 | *1A 444 | *1B 445 | *1C 446 | *1D 447 | *1E 448 | *23 449 | *24 450 | *25 451 | *26 452 | *27 453 | *28 454 | *29 455 | *2A 456 | *2B 457 | *2C 458 | *2D 459 | *2E 460 | *34 461 | *35 462 | *36 463 | *37 464 | *38 465 | *39 466 | *3A 467 | *3B 468 | *3C 469 | *3D 470 | *3E 471 | *45 472 | *46 473 | *47 474 | *48 475 | *49 476 | *4A 477 | *4B 478 | *4C 479 | *4D 480 | *4E 481 | *56 482 | *57 483 | *58 484 | *59 485 | *5A 486 | *5B 487 | *5C 488 | *5D 489 | *5E 490 | *67 491 | *68 492 | *69 493 | *6A 494 | *6B 495 | *6C 496 | *6D 497 | *6E 498 | *78 499 | *79 500 | *7A 501 | *7B 502 | *7C 503 | *7D 504 | *7E 505 | *89 506 | *8A 507 | *8B 508 | *8C 509 | *8D 510 | *8E 511 | *9A 512 | *9B 513 | *9C 514 | *9D 515 | *9E 516 | *AB 517 | *AC 518 | *AD 519 | *AE 520 | *BC 521 | *BD 522 | *BE 523 | *CD 524 | *CE 525 | *DE 526 | 527 | ## Replace all instances of X with Y (most common leetspeak chars) 528 | 529 | se3 530 | so0 531 | si1 532 | si! 533 | sa@ 534 | se3 so0 535 | se3 si1 536 | se3 si! 537 | se3 sa@ 538 | so0 si1 539 | so0 si! 540 | so0 sa@ 541 | si1 sa@ 542 | si! sa@ 543 | se3 so0 si1 544 | se3 so0 si! 545 | se3 so0 sa@ 546 | se3 si1 sa@ 547 | se3 si! sa@ 548 | so0 si1 sa@ 549 | so0 si! sa@ 550 | 551 | ## Replace all instances of X with Y (less common leetspeak chars) 552 | 553 | sl1 554 | slk 555 | sa4 556 | ss2 557 | ss5 558 | se6 559 | sun 560 | 561 | ## Replace all instances of X with Y, toggle the case of characters at position N 562 | 563 | se3 T0 564 | se3 T1 565 | se3 T2 566 | se3 T3 567 | se3 T4 568 | se3 T5 569 | se3 T6 570 | se3 T7 571 | se3 T8 572 | se3 T9 573 | se3 TA 574 | se3 TB 575 | se3 TC 576 | se3 TD 577 | se3 TE 578 | so0 T0 579 | so0 T1 580 | so0 T2 581 | so0 T3 582 | so0 T4 583 | so0 T5 584 | so0 T6 585 | so0 T7 586 | so0 T8 587 | so0 T9 588 | so0 TA 589 | so0 TB 590 | so0 TC 591 | so0 TD 592 | so0 TE 593 | si1 T0 594 | si1 T1 595 | si1 T2 596 | si1 T3 597 | si1 T4 598 | si1 T5 599 | si1 T6 600 | si1 T7 601 | si1 T8 602 | si1 T9 603 | si1 TA 604 | si1 TB 605 | si1 TC 606 | si1 TD 607 | si1 TE 608 | si! T0 609 | si! T1 610 | si! T2 611 | si! T3 612 | si! T4 613 | si! T5 614 | si! T6 615 | si! T7 616 | si! T8 617 | si! T9 618 | si! TA 619 | si! TB 620 | si! TC 621 | si! TD 622 | si! TE 623 | sa@ T0 624 | sa@ T1 625 | sa@ T2 626 | sa@ T3 627 | sa@ T4 628 | sa@ T5 629 | sa@ T6 630 | sa@ T7 631 | sa@ T8 632 | sa@ T9 633 | sa@ TA 634 | sa@ TB 635 | sa@ TC 636 | sa@ TD 637 | sa@ TE 638 | se3 so0 T0 639 | se3 so0 T1 640 | se3 so0 T2 641 | se3 so0 T3 642 | se3 so0 T4 643 | se3 so0 T5 644 | se3 so0 T6 645 | se3 so0 T7 646 | se3 so0 T8 647 | se3 so0 T9 648 | se3 so0 TA 649 | se3 so0 TB 650 | se3 so0 TC 651 | se3 so0 TD 652 | se3 so0 TE 653 | se3 si1 T0 654 | se3 si1 T1 655 | se3 si1 T2 656 | se3 si1 T3 657 | se3 si1 T4 658 | se3 si1 T5 659 | se3 si1 T6 660 | se3 si1 T7 661 | se3 si1 T8 662 | se3 si1 T9 663 | se3 si1 TA 664 | se3 si1 TB 665 | se3 si1 TC 666 | se3 si1 TD 667 | se3 si1 TE 668 | se3 si! T0 669 | se3 si! T1 670 | se3 si! T2 671 | se3 si! T3 672 | se3 si! T4 673 | se3 si! T5 674 | se3 si! T6 675 | se3 si! T7 676 | se3 si! T8 677 | se3 si! T9 678 | se3 si! TA 679 | se3 si! TB 680 | se3 si! TC 681 | se3 si! TD 682 | se3 si! TE 683 | se3 sa@ T0 684 | se3 sa@ T1 685 | se3 sa@ T2 686 | se3 sa@ T3 687 | se3 sa@ T4 688 | se3 sa@ T5 689 | se3 sa@ T6 690 | se3 sa@ T7 691 | se3 sa@ T8 692 | se3 sa@ T9 693 | se3 sa@ TA 694 | se3 sa@ TB 695 | se3 sa@ TC 696 | se3 sa@ TD 697 | se3 sa@ TE 698 | so0 si1 T0 699 | so0 si1 T1 700 | so0 si1 T2 701 | so0 si1 T3 702 | so0 si1 T4 703 | so0 si1 T5 704 | so0 si1 T6 705 | so0 si1 T7 706 | so0 si1 T8 707 | so0 si1 T9 708 | so0 si1 TA 709 | so0 si1 TB 710 | so0 si1 TC 711 | so0 si1 TD 712 | so0 si1 TE 713 | so0 si! T0 714 | so0 si! T1 715 | so0 si! T2 716 | so0 si! T3 717 | so0 si! T4 718 | so0 si! T5 719 | so0 si! T6 720 | so0 si! T7 721 | so0 si! T8 722 | so0 si! T9 723 | so0 si! TA 724 | so0 si! TB 725 | so0 si! TC 726 | so0 si! TD 727 | so0 si! TE 728 | so0 sa@ T0 729 | so0 sa@ T1 730 | so0 sa@ T2 731 | so0 sa@ T3 732 | so0 sa@ T4 733 | so0 sa@ T5 734 | so0 sa@ T6 735 | so0 sa@ T7 736 | so0 sa@ T8 737 | so0 sa@ T9 738 | so0 sa@ TA 739 | so0 sa@ TB 740 | so0 sa@ TC 741 | so0 sa@ TD 742 | so0 sa@ TE 743 | si1 sa@ T0 744 | si1 sa@ T1 745 | si1 sa@ T2 746 | si1 sa@ T3 747 | si1 sa@ T4 748 | si1 sa@ T5 749 | si1 sa@ T6 750 | si1 sa@ T7 751 | si1 sa@ T8 752 | si1 sa@ T9 753 | si1 sa@ TA 754 | si1 sa@ TB 755 | si1 sa@ TC 756 | si1 sa@ TD 757 | si1 sa@ TE 758 | si! sa@ T0 759 | si! sa@ T1 760 | si! sa@ T2 761 | si! sa@ T3 762 | si! sa@ T4 763 | si! sa@ T5 764 | si! sa@ T6 765 | si! sa@ T7 766 | si! sa@ T8 767 | si! sa@ T9 768 | si! sa@ TA 769 | si! sa@ TB 770 | si! sa@ TC 771 | si! sa@ TD 772 | si! sa@ TE 773 | se3 so0 si1 T0 774 | se3 so0 si1 T1 775 | se3 so0 si1 T2 776 | se3 so0 si1 T3 777 | se3 so0 si1 T4 778 | se3 so0 si1 T5 779 | se3 so0 si1 T6 780 | se3 so0 si1 T7 781 | se3 so0 si1 T8 782 | se3 so0 si1 T9 783 | se3 so0 si1 TA 784 | se3 so0 si1 TB 785 | se3 so0 si1 TC 786 | se3 so0 si1 TD 787 | se3 so0 si1 TE 788 | se3 so0 si! T0 789 | se3 so0 si! T1 790 | se3 so0 si! T2 791 | se3 so0 si! T3 792 | se3 so0 si! T4 793 | se3 so0 si! T5 794 | se3 so0 si! T6 795 | se3 so0 si! T7 796 | se3 so0 si! T8 797 | se3 so0 si! T9 798 | se3 so0 si! TA 799 | se3 so0 si! TB 800 | se3 so0 si! TC 801 | se3 so0 si! TD 802 | se3 so0 si! TE 803 | se3 so0 sa@ T0 804 | se3 so0 sa@ T1 805 | se3 so0 sa@ T2 806 | se3 so0 sa@ T3 807 | se3 so0 sa@ T4 808 | se3 so0 sa@ T5 809 | se3 so0 sa@ T6 810 | se3 so0 sa@ T7 811 | se3 so0 sa@ T8 812 | se3 so0 sa@ T9 813 | se3 so0 sa@ TA 814 | se3 so0 sa@ TB 815 | se3 so0 sa@ TC 816 | se3 so0 sa@ TD 817 | se3 so0 sa@ TE 818 | se3 si1 sa@ T0 819 | se3 si1 sa@ T1 820 | se3 si1 sa@ T2 821 | se3 si1 sa@ T3 822 | se3 si1 sa@ T4 823 | se3 si1 sa@ T5 824 | se3 si1 sa@ T6 825 | se3 si1 sa@ T7 826 | se3 si1 sa@ T8 827 | se3 si1 sa@ T9 828 | se3 si1 sa@ TA 829 | se3 si1 sa@ TB 830 | se3 si1 sa@ TC 831 | se3 si1 sa@ TD 832 | se3 si1 sa@ TE 833 | se3 si! sa@ T0 834 | se3 si! sa@ T1 835 | se3 si! sa@ T2 836 | se3 si! sa@ T3 837 | se3 si! sa@ T4 838 | se3 si! sa@ T5 839 | se3 si! sa@ T6 840 | se3 si! sa@ T7 841 | se3 si! sa@ T8 842 | se3 si! sa@ T9 843 | se3 si! sa@ TA 844 | se3 si! sa@ TB 845 | se3 si! sa@ TC 846 | se3 si! sa@ TD 847 | se3 si! sa@ TE 848 | so0 si1 sa@ T0 849 | so0 si1 sa@ T1 850 | so0 si1 sa@ T2 851 | so0 si1 sa@ T3 852 | so0 si1 sa@ T4 853 | so0 si1 sa@ T5 854 | so0 si1 sa@ T6 855 | so0 si1 sa@ T7 856 | so0 si1 sa@ T8 857 | so0 si1 sa@ T9 858 | so0 si1 sa@ TA 859 | so0 si1 sa@ TB 860 | so0 si1 sa@ TC 861 | so0 si1 sa@ TD 862 | so0 si1 sa@ TE 863 | so0 si! sa@ T0 864 | so0 si! sa@ T1 865 | so0 si! sa@ T2 866 | so0 si! sa@ T3 867 | so0 si! sa@ T4 868 | so0 si! sa@ T5 869 | so0 si! sa@ T6 870 | so0 si! sa@ T7 871 | so0 si! sa@ T8 872 | so0 si! sa@ T9 873 | so0 si! sa@ TA 874 | so0 si! sa@ TB 875 | so0 si! sa@ TC 876 | so0 si! sa@ TD 877 | so0 si! sa@ TE 878 | 879 | ## Toggle the case of characters at position N, one char, up to position 15 880 | 881 | T0 882 | T1 883 | T2 884 | T3 885 | T4 886 | T5 887 | T6 888 | T7 889 | T8 890 | T9 891 | TA 892 | TB 893 | TC 894 | TD 895 | TE 896 | 897 | ## Toggle the case of characters at position N, two chars, up to position 15 898 | 899 | T0 T1 900 | T0 T2 901 | T0 T3 902 | T0 T4 903 | T0 T5 904 | T0 T6 905 | T0 T7 906 | T0 T8 907 | T0 T9 908 | T0 TA 909 | T0 TB 910 | T0 TC 911 | T0 TD 912 | T0 TE 913 | T1 T2 914 | T1 T3 915 | T1 T4 916 | T1 T5 917 | T1 T6 918 | T1 T7 919 | T1 T8 920 | T1 T9 921 | T1 TA 922 | T1 TB 923 | T1 TC 924 | T1 TD 925 | T1 TE 926 | T2 T3 927 | T2 T4 928 | T2 T5 929 | T2 T6 930 | T2 T7 931 | T2 T8 932 | T2 T9 933 | T2 TA 934 | T2 TB 935 | T2 TC 936 | T2 TD 937 | T2 TE 938 | T3 T4 939 | T3 T5 940 | T3 T6 941 | T3 T7 942 | T3 T8 943 | T3 T9 944 | T3 TA 945 | T3 TB 946 | T3 TC 947 | T3 TD 948 | T3 TE 949 | T4 T5 950 | T4 T6 951 | T4 T7 952 | T4 T8 953 | T4 T9 954 | T4 TA 955 | T4 TB 956 | T4 TC 957 | T4 TD 958 | T4 TE 959 | T5 T6 960 | T5 T7 961 | T5 T8 962 | T5 T9 963 | T5 TA 964 | T5 TB 965 | T5 TC 966 | T5 TD 967 | T5 TE 968 | T6 T7 969 | T6 T8 970 | T6 T9 971 | T6 TA 972 | T6 TB 973 | T6 TC 974 | T6 TD 975 | T6 TE 976 | T7 T8 977 | T7 T9 978 | T7 TA 979 | T7 TB 980 | T7 TC 981 | T7 TD 982 | T7 TE 983 | T8 T9 984 | T8 TA 985 | T8 TB 986 | T8 TC 987 | T8 TD 988 | T8 TE 989 | T9 TA 990 | T9 TB 991 | T9 TC 992 | T9 TD 993 | T9 TE 994 | TA TB 995 | TA TC 996 | TA TD 997 | TA TE 998 | TB TC 999 | TB TD 1000 | TB TE 1001 | TC TD 1002 | TC TE 1003 | TD TE 1004 | 1005 | ## Inserts character X at position N (passphrase maker), one char, up to length 15 1006 | 1007 | i0 : 1008 | i1 : 1009 | i2 : 1010 | i3 : 1011 | i4 : 1012 | i5 : 1013 | i6 : 1014 | i7 : 1015 | i8 : 1016 | i9 : 1017 | iA : 1018 | iB : 1019 | iC : 1020 | iD : 1021 | iE : 1022 | 1023 | ## Inserts character X at position N (passphrase maker), two chars, up to length 15 1024 | 1025 | i0 i1 : 1026 | i0 i2 : 1027 | i0 i3 : 1028 | i0 i4 : 1029 | i0 i5 : 1030 | i0 i6 : 1031 | i0 i7 : 1032 | i0 i8 : 1033 | i0 i9 : 1034 | i0 iA : 1035 | i0 iB : 1036 | i0 iC : 1037 | i0 iD : 1038 | i0 iE : 1039 | i1 i2 : 1040 | i1 i3 : 1041 | i1 i4 : 1042 | i1 i5 : 1043 | i1 i6 : 1044 | i1 i7 : 1045 | i1 i8 : 1046 | i1 i9 : 1047 | i1 iA : 1048 | i1 iB : 1049 | i1 iC : 1050 | i1 iD : 1051 | i1 iE : 1052 | i2 i3 : 1053 | i2 i4 : 1054 | i2 i5 : 1055 | i2 i6 : 1056 | i2 i7 : 1057 | i2 i8 : 1058 | i2 i9 : 1059 | i2 iA : 1060 | i2 iB : 1061 | i2 iC : 1062 | i2 iD : 1063 | i2 iE : 1064 | i3 i4 : 1065 | i3 i5 : 1066 | i3 i6 : 1067 | i3 i7 : 1068 | i3 i8 : 1069 | i3 i9 : 1070 | i3 iA : 1071 | i3 iB : 1072 | i3 iC : 1073 | i3 iD : 1074 | i3 iE : 1075 | i4 i5 : 1076 | i4 i6 : 1077 | i4 i7 : 1078 | i4 i8 : 1079 | i4 i9 : 1080 | i4 iA : 1081 | i4 iB : 1082 | i4 iC : 1083 | i4 iD : 1084 | i4 iE : 1085 | i5 i6 : 1086 | i5 i7 : 1087 | i5 i8 : 1088 | i5 i9 : 1089 | i5 iA : 1090 | i5 iB : 1091 | i5 iC : 1092 | i5 iD : 1093 | i5 iE : 1094 | i6 i7 : 1095 | i6 i8 : 1096 | i6 i9 : 1097 | i6 iA : 1098 | i6 iB : 1099 | i6 iC : 1100 | i6 iD : 1101 | i6 iE : 1102 | i7 i8 : 1103 | i7 i9 : 1104 | i7 iA : 1105 | i7 iB : 1106 | i7 iC : 1107 | i7 iD : 1108 | i7 iE : 1109 | i8 i9 : 1110 | i8 iA : 1111 | i8 iB : 1112 | i8 iC : 1113 | i8 iD : 1114 | i8 iE : 1115 | i9 iA : 1116 | i9 iB : 1117 | i9 iC : 1118 | i9 iD : 1119 | i9 iE : 1120 | iA iB : 1121 | iA iC : 1122 | iA iD : 1123 | iA iE : 1124 | iB iC : 1125 | iB iD : 1126 | iB iE : 1127 | iC iD : 1128 | iC iE : 1129 | iD iE : 1130 | 1131 | ## Inserts character X at position N (passphrase maker), one char, up to length 15 1132 | 1133 | i0- : 1134 | i1- : 1135 | i2- : 1136 | i3- : 1137 | i4- : 1138 | i5- : 1139 | i6- : 1140 | i7- : 1141 | i8- : 1142 | i9- : 1143 | iA- : 1144 | iB- : 1145 | iC- : 1146 | iD- : 1147 | iE- : 1148 | 1149 | ## Inserts character X at position N (passphrase maker), two chars, up to length 15 1150 | 1151 | i0- i1- : 1152 | i0- i2- : 1153 | i0- i3- : 1154 | i0- i4- : 1155 | i0- i5- : 1156 | i0- i6- : 1157 | i0- i7- : 1158 | i0- i8- : 1159 | i0- i9- : 1160 | i0- iA- : 1161 | i0- iB- : 1162 | i0- iC- : 1163 | i0- iD- : 1164 | i0- iE- : 1165 | i1- i2- : 1166 | i1- i3- : 1167 | i1- i4- : 1168 | i1- i5- : 1169 | i1- i6- : 1170 | i1- i7- : 1171 | i1- i8- : 1172 | i1- i9- : 1173 | i1- iA- : 1174 | i1- iB- : 1175 | i1- iC- : 1176 | i1- iD- : 1177 | i1- iE- : 1178 | i2- i3- : 1179 | i2- i4- : 1180 | i2- i5- : 1181 | i2- i6- : 1182 | i2- i7- : 1183 | i2- i8- : 1184 | i2- i9- : 1185 | i2- iA- : 1186 | i2- iB- : 1187 | i2- iC- : 1188 | i2- iD- : 1189 | i2- iE- : 1190 | i3- i4- : 1191 | i3- i5- : 1192 | i3- i6- : 1193 | i3- i7- : 1194 | i3- i8- : 1195 | i3- i9- : 1196 | i3- iA- : 1197 | i3- iB- : 1198 | i3- iC- : 1199 | i3- iD- : 1200 | i3- iE- : 1201 | i4- i5- : 1202 | i4- i6- : 1203 | i4- i7- : 1204 | i4- i8- : 1205 | i4- i9- : 1206 | i4- iA- : 1207 | i4- iB- : 1208 | i4- iC- : 1209 | i4- iD- : 1210 | i4- iE- : 1211 | i5- i6- : 1212 | i5- i7- : 1213 | i5- i8- : 1214 | i5- i9- : 1215 | i5- iA- : 1216 | i5- iB- : 1217 | i5- iC- : 1218 | i5- iD- : 1219 | i5- iE- : 1220 | i6- i7- : 1221 | i6- i8- : 1222 | i6- i9- : 1223 | i6- iA- : 1224 | i6- iB- : 1225 | i6- iC- : 1226 | i6- iD- : 1227 | i6- iE- : 1228 | i7- i8- : 1229 | i7- i9- : 1230 | i7- iA- : 1231 | i7- iB- : 1232 | i7- iC- : 1233 | i7- iD- : 1234 | i7- iE- : 1235 | i8- i9- : 1236 | i8- iA- : 1237 | i8- iB- : 1238 | i8- iC- : 1239 | i8- iD- : 1240 | i8- iE- : 1241 | i9- iA- : 1242 | i9- iB- : 1243 | i9- iC- : 1244 | i9- iD- : 1245 | i9- iE- : 1246 | iA- iB- : 1247 | iA- iC- : 1248 | iA- iD- : 1249 | iA- iE- : 1250 | iB- iC- : 1251 | iB- iD- : 1252 | iB- iE- : 1253 | iC- iD- : 1254 | iC- iE- : 1255 | iD- iE- : 1256 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "hate-crack" 3 | version = "1.09" 4 | description = "Menu driven Python wrapper for hashcat" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | dependencies = [ 8 | "pytest>=8.3.4", 9 | ] 10 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ``` 2 | ___ ___ __ _________ __ 3 | / | \_____ _/ |_ ____ \_ ___ \____________ ____ | | __ 4 | / ~ \__ \\ __\/ __ \ / \ \/\_ __ \__ \ _/ ___\| |/ / 5 | \ Y // __ \| | \ ___/ \ \____| | \// __ \\ \___| < 6 | \___|_ /(____ /__| \___ >____\______ /|__| (____ /\___ >__|_ \ 7 | \/ \/ \/_____/ \/ \/ \/ \/ 8 | ``` 9 | 10 | ## Installation 11 | Get the latest hashcat binaries (https://hashcat.net/hashcat/) 12 | 13 | ``` 14 | git clone https://github.com/hashcat/hashcat.git 15 | cd hashcat/ 16 | make 17 | make install 18 | ``` 19 | ### Download hate_crack 20 | ```git clone https://github.com/trustedsec/hate_crack.git``` 21 | * Customize binary and wordlist paths in "config.json" 22 | * Make sure that at least "rockyou.txt" is within your "wordlists" path 23 | ### Create Optimized Wordlists 24 | wordlist_optimizer.py - parses all wordlists from ``, sorts them by length and de-duplicates into `` 25 | 26 | ```$ python wordlist_optimizer.py 27 | usage: python wordlist_optimizer.py 28 | 29 | $ python wordlist_optimizer.py wordlists.txt ../optimized_wordlists 30 | ``` 31 | ------------------------------------------------------------------- 32 | ## Usage 33 | `$ ./hate_crack.py 34 | usage: python hate_crack.py ` 35 | 36 | The is attained by running `hashcat --help` 37 | 38 | Example Hashes: http://hashcat.net/wiki/doku.php?id=example_hashes 39 | 40 | 41 | ``` 42 | $ hashcat --help |grep -i ntlm 43 | 5500 | NetNTLMv1 | Network protocols 44 | 5500 | NetNTLMv1 + ESS | Network protocols 45 | 5600 | NetNTLMv2 | Network protocols 46 | 1000 | NTLM | Operating-Systems 47 | ``` 48 | 49 | ``` 50 | $ ./hate_crack.py 1000 51 | 52 | ___ ___ __ _________ __ 53 | / | \_____ _/ |_ ____ \_ ___ \____________ ____ | | __ 54 | / ~ \__ \\ __\/ __ \ / \ \/\_ __ \__ \ _/ ___\| |/ / 55 | \ Y // __ \| | \ ___/ \ \____| | \// __ \\ \___| < 56 | \___|_ /(____ /__| \___ >____\______ /|__| (____ /\___ >__|_ \ 57 | \/ \/ \/_____/ \/ \/ \/ \/ 58 | Version 1.09 59 | 60 | 61 | (1) Quick Crack 62 | (2) Extensive Pure_Hate Methodology Crack 63 | (3) Brute Force Attack 64 | (4) Top Mask Attack 65 | (5) Fingerprint Attack 66 | (6) Combinator Attack 67 | (7) Hybrid Attack 68 | (8) Pathwell Top 100 Mask Brute Force Crack 69 | (9) PRINCE Attack 70 | (10) YOLO Combinator Attack 71 | (11) Middle Combinator Attack 72 | (12) Thorough Combinator Attack 73 | (13) Bandrel Methodology 74 | 75 | (95) Analyze hashes with Pipal 76 | (96) Export Output to Excel Format 77 | (97) Display Cracked Hashes 78 | (98) Display README 79 | (99) Quit 80 | 81 | Select a task: 82 | ``` 83 | ------------------------------------------------------------------- 84 | #### Quick Crack 85 | * Runs a dictionary attack using all wordlists configured in your "hcatOptimizedWordlists" path 86 | and optionally applies a rule that can be selected from a list by ID number. Multiple rules can be selected by using a 87 | comma separated list, and chains can be created by using the '+' symbol. 88 | 89 | ``` 90 | Which rule(s) would you like to run? 91 | (1) best64.rule 92 | (2) d3ad0ne.rule 93 | (3) T0XlC.rule 94 | (4) dive.rule 95 | (99) YOLO...run all of the rules 96 | Enter Comma separated list of rules you would like to run. To run rules chained use the + symbol. 97 | For example 1+1 will run best64.rule chained twice and 1,2 would run best64.rule and then d3ad0ne.rule sequentially. 98 | Choose wisely: 99 | ``` 100 | 101 | 102 | 103 | 104 | #### Extensive Pure_Hate Methodology Crack 105 | Runs several attack methods provided by Martin Bos (formerly known as pure_hate) 106 | * Brute Force Attack (7 characters) 107 | * Dictionary Attack 108 | * All wordlists in "hcatOptimizedWordlists" with "best64.rule" 109 | * wordlists/rockyou.txt with "d3ad0ne.rule" 110 | * wordlists/rockyou.txt with "T0XlC.rule" 111 | * Top Mask Attack (Target Time = 4 Hours) 112 | * Fingerprint Attack 113 | * Combinator Attack 114 | * Hybrid Attack 115 | * Extra - Just For Good Measure 116 | - Runs a dictionary attack using wordlists/rockyou.txt with chained "combinator.rule" and "InsidePro-PasswordsPro.rule" rules 117 | 118 | #### Brute Force Attack 119 | Brute forces all characters with the choice of a minimum and maximum password length. 120 | 121 | #### Top Mask Attack 122 | Uses StatsGen and MaskGen from PACK (https://thesprawl.org/projects/pack/) to perform a top mask attack using passwords already cracked for the current session. 123 | Presents the user a choice of target cracking time to spend (default 4 hours). 124 | 125 | #### Fingerprint Attack 126 | https://hashcat.net/wiki/doku.php?id=fingerprint_attack 127 | 128 | Runs a fingerprint attack using passwords already cracked for the current session. 129 | 130 | #### Combinator Attack 131 | https://hashcat.net/wiki/doku.php?id=combinator_attack 132 | 133 | Runs a combinator attack using the "rockyou.txt" wordlist. 134 | 135 | #### Hybrid Attack 136 | https://hashcat.net/wiki/doku.php?id=hybrid_attack 137 | 138 | * Runs several hybrid attacks using the "rockyou.txt" wordlists. 139 | - Hybrid Wordlist + Mask - ?s?d wordlists/rockyou.txt ?1?1 140 | - Hybrid Wordlist + Mask - ?s?d wordlists/rockyou.txt ?1?1?1 141 | - Hybrid Wordlist + Mask - ?s?d wordlists/rockyou.txt ?1?1?1?1 142 | - Hybrid Mask + Wordlist - ?s?d ?1?1 wordlists/rockyou.txt 143 | - Hybrid Mask + Wordlist - ?s?d ?1?1?1 wordlists/rockyou.txt 144 | - Hybrid Mask + Wordlist - ?s?d ?1?1?1?1 wordlists/rockyou.txt 145 | 146 | #### Pathwell Top 100 Mask Brute Force Crack 147 | Runs a brute force attack using the top 100 masks from KoreLogic: 148 | https://blog.korelogic.com/blog/2014/04/04/pathwell_topologies 149 | 150 | #### PRINCE Attack 151 | https://hashcat.net/events/p14-trondheim/prince-attack.pdf 152 | 153 | Runs a PRINCE attack using wordlists/rockyou.txt 154 | 155 | #### YOLO Combinator Attack 156 | Runs a continuous combinator attack using random wordlists from the 157 | optimized wordlists for the left and right sides. 158 | 159 | #### Middle Combinator Attack 160 | https://jeffh.net/2018/04/26/combinator_methods/ 161 | 162 | Runs a modified combinator attack adding a middle character mask: 163 | wordlists/rockyou.txt + masks + worklists/rockyou.txt 164 | 165 | Where the masks are some of the most commonly used separator characters: 166 | 2 4 - _ , + . & 167 | 168 | #### Thorough Combinator Attack 169 | https://jeffh.net/2018/04/26/combinator_methods/ 170 | 171 | * Runs many rounds of different combinator attacks with the rockyou list. 172 | - Standard Combinator attack: rockyou.txt + rockyou.txt 173 | - Middle Combinator attack: rockyou.txt + ?n + rockyou.txt 174 | - Middle Combinator attack: rockyou.txt + ?s + rockyou.txt 175 | - End Combinator attack: rockyou.txt + rockyou.txt + ?n 176 | - End Combinator attack: rockyou.txt + rockyou.txt + ?s 177 | - Hybrid middle/end attack: rockyou.txt + ?n + rockyou.txt + ?n 178 | - Hybrid middle/end attack: rockyou.txt + ?s + rockyou.txt + ?s 179 | 180 | 181 | #### Bandrel Methodology 182 | 183 | * Prompts for input of comma separated names and then creates a pseudo hybrid attack by capitalizing the first letter 184 | and adding up to six additional characters at the end. Each word is limited to a total of five minutes. 185 | - Built in additional common words including seasons, months has been included as a customizable config.json entry 186 | - The default five minute time limit is customizable via the config.json 187 | 188 | ------------------------------------------------------------------- 189 | ### Version History 190 | Version 1.9 191 | Revamped the hate_crack output to increase processing speed exponentially combine_ntlm_output function for combining 192 | Introducing New Attack mode "Bandrel Methodology" 193 | Updated pipal function to output top x number of basewords 194 | 195 | Version 1.08 196 | Added a Pipal menu Option to analyze hashes. https://github.com/digininja/pipal 197 | 198 | Version 1.07 199 | Minor bug fixes with pwdump formating and unhexify function 200 | 201 | Version 1.06 202 | Updated the quick crack and recylcing functions to use user customizable rules. 203 | 204 | Version 1.05 205 | Abstraction of rockyou.txt so that you can use whatever dictionary that you would like to specified in the config.json 206 | Minor change the quickcrack that allows you to specify 0 for number of times best64 is chained 207 | 208 | Version 1.04 209 | Two new attacks Middle Combinator and Thorough Combinator 210 | 211 | Version 1.03 212 | Introduction of new feature to use session files for multiple concurrent sessions of hate_crack 213 | Minor bug fix 214 | 215 | Version 1.02 216 | Introduction of new feature to export the output of pwdump formated NTDS outputs to excel with clear-text passwords 217 | 218 | Version 1.01 219 | Minor bug fixes 220 | 221 | Version 1.00 222 | Initial public release 223 | -------------------------------------------------------------------------------- /wordlist_optimizer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import os 5 | import subprocess 6 | import shutil 7 | import pathlib 8 | 9 | # Help 10 | def usage(): 11 | print("usage: python %s " % sys.argv[0]) 12 | 13 | def lineCount(file): 14 | try: 15 | outFile = open(file) 16 | except: 17 | return 0 18 | 19 | count = 0 20 | for line in outFile: 21 | count = count + 1 22 | return count 23 | 24 | # Main guts 25 | def main(): 26 | try: 27 | if not os.path.isfile(sys.argv[1]): 28 | print('{0} is not a valid file.\n'.format(sys.argv[1])) 29 | sys.exit() 30 | if not os.path.isdir(sys.argv[2]): 31 | create_directory = input('{0} is not a directory. Do you want to create it? (Y or N)'.format(sys.argv[2])) 32 | if create_directory.upper() == 'Y': 33 | try: 34 | pathlib.Path(sys.argv[2]).mkdir(parents=True, exist_ok=True) 35 | except PermissionError: 36 | print('You do not have the correct permissions to receate the directory. Please try a different path or create manually') 37 | sys.exit() 38 | else: 39 | print('Please specify a valid directory and try again') 40 | sys.exit() 41 | input_list = open(sys.argv[1], "r") 42 | destination = sys.argv[2] 43 | except IndexError: 44 | usage() 45 | sys.exit() 46 | 47 | if sys.platform == 'darwin': 48 | splitlen_bin = "hashcat-utils/bin/splitlen.app" 49 | rli_bin = "hashcat-utils/bin/rli.app" 50 | else: 51 | splitlen_bin = "hashcat-utils/bin/splitlen.bin" 52 | rli_bin = "hashcat-utils/bin/rli.bin" 53 | 54 | # Get list of wordlists from argument 55 | for wordlist in input_list: 56 | print(wordlist.strip()) 57 | 58 | # Parse wordlists by password length into "optimized" 59 | if len(os.listdir(destination)) == 0: 60 | splitlenProcess = subprocess.Popen("%s %s < %s" % (splitlen_bin, destination, wordlist), shell=True).wait() 61 | else: 62 | if not os.path.isdir("/tmp/splitlen"): 63 | os.mkdir("/tmp/splitlen") 64 | splitlenProcess = subprocess.Popen("%s /tmp/splitlen < %s" % (splitlen_bin, wordlist), shell=True).wait() 65 | 66 | # Copy unique passwords into "optimized" 67 | for file in os.listdir("/tmp/splitlen"): 68 | if not os.path.isfile(destination + "/" + file): 69 | shutil.copyfile("/tmp/splitlen/" + file, destination + "/" + file) 70 | else: 71 | rliProcess = subprocess.Popen("%s /tmp/splitlen/%s /tmp/splitlen.out %s/%s" % (rli_bin, file, destination, file), shell=True).wait() 72 | if lineCount("/tmp/splitlen.out") > 0: 73 | destination_file = open(destination + "/" + file, "a") 74 | splitlen_file = open("/tmp/splitlen.out", "r") 75 | destination_file.write(splitlen_file.read()) 76 | destination_file.close() 77 | splitlen_file.close() 78 | 79 | # Clean Up 80 | if os.path.isdir("/tmp/splitlen"): 81 | shutil.rmtree('/tmp/splitlen') 82 | if os.path.isfile("/tmp/splitlen.out"): 83 | os.remove("/tmp/splitlen.out") 84 | 85 | 86 | # Standard boilerplate to call the main() function 87 | if __name__ == '__main__': 88 | main() 89 | --------------------------------------------------------------------------------