# # This file is part of John the Ripper password cracker, # Copyright (c) 1996-2006,2008-2013,2019 by Solar Designer # # Redistribution and use in source and binary forms, with or without # modification, are permitted. # # There's ABSOLUTELY NO WARRANTY, express or implied. # # Please note that although this configuration file is under the cut-down BSD # license above, many source files in John the Ripper are under GPLv2. # For licensing terms for John the Ripper as a whole, see doc/LICENSE. # # ...with changes in the jumbo patch, by various authors # # The [Options] section is for general options only. # Note that MPI specific options have been moved # to [Options.MPI] # There is also a new section [Options.OpenCL] # for OpenCL specific options # Default settings for Markov mode have been moved # to [Markov.Default], but you can define other # Markov modes as well, see ../doc/MARKOV [Options] # Default wordlist file name (including in batch mode) Wordlist = $JOHN/password.lst # Use idle cycles only Idle = Y # Crash recovery file saving delay in seconds Save = 60 # Beep when a password is found (who needs this anyway?) Beep = N # if set to Y then dynamic format will always work with bare hashes. Normally # dynamic only uses bare hashes if a single dynamic type is selected with # the -format= (so -format=dynamic_0 would use valid bare hashes). DynamicAlwaysUseBareHashes = N # Default Single mode rules SingleRules = Single # Default batch mode Wordlist rules BatchModeWordlistRules = Wordlist # Default wordlist mode rules when not in batch mode (if any). If this is # changed from an 'empty list' to have default rules applied, and you later # DO want to perform a run once without rules, use --rules:none on the # command line. The default is 'empty' or NO rules run at all. WordlistRules = # Default loopback mode rules (if any) # If this is set and you want to run once without rules, use --rules:none LoopbackRules = Loopback # Max. number of times to warn about crypting suboptimally small batches, # before suppressing the warnings. MaxKPCWarnings = 10 # If set to true, relax the KPC warning checks and only warn for really # bad situations (the fewer salts, the more slack). RelaxKPCWarningCheck = N # Default/batch mode Incremental mode # Warning: changing these might currently break resume on existing sessions # one option frequently changed (with above caveat) is setting DefaultIncrementalUTF8 = UTF8 DefaultIncremental = ASCII DefaultIncrementalUTF8 = ASCII DefaultIncrementalLM = LM_ASCII # Time formatting string used in status ETA. # # TimeFormat24 is used when ETA is within 24h, so it is possible to omit # the date then if you like, and show seconds instead. # # %c means 'local' specific canonical form, such as: # 05/06/11 18:10:34 # # Other examples # %d/%m/%y %H:%M (day/mon/year hour:min) # %m/%d/%y %H:%M (mon/day/year hour:min) # %Y-%m-%d %H:%M (ISO 8601 style, 2011-05-06 18:10) TimeFormat = %Y-%m-%d %H:%M TimeFormat24 = %H:%M:%S # # optional add a date timestamp in front of every logged line. # the default is no timestamp logging. See the docs for # strftime for more information: # http://en.cppreference.com/w/c/chrono/strftime # # examples: # 2016-02-20T22:35:38+01:00 would be %Y-%m-%dT%H:%M:%S%z # Feb 20 22:35:38 would be %b %d %H:%M:%S LogDateFormat = # if log date is being used, the time will default to local # time. But if the next line is changed to 'Y', date output # in UTC. Note, if LogDateFormat is not set, this option # is ignored. LogDateFormatUTC = N # if logging to stderr (--log-stderr command line switch used), # then use date format when outputting to the stderr. # # example # Feb 20 22:35:38 would be %b %d %H:%M:%S LogDateStderrFormat = # If this is given, it will be printed in the end on any cracked password # output. In case some 8-bit passwords upset your terminal, putting an # ANSI "SGR Reset/Normal" here might be a cure. Any "^" characters will be # parsed as ESC for use in ANSI codes (like in the default) TerminalReset = ^[0m # This can be used to colorize (on screen) or otherwise emphasize (in log # files) output whenever a supposed administrator password gets cracked. # # Set this to N or comment it out to disable all "MarkAdmin" stuff. MarkAdminCracks = Y # If MarkAdminCracks = Y above, the below will be used (if defined) for # terminal output. The default is to change color to red before the username # and reset to normal after it. Any "^" characters will be parsed as ESC for # use in ANSI codes (like in the defaults) MarkAdminStart = ^[31m MarkAdminEnd = ^[0m # If MarkAdminCracks = Y above, the below will be used (if defined) for logs. # This literal string will be printed after the " + Cracked: root" line. MarkAdminString = (ADMIN ACCOUNT) # Permissions to set for session.log file # Default is 0600 LogFilePermissions = 0600 # Permissions to set for POT file # Default is 0600 PotFilePermissions = 0600 # John exits if another user owns log or pot file because CHMOD fails, # If this is set John prints a warning and continues # Default is N IgnoreChmodErrors = N # This figure is in MB. The default is to memory map wordlists not larger # than one terabyte. # Set this to 0 to disable any use of memory-mapping in wordlist mode. WordlistMemoryMapMaxSize = 1048576 # For single mode, load the full GECOS field (before splitting) as one # additional candidate. Normal behavior is to only load individual words # from that field. Enabling this can help when this field contains email # addresses or other strings that are better used unsplit, but it increases # the number of words tried so it may also slow things down. PristineGecos = N # Add an extra pass when loading Single words, that tries to parse things # like JEdgarHoover to J Edgar Hoover and so on. JumboSingleWords = N # For single mode, ignore the login field. # Normal behavior is to use the login field for single mode. # Skipping the login field should only be enabled if previous single mode # sessions did already make use of the login field, but no other information, # and now you want to use other information, skip the login field, but still # want the login field to be reported on successful cracks or with --show. SingleSkipLogin = N # Over-ride SINGLE_WORDS_PAIR_MAX in params.h. This may slow down Single mode # but it may also help cracking a few more candidates. Default in core John # is 4 while the Jumbo default is 6. This limit is automagically increased # by word seed options --single-seed and/or --single-wordlist if needed. SingleWordsPairMax = 6 # Setting this to false stops Single mode from re-testing guessed plaintexts # with all other salts. SingleRetestGuessed = Y # Max recursion depth for SingleRetestGuessed, so we don't blow the stack SingleMaxRecursionDepth = 10000 # Set the maximum word buffer size used by Single mode. The default is # 4 GB. If running fork this is the *total* used by a session (size is # divided by number of forks). If running MPI, we try to determine the # number of local processes on each node and divide it accordingly. SingleMaxBufferSize = 4 # When running single mode with a GPU or accelerator, we prioritize speed # (saturating buffers) over resume ability: When resuming such a session # it may take longer to catch up. Set this option to Y to prioritize # resuming instead, at the cost of max. speed. SinglePrioResume = N # Protect the restore files (*.rec) from being overwritten. The default # mode is "Disabled". This mode will provide no protection, but has been # the default mode in JtR forever, so to not change behavior, that mode # has been kept as default. You can change this to "Named" or "Always" # If this option is changed to "Named", then any restore file created # with a --session=xxxx will be protected from being overwritten. If # the option is set to "Always", then all .rec files will be kept from # being overwritten, even ${JOHN}/john.rec file SessionFileProtect = Disabled # Protect the log files (*.log) from being reused by new sessons. # The default mode is "Disabled". That means, a nee session will just append # to an existing log file. # With "Named", a new session will not be allowed to append to an existing # log file, except if the --session=NAME option hasn't been used. # With "Always", not even the default log file ${JOHN}/john.log can be # reused by a new session. # (Of course, a restored session will always be allowed to append to an # existing log file.) # Unless you use the --nolog option, setting LogFileProtect will also # prevent overwriting existing session files. LogFileProtect = Disabled # Emit a status line whenever a password is cracked (this is the same as # passing the --crack-status option flag to john). NOTE: if this is set # to true here, --crack-status will toggle it back to false. CrackStatus = N # When printing status, show number of candidates tried (eg. 123456p). # This is added to the "+ Cracked" line in the log as well (and that figure # will be exact while the screen output will be a multiple of batch size). StatusShowCandidates = N # Write cracked passwords to the log file (default is just the user name) LogCrackedPasswords = N # Disable the dupe checking when loading hashes. For testing purposes only! NoLoaderDupeCheck = N # Default encoding for input files (ie. login/GECOS fields) and wordlists # etc. If this is not set here and --encoding is not used either, the default # is ISO-8859-1 for Unicode conversions and 7-bit ASCII encoding is assumed # for rules, e.g., uppercasing of letters other than a-z will not work at all! DefaultEncoding = UTF-8 # Default --target-encoding for Microsoft hashes (LM, NETLM et al) when input # encoding is UTF-8. CP850 would be a universal choice for covering most # "Latin-1" countries. DefaultMSCodepage = CP850 # Default internal legacy codepage to be used by mask mode and within the # rules engine, when both input and target encodings are Unicode (eg. UTF-8 # wordlist and NT hashes). In some cases this hits performance but lets us # do things like Unicode case conversions. You can pick any supported # legacy codepage that has as much support for the input data as possible, # e.g., for "Latin-1" language passwords you can use ISO-8859-1, CP850 or # CP1252 and it will hardly make any difference but in some cases, ISO-8859-1 # is fastest. Using "UTF-8" (which is not a legacy codepage!) will disable. # # The default is to NOT use any internal codepage. DefaultInternalCodepage = # Warn if seeing UTF-8 when expecting some other encoding, or vice versa. # This is disabled for ASCII or RAW encodings, for performance. WarnEncoding = Y # Always report (to screen and log) cracked passwords as UTF-8, regardless of # input encoding. This is recommended if you have your terminal set for UTF-8. AlwaysReportUTF8 = Y # Always store Unicode (UTF-16) passwords as UTF-8 in john.pot, regardless # of input encoding. This prevents john.pot from being filled with mixed # and eventually unknown encodings. This is recommended if you have your # terminal set for UTF-8 and/or you want to run --loopback for LM->NT # including non-ASCII. UnicodeStoreUTF8 = Y # Always report/store non-Unicode formats as UTF-8, regardless of input # encoding. Note: The actual codepage that was used is not stored anywhere # except in the log file. # This is needed e.g. for --loopback to crack LM->NT including non-ASCII. CPstoreUTF8 = Y # Normally, we try to handle Unicode characters not in our selected codepage # with best effort. Enabling this option will instead translate any such # character to "?" (default), to meet certain formats' behavior. EmulateBrokenEncoding = N ReplacementCharacter = ? # Default verbosity is 3, valid figures are 1-5 right now. # 4-5 enables some extra output and diagnostics. # 4 is same verbosity as "john proper" aka. non-jumbo. # 3 mutes rules & incremental output in logs (LOTS of lines). # 2 mutes some other diagnostics. # 1 even mutes printing (to screen) of cracked passwords. Verbosity = 3 # If set to Y, do not output, log or store cracked passwords verbatim. # This implies a different default .pot database file "secure.pot" instead # of "john.pot" but it can still be overridden using --pot=FILE. # This also overrides other options, e.g. LogCrackedPasswords. SecureMode = N # If set to Y, a session using --fork or MPI will signal to other nodes when # it has written cracks to the pot file, so they will re-sync. Note that this # may be delayed by buffers and the "Save" timer setting near top of this file. ReloadAtCrack = N # If set to Y, a session using --fork or MPI will signal to other nodes when # it has cracked all hashes (there's nothing more to do!). This is ignored # when ReloadAtCrack = Y because it's redundant. ReloadAtDone = Y # If set to Y, resync pot file when saving session. This does not involve any # signalling, we just detect that someone else wrote to the pot file. # This will sync with concurrent sessions even when not using --fork or MPI # but it may be delayed by the "Save" timer setting near top of this file. ReloadAtSave = Y # If this file exists, john will abort cleanly AbortFile = /var/run/john/abort # While this file exists, john will pause PauseFile = /var/run/john/pause # If set to true, the uid will be appended to user name on cracks # With: password123 (Administrator:500) # Without password123 (Administrator) # This is disabled by --save-memory. ShowUIDinCracks = N # This sets the "grace time" for --max-run-time=N. If john has not finished # this long after the initial abort signal, it will send another one (similar # to pressing ctrl-c a second time) which will stop john immediately and not # wait further for an optimal resume point. # Setting this to 0 means NO grace time - immediately abort. Setting it to # a negative number means UNLIMITED grace time - never hard abort. AbortGraceTime = 30 # Setting this to true allows SAP-B and SAP-G "half hashes" to be cracked. # These are taken from RFC_READ_TABLE and padded with nulls to correct length. # This may produce some false positives if enabled, at least for SAP-B. SAPhalfHashes = N [Options:CPUtune] # If preset is given, use it and skip autotune (NOTE: non-intel archs will # currently ignore this option and always autotune) UsePreset = Y # Performance sample time, default 10 ms AutoTuneSampleTime = 10 # Required gain to consider this scale better. Default is 1 % AutoTuneReqGain = 1 # Max crypt_all() duration for trying a higher scale, default 100 ms AutoTuneMaxDuration = 100 # If we tried this many increases of scale w/o gain, give up. Default 3. AutoTuneMaxNoProgress = 3 [Options:MPI] # Automagically disable OMP if MPI is used (set to N if # you want to run one MPI process per multi-core host) MPIOMPmutex = Y # Print a notice if disabling OMP (when MPIOMPmutex = Y) # or when running OMP and MPI at the same time MPIOMPverbose = Y # Assume all MPI nodes are homogenous; Enforce same OpenCL workgroup sizes. MPIAllGPUsSame = N # Options that may affect both GPUs and other accelerators (eg. FPGA) [Options:GPU] # Show GPU temperature, fan and utilization along with normal status output SensorsStatus = Y # If SensorsStatus is true, individual ones can be turned off TempStatus = Y UtilStatus = N FanStatus = N # Abort the process or sleep for a while if a GPU hits this temperature (in C) AbortTemperature = 95 # Instead of aborting, sleep for this many seconds to cool the GPU down when # the temperature hits the AbortTemperature value, then re-test the temperature # and either wake up or go to sleep again. Set this to 0 to actually abort. # Suppress repeated sleep/wakeup messages when SleepOnTemperature = 1, # we are interpreting this as intent to keep the GPU temperature around the limit. SleepOnTemperature = 1 [Options:OpenCL] # Set default OpenCL device(s). Command line option will override this. # If not set, we will search for a GPU or fall-back to the most # powerful device. Syntax is same as --device option. Device = # If set to true, store LWS and GWS in session file for later resume. # Note that when resuming, this option is ignored: If the session file # was written with this option set, it will still be used. ResumeWS = N # Global max. single kernel invocation duration, in ms. Setting this low # (eg. 10-100 ms) gives you a better responding desktop but lower performance. # Setting it high (eg. 200-500 ms) will maximize performance but your desktop # may lag. Really high values may trip watchdogs (eg. 5 seconds). Some versions # of AMD Catalyst may hang if you go above 200 ms, and in general any good # kernel will perform optimally at 100-200 ms anyway. Global_MaxDuration = # Some formats vectorize their kernels in case the device says it's a good # idea. Some devices give "improper" hints which means we vectorize but get # a performance drop. If you have such a device, uncommenting the below # will disable vectorizing globally. # With this set to N (or commented out) you can force it per session with # the --force-scalar command-line option instead. ForceScalar = N # Global build options. Format-specific build options below may be # concatenated to this. GlobalBuildOpts = -cl-mad-enable # Initial local work-size for auto-tune (CPU devices excepted). # 0 means let the OpenCL implementation pick a suitable value. # 1 means query for "best multiple" (usually corresponds to "warp size"). # Any other value (eg. 64) will be taken verbatim. AutotuneLWS = 1 # Format-specific settings: # Uncomment the below for nvidia sm_30 and beyond. # Please, check if it is really better. #sha512crypt_BuildOpts = -cl-nv-maxrregcount=80 # Best configuration value to be used at runtime. sha512crypt_Bonaire = -DUNROLL_LOOP=132104 # Example: Override auto-tune for RAR format. #rar_LWS = 128 #rar_GWS = 8192 [List.OpenCL:Drivers] #Driver ; Description ; Recommendation #AMD driver versions 938 , 2 ; 12.8 ; 1084, 4 ; 13.1 ; 1124, 2 ; 13.4 ; 1214, 3 ; 13.6 beta ; 1311, 2 ; 13.11 beta-1 ; 1348, 5 ; 13.12 ; 1445, 5 ; 14.4 (Mantle) ; 1526, 3 ; 14.6 beta (Mantle) ; 1573, 4 ; 14.9 (Mantle) ; VGL S 1642, 5 ; 14.12 (Omega) ; VGL S 1702, 3 ; 15.5 beta ; T 1729, 3 ; 15.5 ; 1800, 5 ; 15.7 ; VG* R 1800, 8 ; 15.7.1 ; VGW R 1800, 11; 15.9 ; VGL S 1912, 5 ; 15.12 ; #NVIDIA driver versions 346, 0 ; ; N* R 319, 0 ; ; N* S #End 0, 0 ; ; #Labels # * -> all OS # N -> NVIDIA # G -> GCN # V -> VLIW4 and VLIW5 # W -> Windows # L -> Linux # R -> recommended # S -> supported # T -> not recommended: really bad software. I mean "trash". # ZTEX specific settings [List.ZTEX:Devices] # If you list Serial Numbers (SN) of ZTEX boards here, it will display # numbers (starting from 1) instead of factory programmed SN's. # These numbers can be used in --dev command-line option. #04A36E0000 #04A36D0000 [ZTEX:descrypt] # The design has programmable clock. Design tools reported possible # frequency to be 221 MHz. Tested boards work reliably at 190. Frequency = 190 [ZTEX:bcrypt] # Define typical setting of hashes it's going to process. It allows # to adjust for best performance. TargetSetting = 5 # Design tools reported possible frequency to be 141.5 MHz. # Tested boards work reliably at 150, so that's what we use by default. Frequency = 150 # For any algorithm it's possible to set frequency on per-board and # per-FPGA basis, but the lowest frequency will determine performance. #Frequency_04A36E0FD6 = 142 #Frequency_04A36E0FD6_1 = 143 #Frequency_04A36E0FD6_4 = 144 [ZTEX:sha512crypt] #TargetRounds = 5000 # Design tools reported possible frequency to be 215 MHz. # We never encountered a board where this worked anywhere close # to such high frequency. Default frequency is set to 160 MHz. # Some lucky boards might run at some higher frequency. Frequency = 160 #Config1 = \x00\x00 [ZTEX:Drupal7] #TargetRounds = 16384 # Drupal7 uses same bitstream as sha512crypt, see comment regarding # default frequency in sha512crypt section. #Frequency = 160 # Some bitstreams accept runtime configuration. # In sha512crypt/Drupal7, configuration is 2 bytes. That's interpreted # as a bitmask. By setting any of the lowest 10 bits to 1 it turns off # corresponding unit (there are 10 units in the bitstream). # This turns off units 0 and 1. #Config1 = \x03\x00 # This turns off all 10 units (resulting in a timeout). #Config1_04A36E0FD6_0 = \xff\x03 [ZTEX:sha256crypt] # Design tools reported possible frequency is 241 MHz but tested boards # miss guesses, often fail unless frequency is decreased. # Tested boards work reliably at 175. Frequency = 175 #TargetRounds = 500000 # md5crypt and phpass use same bitstream. Design tools reported # possible frequency is 202 MHz. Tested boards run OK at 180 MHz. [ZTEX:md5crypt] Frequency = 180 [ZTEX:phpass] Frequency = 180 #TargetRounds = 2048 # These formats are disabled from all-formats --test runs, or auto-selection # of format from an input file. Even when disabled, you can use them as long # as you spell them out with the --format option. Or you can delete a line, # comment it out, or change to 'N' [Disabled:Formats] #formatname = Y .include '$JOHN/dynamic_disabled.conf' [Formats:7z] # With this enabled, the 7z formats check padding after AES decryption which # more or less guarantees we don't get any false positives, and also makes # the formats faster (in some cases a LOT faster). We've had one (1) report # of getting a false negative having this enabled though, so if you fail to # crack some archive you may want to disable this and re-try all attacks. TrustPadding = Y # This allows you to list a few words/names that will be used by single mode # as if they were included in every GECOS field. Use sparingly! Please note # that the example words are commented out, so the list is empty! [List.Single:SeedWords] #Pass #Secret #Test # This allows you to read extra pot files when loading hashes. Nothing will # ever be written to these files, they are just read. Any directory in this # list will be traversed and files in it with an extension of .pot will be # read. However there will NOT be any recursion down further directory levels. # Any entries that don't exist will be silently ignored. [List.Extra:Potfiles] #somefile.pot #somedirectory #$JOHN/my.pot [Debug] # Changing this to Yes will enable legacy-style benchmarks, for comparisons Benchmarks_1_8 = N # Changing this to Yes will test salted formats as one/many salts, for debug BenchmarkMany = N [PRINCE] # Default wordlist file name. Will fall back to standard wordlist if not # defined. Wordlist = # Markov modes, see ../doc/MARKOV for more information [Markov:Default] # Default Markov mode settings # # Statsfile cannot be specified on the command line, so # specifying it here is mandatory Statsfile = $JOHN/stats # MkvLvl and MkvMaxLen should also be specified here, as a fallback for # --markov usage without specifying LEVEL and/or --max-length on the # command line. MkvLvl = 200 MkvMaxLen = 12 # MkvMinLvl and MkvMinLen should not be specified at all in [Markov:Default], # or they should be equal to 0 (which is the default if not specified. # MkvMinLvl and MkvMinLen can be used in other Markov mode sections # except [Markov:Default] ; MkvMinLvl = 0 ; MkvMinLen = 0 # A user defined character class is named with a single digit, ie. 0..9. After # the equal-sign, just list all characters that this class should match. You # can specify ranges within brackets, much like pre-processor ranges in rules. # BEWARE of encoding if using non-ASCII characters. If you put UTF-8 characters # here, it will *not* work! You must use a singlebyte encoding and it should # be the same here as you intend to use for your dictionary. # You can however put characters here in \xA3 format (for codepoint 0xA3 - in # many iso-8859 codepages that would mean a pound sign). This works in ranges # too. Using \x00 is not supported though - it will not be parsed as null. # # This is a couple of example classes: # ?0 matches (one version of) base64 characters # ?1 matches hex digits # ?2 matches the TAB character (never try to use \x00!) [UserClasses] 0 = [a-zA-Z0-9/.] 1 = [0-9a-fA-F] 2 = \x09 [Mask] # When iterating over length, emit a status line after each length is done MaskLengthIterStatus = Y # Default mask for -mask if none is given. This is same as hashcat's default. DefaultMask = ?1?2?2?2?2?2?2?3?3?3?3?d?d?d?d # Default mask for Hybrid mask mode if none is given. DefaultHybridMask = ?w?d?d?d?d # Mask mode have custom placeholders ?1..?9 that look similar to user classes # but are a different thing. They are merely defaults for the -1..-9 command # line options. As delivered, they resemble hashcat's defaults. 1 = ?l?d?u 2 = ?l?d 3 = ?l?d*!$@_ 4 = 5 = 6 = 7 = 8 = 9 = [Subsets] # When iterating over length, emit a status line after each length is done LengthIterStatus = Y # Min/Max number of unique characters. MaxDiff can't be set larger than 16. MinDiff = 1 MaxDiff = 7 # Default charset, either a literal string or a single-digit number pointing # to one of the sets below. If not defined, all printable ASCII is used. DefaultCharset = # Subsets mode charsets 0-9. These are literal strings. TAB and space # characters can be used as long as they do not come first or last. The only # "magic" used here is \U+HHHH or \U+HHHHH for any Unicode character (except # the very highest private area that has six hex digits). For example, you # could say \U+1F600 for a "Grinning Face". 0 = 0123456789abcdef 1 = ABCDEF0123456789 2 = 0123456789abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ 3 = 0123456789άέήίαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 4 = 0123456789абвгдежзийклмнопрстуфхцчшщъыьэюяёЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ№ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 5 = 6 = 7 = 8 = 9 = [Regen_Salts_UserClasses] # These are user defined character sets. Their purpose is to allow custom salt # values to be used within the salt_regen logic. These will be the characters # to use for this character within the salt. So if we had a salt that was 4 # characters, and 0-9a-m, we can easily do this by 0 = [0-9a-m]. If this is # used, the regen salt value would be ?0?0?0?0 and salts such as a47m 2kd5 # would be valid. 1 = [1-9] # A "no rules" rule for eg. super-fast Single mode (use with --single=none) [List.Rules:None] : # A "drop all" rule for even faster Single mode (debugging :) [List.Rules:Drop] <1'0 # These are good rules on larger sites where a user ID may already be used, # so a user simply appends numbers to create his loginID, but then uses the # login name he wanted as basis for password. Just strip off digits and treat # the base-word to some manipulation. These rules found from the 2015 A-M # leak. Only adds 30-50 permutations and only applied to user names that have # digits contained within them, and cracks quite a few. # These are currently Jumbo-specific. [List.Rules:JumboSingle] /?d @?d >4 /?d @?d M @?A >4 Q -c /?d @?d >4 M [lc] Q -c /?d @?d M @?A >4 Q M [lc] Q @?D Q >4 /?d @?d >3 <* $[0-9] Q -c /?d @?d >3 <* M [lc] Q $[0-9] /?d @?d >3 <- Az"12" <+ Q -c /?d @?d >3 <- M [lc] Q Az"12" <+ /?d @?d >3 Az"123" <+ Q -c /?d @?d >3 M [lc] Q Az"123" <+ /?d @?d >2 al d -c /?d @?d >2 al M [lc] Q d (?a )?d /?d a0 'p Xpz0 )?a (?d /?a a0 'p Xpz0 # "Single crack" mode rules [List.Rules:Single] # Simple rules come first... : -s x** -c (?a c Q -c l Q -s-c x** /?u l # These were not included in crackers I've seen, but are pretty efficient, # so I include them near the beginning -<6 >6 '6 -<7 >7 '7 l -<6 -c >6 '6 /?u l -<5 >5 '5 # Wedge the Jumbo-specific addons in here! .include [List.Rules:JumboSingle] # Weird order, eh? Can't do anything about it, the order is based on the # number of successful cracks... <* d r c -c <* (?a d c -<5 -c >5 '5 /?u l -c u Q -c )?a r l -[:c] <* !?A \p1[lc] p -c <* c Q d -<7 -c >7 '7 /?u -<4 >4 '4 l -c <+ (?l c r -c <+ )?l l Tm -<3 >3 '3 -<4 -c >4 '4 /?u -<3 -c >3 '3 /?u l -c u Q r <* d M 'l f Q -c <* l Q d M 'l f Q # About 50% of single-mode-crackable passwords get cracked by now... # >2 x12 ... >8 x18 >[2-8] x1\1 >9 \[ # >3 x22 ... >9 x28 >[3-9] x2\p[2-8] # >4 x32 ... >9 x37 >[4-9] x3\p[2-7] # >2 x12 /?u l ... >8 x18 /?u l -c >[2-8] x1\1 /?u l -c >9 \[ /?u l # >3 x22 /?u l ... >9 x28 /?u l -c >[3-9] x2\p[2-8] /?u l # >4 x32 /?u l ... >9 x37 /?u l -c >[4-9] x3\p[2-7] /?u l # Now to the suffix stuff... <* l $[1-9!0a-rt-z"-/:-@\[-`{-~] -c <* (?a c $[1-9!0a-rt-z"-/:-@\[-`{-~] -[:c] <* !?A (?\p1[za] \p1[lc] $s M 'l p Q X0z0 'l $s -[:c] <* /?A (?\p1[za] \p1[lc] $s <* l r $[1-9!] -c <* /?a u $[1-9!] -[:c] <- (?\p1[za] \p1[lc] Az"'s" -[:c] <- (?\p1[za] \p1[lc] Az"!!" -[:c] (?\p1[za] \p1[lc] $! <- Az"!!" # Removing vowels... -[:c] /?v @?v >2 (?\p1[za] \p1[lc] /?v @?v >2 <* d # crack -> cracked, crack -> cracking <* l [PI] -c <* l [PI] (?a c # mary -> marie -[:c] <* (?\p1[za] \p1[lc] )y omi $e # marie -> mary -[:c] (?\p1[za] \p1[lc] )e \] <+ )i val1 oay # The following are some 3l33t rules -[:c] l /[aelos] s\0\p[4310$] (?\p1[za] \p1[:c] -[:c] l /a /[elos] sa4 s\0\p[310$] (?\p1[za] \p1[:c] -[:c] l /e /[los] se3 s\0\p[10$] (?\p1[za] \p1[:c] -[:c] l /l /[os] sl1 s\0\p[0$] (?\p1[za] \p1[:c] -[:c] l /o /s so0 ss$ (?\p1[za] \p1[:c] -[:c] l /a /e /[los] sa4 se3 s\0\p[10$] (?\p1[za] \p1[:c] -[:c] l /a /l /[os] sa4 sl1 s\0\p[0$] (?\p1[za] \p1[:c] -[:c] l /a /o /s sa4 so0 ss$ (?\p1[za] \p1[:c] -[:c] l /e /l /[os] se3 sl1 s\0\p[0$] (?\p1[za] \p1[:c] -[:c] l /[el] /o /s s\0\p[31] so0 ss$ (?\p1[za] \p1[:c] -[:c] l /a /e /l /[os] sa4 se3 sl1 s\0\p[0$] (?\p1[za] \p1[:c] -[:c] l /a /[el] /o /s sa4 s\0\p[31] so0 ss$ (?\p1[za] \p1[:c] -[:c] l /e /l /o /s se3 sl1 so0 ss$ (?\p1[za] \p1[:c] -[:c] l /a /e /l /o /s sa4 se3 sl1 so0 ss$ (?\p1[za] \p1[:c] # Now to the prefix stuff... l ^[1a-z2-90] -c l Q ^[A-Z] ^[A-Z] l ^["-/:-@\[-`{-~] -[:c] <9 (?a \p1[lc] A0"[tT]he" -[:c] <9 (?a \p1[lc] A0"[aA]my" -[:c] <9 (?a \p1[lc] A0"[mdMD]r" -[:c] <9 (?a \p1[lc] A0"[mdMD]r." -[:c] <9 (?a \p1[lc] A0"__" <- !?A l p ^[240-9] # Some word pair rules... # johnsmith -> JohnSmith, johnSmith -p-c (?a 2 (?a c 1 [cl] # JohnSmith -> john smith, john_smith, john-smith -p 1 <- $[ _\-] + l # JohnSmith -> John smith, John_smith, John-smith -p-c 1 <- (?a c $[ _\-] 2 l # JohnSmith -> john Smith, john_Smith, john-Smith -p-c 1 <- l $[ _\-] 2 (?a c # johnsmith -> John Smith, John_Smith, John-Smith -p-c 1 <- (?a c $[ _\-] 2 (?a c # Applying different simple rules to each of the two words -p-[c:] 1 \p1[ur] 2 l -p-c 2 (?a c 1 [ur] -p-[c:] 1 l 2 \p1[ur] -p-c 1 (?a c 2 [ur] # jsmith -> smithj, etc... -[:c] (?a \p1[lc] [{}] -[:c] (?a \p1[lc] [{}] \0 # Toggle case... -c <+ )?u l Tm -c T0 Q M c Q l Q u Q C Q X0z0 'l -c T[1-9A-E] Q M l Tm Q C Q u Q l Q c Q X0z0 'l -c l Q T[1-9A-E] Q M T\0 Q l Tm Q C Q u Q X0z0 'l -c >2 2 /?l /?u t Q M c Q C Q l Tm Q X0z0 'l # Deleting chars... >[2-8] D\p[1-7] >[8-9A-E] D\1 -c /?u >[2-8] D\p[1-7] l -c /?u >[8-9A-E] D\1 l =1?a \[ M c Q -c (?a >[1-9A-E] D\1 c # Inserting a dot... -[:c] >3 (?a \p1[lc] i[12]. # More suffix stuff... <- l Az"[190][0-9]" -c <- (?a c Az"[190][0-9]" <- l Az"[782][0-9]" -c <- (?a c Az"[782][0-9]" <* l $[A-Z] -c <* (?a c $[A-Z] # cracking -> CRACKiNG -c u /I sIi # Crack96 -> cRACK96 %2?a C Q # Crack96 -> cRACK(^ /?A S Q # Crack96 -> CRaCK96 -c /?v V Q # Really weird charset conversions, like "england" -> "rmh;smf" :[RL] Q l Q [RL] -c (?a c Q [RL] :[RL] \0 Q # Both prefixing and suffixing... <- l ^[1!@#$%^&*\-=_+.?|:'"] $\1 <- l ^[({[<] $\p[)}\]>] # The rest of two-digit suffix stuff, less common numbers... <- l Az"[63-5][0-9]" -c <- (?a c Az"[63-5][0-9]" # Some multi-digit numbers... -[:c] (?a \p1[lc] Az"007" <+ -[:c] (?a \p1[lc] Az"123" <+ -[:c] (?a \p1[lc] Az"[0-9]\0\0" <+ -[:c] (?a \p1[lc] Az"1234" <+ -[:c] (?a \p1[lc] Az"[0-9]\0\0\0" <+ -[:c] (?a \p1[lc] Az"12345" <+ -[:c] (?a \p1[lc] Az"[0-9]\0\0\0\0" <+ -[:c] (?a \p1[lc] Az"123456" <+ -[:c] (?a \p1[lc] Az"[0-9]\0\0\0\0\0" <+ # Some [birth] years... l Az"19[7-96-0]" <+ >- l Az"20[01]" <+ >- l Az"19[7-9][0-9]" <+ l Az"20[01][0-9]" <+ l Az"19[6-0][9-0]" <+ [List.Rules:Extra] # Insert/overstrike some characters... !?A >[1-6] l i\0[a-z] !?A l o0[a-z] !?A >[1-7] l o\0[a-z] # Toggle case everywhere (up to length 8), assuming that certain case # combinations were already tried. -c T1 Q M T0 Q -c T2 Q M T[z0] T[z1] Q -c T3 Q M T[z0] T[z1] T[z2] Q -c T4 Q M T[z0] T[z1] T[z2] T[z3] Q -c T5 Q M T[z0] T[z1] T[z2] T[z3] T[z4] Q -c T6 Q M T[z0] T[z1] T[z2] T[z3] T[z4] T[z5] Q -c T7 Q M T[z0] T[z1] T[z2] T[z3] T[z4] T[z5] T[z6] Q # Very slow stuff... l Az"[1-90][0-9][0-9]" <+ -c (?a c Az"[1-90][0-9][0-9]" <+ <[\-9] l A\p[z0]"[a-z][a-z]" <- l ^[a-z] $[a-z] # Wordlist mode rules [List.Rules:Wordlist] # Try words as they are : # Lowercase every pure alphanumeric word -c >3 !?X l Q # Capitalize every pure alphanumeric word -c (?a >2 !?X c Q # Lowercase and pluralize pure alphabetic words <* >2 !?A l p # Lowercase pure alphabetic words and append '1' <* >2 !?A l $1 # Capitalize pure alphabetic words and append '1' -c <* >2 !?A c $1 # Duplicate reasonably short pure alphabetic words (fred -> fredfred) <7 >1 !?A l d # Lowercase and reverse pure alphabetic words >3 !?A l M r Q # Prefix pure alphabetic words with '1' >2 !?A l ^1 # Uppercase pure alphanumeric words -c >2 !?X u Q M c Q u # Lowercase pure alphabetic words and append a digit or simple punctuation <* >2 !?A l $[2!37954860.?] # Words containing punctuation, which is then squeezed out, lowercase /?p @?p >3 l # Words with vowels removed, lowercase /?v @?v >3 l # Words containing whitespace, which is then squeezed out, lowercase /?w @?w >3 l # Capitalize and duplicate short pure alphabetic words (fred -> FredFred) -c <7 >1 !?A c d # Capitalize and reverse pure alphabetic words (fred -> derF) -c <+ >2 !?A c r # Reverse and capitalize pure alphabetic words (fred -> Derf) -c >2 !?A l M r Q c # Lowercase and reflect pure alphabetic words (fred -> fredderf) <7 >1 !?A l d M 'l f Q # Uppercase the last letter of pure alphabetic words (fred -> freD) -c <+ >2 !?A l M r Q c r # Prefix pure alphabetic words with '2' or '4' >2 !?A l ^[24] # Capitalize pure alphabetic words and append a digit or simple punctuation -c <* >2 !?A c $[2!3957468.?0] # Prefix pure alphabetic words with digits >2 !?A l ^[379568] # Capitalize and pluralize pure alphabetic words of reasonable length -c <* >2 !?A c p # Lowercase/capitalize pure alphabetic words of reasonable length and convert: # crack -> cracked, crack -> cracking -[:c] <* >2 !?A \p1[lc] M [PI] Q # Try the second half of split passwords -s x** -s-c x** M l Q # Case toggler for cracking MD4-based NTLM hashes (with the contributed patch) # given already cracked DES-based LM hashes. Use --rules=NT to use this. [List.Rules:NT] : -c T0Q -c ->2 a0 T1QT[z0] -c ->3 a0 T2QT[z0]T[z1] -c ->4 a0 T3QT[z0]T[z1]T[z2] -c ->5 a0 T4QT[z0]T[z1]T[z2]T[z3] -c ->6 a0 T5QT[z0]T[z1]T[z2]T[z3]T[z4] -c ->7 a0 T6QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5] -c ->8 a0 T7QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6] -c ->9 a0 T8QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7] -c ->A a0 T9QT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8] -c ->B a0 TAQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9] -c ->C a0 TBQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA] -c ->D a0 TCQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]T[zB] -c ->E a0 TDQT[z0]T[z1]T[z2]T[z3]T[z4]T[z5]T[z6]T[z7]T[z8]T[z9]T[zA]T[zB]T[zC] # Shift toggler, up to length 16 [List.Rules:ShiftToggle] : W0Q ->2 a0 W1QW[z0] ->3 a0 W2QW[z0]W[z1] ->4 a0 W3QW[z0]W[z1]W[z2] ->5 a0 W4QW[z0]W[z1]W[z2]W[z3] ->6 a0 W5QW[z0]W[z1]W[z2]W[z3]W[z4] ->7 a0 W6QW[z0]W[z1]W[z2]W[z3]W[z4]W[z5] ->8 a0 W7QW[z0]W[z1]W[z2]W[z3]W[z4]W[z5]W[z6] ->9 a0 W8QW[z0]W[z1]W[z2]W[z3]W[z4]W[z5]W[z6]W[z7] ->A a0 W9QW[z0]W[z1]W[z2]W[z3]W[z4]W[z5]W[z6]W[z7]W[z8] ->B a0 WAQW[z0]W[z1]W[z2]W[z3]W[z4]W[z5]W[z6]W[z7]W[z8]W[z9] ->C a0 WBQW[z0]W[z1]W[z2]W[z3]W[z4]W[z5]W[z6]W[z7]W[z8]W[z9]W[zA] ->D a0 WCQW[z0]W[z1]W[z2]W[z3]W[z4]W[z5]W[z6]W[z7]W[z8]W[z9]W[zA]W[zB] ->E a0 WDQW[z0]W[z1]W[z2]W[z3]W[z4]W[z5]W[z6]W[z7]W[z8]W[z9]W[zA]W[zB]W[zC] ->F a0 WEQW[z0]W[z1]W[z2]W[z3]W[z4]W[z5]W[z6]W[z7]W[z8]W[z9]W[zA]W[zB]W[zC]W[zD] ->G a0 WFQW[z0]W[z1]W[z2]W[z3]W[z4]W[z5]W[z6]W[z7]W[z8]W[z9]W[zA]W[zB]W[zC]W[zD]W[zE] [List.Rules:Multiword] -c / Dp l -c / Dp c Tp -c / Dp / Dp l -c / Dp c Tp / Dp Tp -c %4[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M %3[ ] vbpa Tb Q M %2[ ] vbpa Tb Q M /[ ] vbpa Tb Q @?[Zw] -c %3[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M %2[ ] vbpa Tb Q M /[ ] vbpa Tb Q @?[Zw] -c %2[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M /[ ] vbpa Tb Q @?[Zw] -c /[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q @?[Zw] -c %2[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q @?[Zw] -c %3[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q @?[Zw] -c %4[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q @?[Zw] -c %2[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M /[ ] vbpa Tb Q @?[Zw] -c %3[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M /[ ] vbpa Tb Q @?[Zw] -c %4[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M /[ ] vbpa Tb Q @?[Zw] -c %2[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M %3[ ] vbpa Tb Q @?[Zw] -c %2[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M %4[ ] vbpa Tb Q @?[Zw] -c %3[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M %4[ ] vbpa Tb Q @?[Zw] -c %4[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M %3[ ] vbpa Tb Q M %2[ ] vbpa Tb Q @?[Zw] -c %4[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M %2[ ] vbpa Tb Q M /[ ] vbpa Tb Q @?[Zw] -c %4[ ] T[0z] \p0[Q:] \p0[M:] va01 vbpa Tb Q M %3[ ] vbpa Tb Q M /[ ] vbpa Tb Q @?[Zw] # Used for loopback. This rule will produce candidates "PASSWOR" and "D" for # an input of "PASSWORD" (assuming LM, which has halves of length 7). [List.Rules:Split] : -s x** # Some Office <=2003 files have passwords truncated at 15 [List.Rules:OldOffice] : ->F -F 'F # Rules from Hash Runner 2014 [List.Rules:o1] # o[0-9A-Z][ -~] ->\r[1-9A-ZZ] >\p[0-9A-Z] o\0[ -~] Q [List.Rules:o2] # o[0-9A-E][ -~] Q M o[0-9A-E][ -~] Q ->[1-9A-F] ->[1-9A-F] >\p1[0-9A-E] >\p2[0-9A-E] o\3[ -~] Q M o\4[ -~] Q [List.Rules:o3] # o[0-9][ -~] Q M o[0-9][ -~] Q M o[0-9][ -~] Q ->[1-9A] ->[1-9A] ->[1-9A] >\p1[0-9] >\p2[0-9] >\p3[0-9] o\4[ -~] Q M o\5[ -~] Q M o\6[ -~] Q [List.Rules:o] .include [List.Rules:o1] .include [List.Rules:o2] [List.Rules:i1] # i[0-9A-Z][ -~] ->\r[2-9A-ZZZ] >\p1[0-9A-Z] i\0[ -~] [List.Rules:i2] # i[0-9A-E][ -~] i[0-9A-E][ -~] ->[2-9A-G] ->[2-9A-G] >\p1[0-9A-E] >\p2[0-9A-E] i\3[ -~] i\4[ -~] [List.Rules:i3] # i[0-9][ -~] i[0-9][ -~] i[0-9][ -~] ->[4-9A-D] ->[4-9A-D] ->[4-9A-D] >\p1[0-9] >\p2[0-9] >\p3[0-9] i\4[ -~] i\5[ -~] i\6[ -~] [List.Rules:i] .include [List.Rules:i1] .include [List.Rules:i2] [List.Rules:oi] .include [List.Rules:o1] .include [List.Rules:i1] .include [List.Rules:o2] .include [List.Rules:i2] [List.Rules:T9] a0 /?D l sa2 sb2 sc2 sd3 se3 sf3 sg4 sh4 si4 sj5 sk5 sl5 sm6 sn6 so6 sp7 sq7 sr7 ss7 st8 su8 sv8 sw9 sx9 sy9 sz9 s?D* a0 /?D l sa2 sb2 sc2 sd3 se3 sf3 sg4 sh4 si4 sj5 sk5 sl5 sm6 sn6 so6 sp7 sq7 sr7 ss7 st8 su8 sv8 sw9 sx9 sy9 sz9 /?D s?D# # A few rule sets from hashcat (taken as-is from https://github.com/hashcat/) # # Note that these are very poorly optimized with our measure, as they lack # rule-rejection flags. Also, they don't use the preprocessor so are a lot # harder to digest (for a human looking at them that is, for JtR there's # virtually no difference). # [List.Rules:best64] !! hashcat logic ON .include !! hashcat logic OFF [List.Rules:d3ad0ne] !! hashcat logic ON .include !! hashcat logic OFF [List.Rules:dive] !! hashcat logic ON .include !! hashcat logic OFF [List.Rules:InsidePro] !! hashcat logic ON .include !! hashcat logic OFF [List.Rules:T0XlC] !! hashcat logic ON .include .include .include !! hashcat logic OFF [List.Rules:rockyou-30000] !! hashcat logic ON .include !! hashcat logic OFF [List.Rules:specific] !! hashcat logic ON .include !! hashcat logic OFF [List.Rules:hashcat] .include [List.Rules:best64] .include [List.Rules:d3ad0ne] .include [List.Rules:dive] .include [List.Rules:InsidePro] .include [List.Rules:T0XlC] .include [List.Rules:rockyou-30000] .include [List.Rules:specific] # These are for phrase wordlists w/ spaces [List.Rules:passphrase-rule1] .include [List.Rules:passphrase-rule2] .include # Default Loopback mode rules. [List.Rules:Loopback] .include [List.Rules:ShiftToggle] .include [List.Rules:Split] !! hashcat logic ON +m -m !! hashcat logic OFF b1 ] # For Single Mode against fast hashes [List.Rules:Single-Extra] .include [List.Rules:Single] .include [List.Rules:Extra] .include [List.Rules:OldOffice] # For Wordlist mode and very fast hashes [List.Rules:Jumbo] .include [List.Rules:Single-Extra] .include [List.Rules:Wordlist] .include [List.Rules:ShiftToggle] .include [List.Rules:Multiword] .include [List.Rules:best64] # KoreLogic rules .include # Everything, including all KoreLogic and the rest of included hashcat rules. # Only for very fast hashes and/or Single mode. Some of these rules are of # ridiculous quality and lack optimizations - you have been warned. [List.Rules:All] .include [List.Rules:Jumbo] .include [List.Rules:KoreLogic] .include [List.Rules:T9] .include [List.Rules:hashcat] # Incremental modes # This is for one-off uses (make your own custom.chr) [Incremental:Custom] File = $JOHN/custom.chr MinLen = 0 # The theoretical CharCount is 211, we've got 196. [Incremental:UTF8] File = $JOHN/utf8.chr MinLen = 0 CharCount = 196 # This is CP1252, a super-set of ISO-8859-1. # The theoretical CharCount is 219, we've got 203. [Incremental:Latin1] File = $JOHN/latin1.chr MinLen = 0 CharCount = 203 [Incremental:ASCII] File = $JOHN/ascii.chr MinLen = 0 MaxLen = 13 CharCount = 95 [Incremental:LM_ASCII] File = $JOHN/lm_ascii.chr MinLen = 0 MaxLen = 7 CharCount = 69 # This is CP858 (CP850 + Euro sign, superset of CP437). # The theoretical CharCount is 209 minus lowercase, we've got 132. [Incremental:LanMan] File = $JOHN/lanman.chr MinLen = 0 MaxLen = 7 CharCount = 132 # This is alnum (upper & lower case) as well as space. [Incremental:Alnumspace] File = $JOHN/alnumspace.chr MinLen = 1 MaxLen = 13 CharCount = 63 [Incremental:Alnum] File = $JOHN/alnum.chr MinLen = 1 MaxLen = 13 CharCount = 62 [Incremental:Alpha] File = $JOHN/alpha.chr MinLen = 1 MaxLen = 13 CharCount = 52 [Incremental:LowerNum] File = $JOHN/lowernum.chr MinLen = 1 MaxLen = 13 CharCount = 36 [Incremental:UpperNum] File = $JOHN/uppernum.chr MinLen = 1 MaxLen = 13 CharCount = 36 [Incremental:LowerSpace] File = $JOHN/lowerspace.chr MinLen = 1 MaxLen = 13 CharCount = 27 [Incremental:Lower] File = $JOHN/lower.chr MinLen = 1 MaxLen = 13 CharCount = 26 [Incremental:Upper] File = $JOHN/upper.chr MinLen = 1 MaxLen = 13 CharCount = 26 [Incremental:Digits] File = $JOHN/digits.chr MinLen = 1 MaxLen = 20 CharCount = 10 # Some pre-defined word filters as used to generate the supplied .chr files [List.External:Filter_ASCII] void filter() { int i, c; i = 0; while (c = word[i++]) if (c < 0x20 || c > 0x7e || i > 13) { word = 0; return; } } [List.External:Filter_LanMan] void filter() { int i, c; i = 0; while (c = word[i]) { if (i >= 14) { // of up to 14 characters long word = 0; return; } if (c >= 'a' && c <= 'z') // Convert to uppercase word[i] &= 0xDF; i++; } word[7] = 0; // Truncate at 7 characters } [List.External:Filter_LM_ASCII] void filter() { int i, c; i = 0; while (c = word[i]) { if (c < 0x20 || c > 0x7e || // Require ASCII-only i >= 14) { // of up to 14 characters long word = 0; return; } if (c >= 'a' && c <= 'z') // Convert to uppercase word[i] &= 0xDF; i++; } word[7] = 0; // Truncate at 7 characters } [List.External:Filter_Alnumspace] void filter() { int i, c; i = 0; while (c = word[i++]) if (c != ' ' && (((c < '0' || c > '9') && ((c &= 0xDF) < 'A' || c > 'Z'))) || i > 13) { word = 0; return; } } [List.External:Filter_Alnum] void filter() { int i, c; i = 0; while (c = word[i++]) if (((c < '0' || c > '9') && ((c &= 0xDF) < 'A' || c > 'Z')) || i > 13) { word = 0; return; } } [List.External:Filter_Alpha] void filter() { int i, c; i = 0; while (c = word[i++]) if ((c &= 0xDF) < 'A' || c > 'Z' || i > 13) { word = 0; return; } } [List.External:Filter_LowerNum] void filter() { int i, c; i = 0; while (c = word[i++]) if (((c < 'a' || c > 'z') && (c < '0' || c > '9')) || i > 13) { word = 0; return; } } [List.External:Filter_UpperNum] void filter() { int i, c; i = 0; while (c = word[i++]) if (((c < 'A' || c > 'Z') && (c < '0' || c > '9')) || i > 13) { word = 0; return; } } [List.External:Filter_LowerSpace] void filter() { int i, c; i = 0; while (c = word[i++]) if (((c < 'a' || c > 'z') && c != ' ') || i > 13) { word = 0; return; } } [List.External:Filter_Lower] void filter() { int i, c; i = 0; while (c = word[i++]) if (c < 'a' || c > 'z' || i > 13) { word = 0; return; } } [List.External:Filter_Upper] void filter() { int i, c; i = 0; while (c = word[i++]) if (c < 'A' || c > 'Z' || i > 13) { word = 0; return; } } [List.External:Filter_Digits] void filter() { int i, c; i = 0; while (c = word[i++]) if (c < '0' || c > '9' || i > 20) { word = 0; return; } } [List.External:Filter_No_Cap_or_Symbols] void filter() { int i, c; i = 0; while (c = word[i++]) if ((c < 'a' || c > 'z') && (c < '0' || c > '9')) { return; } word = 0; return; } # Reject words that are illegal UTF-8 # We obviously let pure ASCII through too [List.External:Filter_UTF8] void filter() { int s, a, p; p = 0; while (s = word[p++] & 0xff) { if (s > 0x7f) { if (s < 0xc2 || s > 0xf7) { // illegal single-byte word = 0; return; } // two-byte c2..df a = word[p++] & 0xff; if (a < 0x80 || a > 0xbf) { word = 0; return; } if (s > 0xdf) { // three-byte e0..ef if (s == 0xe0 && a < 0xa0) { word = 0; return; } if (s == 0xed && a > 0x9f) { word = 0; return; } if (s == 0xf0 && a < 0x90) { word = 0; return; } if (s == 0xf4 && a > 0x8f) { word = 0; return; } a = word[p++] & 0xff; if (a < 0x80 || a > 0xbf) { word = 0; return; } if (s > 0xef) { // four-byte f0..f7 a = word[p++] & 0xff; if (a < 0x80 || a > 0xbf) { word = 0; return; } } } } } } # Reject words that are LEGAL UTF-8 (also rejects pure ASCII) [List.External:Filter_non-UTF8] void filter() { int s, a, p; p = 0; while (s = word[p++] & 0xff) { if (s > 0x7f) { if (s < 0xc2 || s > 0xf7) { // illegal single-byte return; } // two-byte c2..df a = word[p++] & 0xff; if (a < 0x80 || a > 0xbf) { return; } if (s > 0xdf) { // three-byte e0..ef if (s == 0xe0 && a < 0xa0) { return; } if (s == 0xed && a > 0x9f) { return; } if (s == 0xf0 && a < 0x90) { return; } if (s == 0xf4 && a > 0x8f) { return; } a = word[p++] & 0xff; if (a < 0x80 || a > 0xbf) { return; } if (s > 0xef) { // four-byte f0..f7 a = word[p++] & 0xff; if (a < 0x80 || a > 0xbf) { return; } } } } } word = 0; } # A simple cracker for LM hashes [List.External:LanMan] int length; // Current length int maxlength; void init() { if (req_minlen) length = req_minlen; else length = 1; if (req_maxlen) maxlength = req_maxlen; else // the format's limit maxlength = cipher_limit; word[0] = 'A' - 1; // Start with "A" word[length] = 0; } void generate() { int i; i = length - 1; // Start from the last character while (++word[i] > 'Z') // Try to increase it if (i) // Overflow here, any more positions? word[i--] = 'A'; // Yes, move to the left, and repeat else // No if (length < maxlength) { word[i = ++length] = 0; // Switch to the next length while (i--) word[i] = 'A'; return; } else { word = 0; return; // We're done } } void restore() { length = 0; // Calculate the length while (word[length]) length++; } # Simple and well-commented, yet useful external mode example # NOTE, this has now been 'split' up into a base extern, 'base', and then # multiple External:double functions. It still has same code as original # double, but now can be easily expanded. [List.External_base:Double] /* * This cracking mode tries all the possible duplicated lowercase alphabetic * "words" of up to 8 characters long. Since word halves are the same, it * only has to try about 500,000 words. */ /* Global variables: current length and word */ /* make this 'long' enough for other externs that include this one */ /* (up to 125 bytes long) */ int length, current[126], max; /* this new 'type' variable, is used to tell double what character set to * use. It can use the original (alpha). If type is 0 (i.e. unset), then * a-z (alpha) character set is used. If type is '0' (a zero ascii byte) * then alnum charset is used, a-z0-9. If type is a space char, then all * charset is used [space - tilde] or [ -~]. This required setting the * type var in the init() of alnum or all doubles (it can be left unset * in the alpha versions). It also requires some if logic in generate. * other than that, it works the same, with almost no performance hit */ int type; /* Generates a new word */ void generate() { int i; /* Export last generated word, duplicating it at the same time; here "word" * is a pre-defined external variable. */ word[(i = length) << 1] = 0; while (i--) word[length + i] = word[i] = current[i]; /* Generate a new word */ i = length - 1; // Start from the last character if (type == 0) { /* alpha */ while (++current[i] > 'z') // Try to increase it if (i) // Overflow here, any more positions? current[i--] = 'a'; // Yes, move to the left, and repeat else { // No current = 0; // Request a length switch break; // Break out of the loop } } else if (type == '0') { /* alnum */ if (current[i] == 'z') current[i] = '0'-1; while (++current[i] == '9') { // Try to increase it if (i) // Overflow here, any more positions? current[i--] = 'a'; // Yes, move to the left, and repeat else { // No current = 0; // Request a length switch break; // Break out of the loop } if (current[i] == 'z') current[i] = '0'-1; } } else if (type == ' ') { /* all */ while (++current[i] > '~') { // Try to increase it if (i) // Overflow here, any more positions? current[i--] = ' '; // Yes, move to the left, and repeat else { // No current = 0; // Request a length switch break; // Break out of the loop } } } /* else ????? wtf?? */ /* Switch to the next length, unless we were generating 8 character long * words already. */ if (!current && length < max) { i = ++length; if (type == 0 || type == '0') while (i--) current[i] = 'a'; else if (type == ' ') while (i--) current[i] = ' '; } } /* Called when restoring an interrupted session */ void restore() { int i; /* Import the word back */ i = 0; while (current[i] = word[i]) i++; /* ...and calculate the half-word length */ length = i >> 1; } [List.External:Double] .include [List.External_base:Double] /* Called at startup to initialize the global variables */ void init() { int i; if (req_minlen) i = length = (req_minlen + 1) / 2; else i = length = 2; // Start with 4 character long words while (i--) current[i] = 'a'; // Set our half-word to "aa" if (req_maxlen) max = (req_maxlen + 1) / 2; else if (length > 4) max = length; else max = 4; } [List.External:Double_alnum] .include [List.External_base:Double] /* Called at startup to initialize the global variables */ void init() { int i; if (req_minlen) i = length = (req_minlen + 1) / 2; else i = length = 2; // Start with 4 character long words while (i--) current[i] = 'a'; // Set our half-word to "aa" if (req_maxlen) max = (req_maxlen + 1) / 2; else if (length > 4) max = length; else max = 4; type = '0'; } [List.External:Double_all] .include [List.External_base:Double] void init() { int i; if (req_minlen) i = length = (req_minlen + 1) / 2; else i = length = 2; // Start with 4 character long words while (i--) current[i] = ' '; // Set our half-word to " " if (req_maxlen) max = (req_maxlen + 1) / 2; else if (length > 4) max = length; else max = 4; type = ' '; } # Try strings of repeated characters. # # This is the code which is common for all [List.External:Repeats*] # sections which include this External_base section. # The generate() function will limit the maximum length of generated # candidates to either the format's limit (maximum password length) # or to the limit specified with --stdout=LENGTH (Default: 125), # thus avoiding duplicate candidates for formats with limited maximum # passwortd length. # The comparison of the current length and the limit is only done # after switching to a new length. # So, if the minimum length specified already exceeds this limit, # then all the candidates for the minimum length will be generated # nevertheless. [List.External_base:Repeats] int minlength, maxlength, minc, maxc, length, c; void generate() { int i; i = 0; while (i < length) word[i++] = c; word[i] = 0; if (c++ < maxc) return; c = minc; if (++length > maxlength) c = 0; // Will NUL out the next "word" and thus terminate } # Try strings of repeated characters (range: space - 0xff). [List.External:Repeats] .include [List.External_base:Repeats] void init() { if (req_minlen) minlength = req_minlen; else minlength = 1; if (req_maxlen) maxlength = req_maxlen; else maxlength = cipher_limit; // the format's limit minc = 0x20; maxc = 0xff; length = minlength; c = minc; } # Try strings of repeated digits (range: '0' - '9'). [List.External:Repeats_digits] .include [List.External_base:Repeats] void init() { if (req_minlen) minlength = req_minlen; else minlength = 1; if (req_maxlen) maxlength = req_maxlen; else maxlength = cipher_limit; // the format's limit minc = '0'; maxc = '9'; length = minlength; c = minc; } # Try strings of repeated lowercase letters (range: 'a' - 'z'). [List.External:Repeats_lowercase] .include [List.External_base:Repeats] void init() { if (req_minlen) minlength = req_minlen; else minlength = 1; if (req_maxlen) maxlength = req_maxlen; else maxlength = cipher_limit; // the format's limit minc = 'a'; maxc = 'z'; length = minlength; c = minc; } # Try strings of repeated printable ASCII characters # (range: ' ' - '~'). [List.External:Repeats_printable_ASCII] .include [List.External_base:Repeats] void init() { if (req_minlen) minlength = req_minlen; else minlength = 1; if (req_maxlen) maxlength = req_maxlen; else maxlength = cipher_limit; // the format's limit minc = ' '; maxc = '~'; length = minlength; c = minc; } # Try character sequences ("0123456", "acegikmoqs", "ZYXWVU", etc.). # # The generate() function will limit the maximum length of generated # candidates to either the format's limit (maximum password length) # or to the limit specified with --stdout=LENGTH (Default: 125), # thus avoiding duplicate candidates for formats with limited maximum # passwortd length. # The comparison of the current length and the limit is only done # after switching to a new length. # So, if the minimum length specified already exceeds this limit, # then all the candidates for the minimum length will be generated # nevertheless. # External modes reusing this External_base mode should only need to # adjust the init() function. # In the init() function, a minimum length which is > 1 should be # specified. # Otherwise, the generated candidates will not depend on the increment # specified. # For length = 1, the candidates will be the same as for external mode # Repeats with length 1. # Actually, Repeats is a special case of Sequence, using increment = 0. # External modes reusing this External_base mode should also make sure # that the number of different characters (specified as a range from "from" # to "to") is not smaller than the minimum length ("minlength"), # if the start increment "inc" is 1. # For a start increment > 1, the number of different characters in the # range "from" - "to" must be greater than or equal to # (1 + ("minlength" - 1) * "inc"). # Otherwise you might get unexpected results. # The range of characters to be used for the sequences needs to be # specified by adjusting the "from" and "to" variables. # To generate sequences which decrement characters ("987654"), # "from" must be > "to". # Otherwise, the generated sequences will increment characters ("abcdef"). # # Variables to be used and the generate() function are common # for all sections which include this External_base section. [List.External_base:Sequence] /* * See the [List.External:Sequence_0-9] section to learn more about * the meaning of these variables which can be adjusted to define * new external modes based on an existing one: */ int minlength, from, to, maxlength, inc, direction; /* * The value of these variables shouldn't be changed when copying * an existing external mode: */ int length, first; void generate() { int i; i = 0; while (i < length) { word[i] = first + (i * inc * direction); ++i; } word[i] = 0; // start the next sequence of the same length // with the next character first = first + direction; // But check that a sequence of the current length // is still possible (without leaving the range of // characters allowed if ((direction > 0 && first + (length - 1) * inc > to) || (direction < 0 && first - (length - 1) * inc < to)) { // No more sequence is possible. Reset start character first = from; // Now try the next length. // But just in case an individual External mode reusing // this External_base mode did specify a maxlength // which is larger than the one supported by the format // or by --stdout=LENGTH, make sure no more candidates // are generated. // Checking this just once per length per increment // doen't really hurt performance. if (maxlength > cipher_limit) maxlength = cipher_limit; // For a similar reason, the maximum length of a // sequence is limited by the number of different // characters and by the increment. // The larger the increment, the smaller // the maximum possible length for a given // character range. while (inc * (maxlength - 1) > direction * (to - from)) --maxlength; if (++length > maxlength) { // The maximum length for this increment has been reached. // Restart at minimum length with the next possible // increment ++inc; // Unfortunately, we have to check again // if the maximum length needs to be reduced // for the new increment while (inc * (maxlength - 1) > direction * (to - from)) --maxlength; length = minlength; } if (maxlength < minlength) // With the current increment, we can't even generate // sequences of the minimum required length. // So we need to stop here. // This will make sure that no more candidiates // will be generated: first = 0; } } # Try sequences of digits (range: '0' - '9'). # # Aditional comments can be found in the # section [List.External_base:Sequence] # # This external mode is thoroughly commented, # to make it easier to copy and adjust it as needed. [List.External:Sequence_0-9] .include [List.External_base:Sequence] void init() { // Adjust the following 4 variables if you want to define // a different external mode. // This is the start character for the generated sequence // if "from" is smaller than "to", the increment from // first to second character ... will be positive ("0123456789"). // Otherwise, it will be negative ("987654321"). from = '0'; to = '9'; // minimum length of the sequence // make sure it is not larger than the number of different characters // in the range between "from" and "to" specified above minlength = 2; // start increment for generating the sequence, usually 1 // if it is larger than 1, you need even more characters // in the range between "from" and "to" // Don't specify a negative value here. // If you want to generate sequences like "zyxwvu" or "86420", // adjust "from" and "to" so that "from" is larger than "to". // (A start increment of 0 is also possible, in that case the first // sequences will be candidates which just repeat the same character.) inc = 1; // For copied external modes, no further changes should be required // in the statements following this comment length = minlength; first = from; if (from <= to) { maxlength = to - from + 1; direction = 1; } else { // We have to create sequences which decrement the previous character maxlength = from - to + 1; direction = -1; } } # Try sequence of lower case letters (range: 'a' - 'z'). # This external mode is not very well documented. # Refer to [List.External:Sequence_0-9] for more detailed information. [List.External:Sequence_a-z] .include [List.External_base:Sequence] void init() { from = 'a'; to = 'z'; minlength = 2; inc = 1; length = minlength; first = from; if (from <= to) { maxlength = to - from + 1; direction = 1; } else { maxlength = from - to + 1; direction = -1; } } # Try sequence of lower case letters (range: 'a' - 'z'), but reversed # ("zxywvu"). # This external mode is not very well documented. # Refer to [List.External:Sequence_0-9] for more detailed information. [List.External:Sequence_z-a] .include [List.External_base:Sequence] void init() { from = 'z'; to = 'a'; minlength = 2; inc = 1; length = minlength; first = from; if (from <= to) { maxlength = to - from + 1; direction = 1; } else { maxlength = from - to + 1; direction = -1; } } # Try sequence of printable ASCII characters (range: ' ' - '~'). # This external mode is not very well documented. # Refer to [List.External:Sequence_0-9] for more detailed information. [List.External:Sequence_printable_ascii] .include [List.External_base:Sequence] void init() { from = ' '; to = '~'; minlength = 2; inc = 1; length = minlength; first = from; if (from <= to) { maxlength = to - from + 1; direction = 1; } else { maxlength = from - to + 1; direction = -1; } } # Try sequence of printable ASCII characters (range: ' ' - '~'), # but decrementing characters ("fedcba") instead of incrementing. # This external mode is not very well documented. # Refer to [List.External:Sequence_0-9] for more detailed information. [List.External:Sequence_reversed_ascii] .include [List.External_base:Sequence] void init() { from = '~'; to = ' '; minlength = 2; inc = 1; length = minlength; first = from; if (from <= to) { maxlength = to - from + 1; direction = 1; } else { maxlength = from - to + 1; direction = -1; } } # Try sequence of characters (range: space - 0xff). # This external mode is not very well documented. # Refer to [List.External:Sequence_0-9] for more detailed information. [List.External:Sequence] .include [List.External_base:Sequence] void init() { from = ' '; to = 0xff; minlength = 2; inc = 1; length = minlength; first = from; if (from <= to) { maxlength = to - from + 1; direction = 1; } else { maxlength = from - to + 1; direction = -1; } } # Generate candidate passwords from many small subsets of characters from a # much larger full character set. This will test for passwords containing too # few different characters. As currently implemented, this code will produce # some duplicates, although their number is relatively small when the maximum # number of different characters (the maxdiff setting) is significantly lower # than the maximum length (the maxlength setting). Nevertheless, you may want # to pass the resulting candidate passwords through "unique" if you intend to # test them against hashes that are salted and/or of a slow to compute type. [List.External:Subsets] int minlength; // Minimum password length to try int maxlength; // Maximum password length to try int startdiff; // Initial number of characters in a subset to try int maxdiff; // Maximum number of characters in a subset to try int last; // Last character position, zero-based int lastid; // Character index in the last position int id[0x7f]; // Current character indices for other positions int subset[0x100], c0; // Current subset int subcount; // Number of characters in the current subset int subid[0x100]; // Indices into charset[] of characters in subset[] int charset[0x100]; // Full character set int charcount; // Number of characters in the full charset void init() { int i, c; // Minimum password length to try, must be at least 1 if (req_minlen) minlength = req_minlen; else minlength = 1; // Maximum password length to try, must be at least same as minlength // This external mode's default maximum length can be adjusted // using --max-length= on the command line if (req_maxlen) maxlength = req_maxlen; else maxlength = 8; // "cipher_limit" is the variable which contains the format's // maximum password length if (maxlength > cipher_limit) maxlength = cipher_limit; startdiff = 1; // Initial number of different characters to try maxdiff = 3; // Maximum number of different characters to try /* This defines the character set */ i = 0; c = 0x20; while (c <= 0x7e) charset[i++] = c++; if (maxdiff > (charcount = i)) maxdiff = i; if (maxdiff > maxlength) maxdiff = maxlength; /* * Initialize the variables such that generate() gets to its "next subset" * code, which will initialize everything for real. */ subcount = (i = startdiff) - 1; while (i--) subid[i] = charcount; subset[0] = c0 = 0; last = maxlength - 1; lastid = -1; } void generate() { int i; /* Handle the typical case specially */ if (word[last] = subset[++lastid]) return; lastid = 0; word[i = last] = c0; while (i--) { // Have a preceding position? if (word[i] = subset[++id[i]]) return; id[i] = 0; word[i] = c0; } if (++last < maxlength) { // Next length? id[last] = lastid = 0; word[last] = c0; word[last + 1] = 0; return; } /* Next subset */ if (subcount) { int j; i = subcount - 1; j = charcount; while (++subid[i] >= j) { if (i--) { j--; continue; } subid[i = 0] = 0; subset[++subcount] = 0; break; } } else { subid[i = 0] = 0; subset[++subcount] = 0; } subset[i] = charset[subid[i]]; while (++i < subcount) subset[i] = charset[subid[i] = subid[i - 1] + 1]; if (subcount > maxdiff) { word = 0; // Done return; } /* * We won't be able to fully use the subset if the length is smaller than the * character count. We assume that we've tried all smaller subsets before, so * we don't bother with such short lengths. */ if (minlength < subcount) last = subcount - 1; else last = minlength - 1; c0 = subset[0]; i = 0; while (i <= last) { id[i] = 0; word[i++] = c0; } lastid = 0; word[i] = 0; } # Try sequences of adjacent keys on a keyboard as candidate passwords [List.External:Keyboard] int maxlength, length; // Maximum password length to try, current length int fuzz; // The desired "fuzz factor", either 0 or 1 int id[15]; // Current character indices for each position int m[0x800]; // The keys matrix int mc[0x100]; // Counts of adjacent keys int f[0x40], fc; // Characters for the first position, their count void init() { int minlength; int i, j, c, p; int k[0x40]; // Initial password length to try if (req_minlen) minlength = req_minlen; else minlength = 1; if (req_maxlen) maxlength = req_maxlen; else maxlength = cipher_limit; // the format's limit fuzz = 1; // "Fuzz factor", set to 0 for much quicker runs /* * This defines the keyboard layout, by default for a QWERTY keyboard. */ i = 0; while (i < 0x40) k[i++] = 0; k[0] = '`'; i = 0; while (++i <= 9) k[i] = '0' + i; k[10] = '0'; k[11] = '-'; k[12] = '='; k[0x11] = 'q'; k[0x12] = 'w'; k[0x13] = 'e'; k[0x14] = 'r'; k[0x15] = 't'; k[0x16] = 'y'; k[0x17] = 'u'; k[0x18] = 'i'; k[0x19] = 'o'; k[0x1a] = 'p'; k[0x1b] = '['; k[0x1c] = ']'; k[0x1d] = '\\'; k[0x21] = 'a'; k[0x22] = 's'; k[0x23] = 'd'; k[0x24] = 'f'; k[0x25] = 'g'; k[0x26] = 'h'; k[0x27] = 'j'; k[0x28] = 'k'; k[0x29] = 'l'; k[0x2a] = ';'; k[0x2b] = '\''; k[0x31] = 'z'; k[0x32] = 'x'; k[0x33] = 'c'; k[0x34] = 'v'; k[0x35] = 'b'; k[0x36] = 'n'; k[0x37] = 'm'; k[0x38] = ','; k[0x39] = '.'; k[0x3a] = '/'; i = 0; while (i < 0x100) mc[i++] = 0; fc = 0; /* rows */ c = 0; i = 0; while (i < 0x40) { p = c; c = k[i++] & 0xff; if (!c) continue; f[fc++] = c; if (!p) continue; m[(c << 3) + mc[c]++] = p; m[(p << 3) + mc[p]++] = c; } f[fc] = 0; /* columns */ i = 0; while (i < 0x30) { p = k[i++] & 0xff; if (!p) continue; j = 1 - fuzz; while (j <= 1 + fuzz) { c = k[i + 0x10 - j++] & 0xff; if (!c) continue; m[(c << 3) + mc[c]++] = p; m[(p << 3) + mc[p]++] = c; } } length = 0; while (length < minlength) id[length++] = 0; } void generate() { int i, p, maxcount; word[i = 0] = p = f[id[0]]; while (++i < length) word[i] = p = m[(p << 3) + id[i]]; word[i--] = 0; if (i) maxcount = mc[word[i - 1]]; else maxcount = fc; while (++id[i] >= maxcount) { if (!i) { if (length < maxlength) { id[0] = 0; id[length++] = 0; } return; } id[i--] = 0; if (i) maxcount = mc[word[i - 1]]; else maxcount = fc; } } void restore() { int i; /* Calculate the length */ length = 0; while (word[length]) id[length++] = 0; /* Infer the first character index */ i = -1; while (++i < fc) { if (f[i] == word[0]) { id[0] = i; break; } } /* This sample can be enhanced to infer the rest of the indices here */ } # Simplest (fastest?) possible dumb exhaustive search, demonstrating a # mode that does not need any special restore() handling. # Defaults to printable ASCII. [List.External:DumbDumb] int maxlength; // Maximum password length to try int startchar, endchar; // Range of characters (inclusive) void init() { int i; startchar = ' '; // Start with space endchar = '~'; // End with tilde // Create first word, honoring --min-len if (!(i = req_minlen)) i++; word[i] = 0; while (i--) word[i] = startchar; word[0] = startchar - 1; if (req_maxlen) maxlength = req_maxlen; // --max-len else maxlength = cipher_limit; // format's limit } void generate() { int i; if (++word <= endchar) return; i = 0; while (word[i] > endchar) { word[i++] = startchar; if (!word[i]) { word[i] = startchar; word[i + 1] = 0; } else word[i]++; } if (i >= maxlength) word = 0; } /* * This mode will resume correctly without any restore handing. * The empty function just confirms to John that everything is in order. */ void restore() { } # Generic implementation of "dumb" exhaustive search, given a range of lengths # and an arbitrary charset. This is pre-configured to try 8-bit characters # against LM hashes, which is only reasonable to do for very short password # half lengths. [List.External:DumbForce] int maxlength; // Maximum password length to try int last; // Last character position, zero-based int lastid; // Character index in the last position int id[0x7f]; // Current character indices for other positions int charset[0x100], c0; // Character set void init() { int minlength; int i, c; // Initial password length to try, must be at least 1 if (req_minlen) minlength = req_minlen; else minlength = 1; if (req_maxlen) maxlength = req_maxlen; else maxlength = cipher_limit; // the format's limit /* * This defines the character set. * * Let's say, we want to try TAB, all non-control ASCII characters, and all * 8-bit characters, including the 8-bit terminal controls range (as these are * used as regular national characters with some 8-bit encodings), but except * for known terminal controls (risky for the terminal we may be running on). * * Also, let's say our hashes are case-insensitive, so skip lowercase letters * (this is right for LM hashes). */ i = 0; charset[i++] = 9; // Add horizontal TAB (ASCII 9), then c = ' '; // start with space (ASCII 32) and while (c < 'a') // proceed till lowercase 'a' charset[i++] = c++; c = 'z' + 1; // Skip lowercase letters and while (c <= 0x7e) // proceed for all printable ASCII charset[i++] = c++; c++; // Skip DEL (ASCII 127) and while (c < 0x84) // proceed over 8-bit codes till IND charset[i++] = c++; charset[i++] = 0x86; // Skip IND (84 hex) and NEL (85 hex) charset[i++] = 0x87; c = 0x89; // Skip HTS (88 hex) while (c < 0x8d) // Proceed till RI (8D hex) charset[i++] = c++; c = 0x91; // Skip RI, SS2, SS3, DCS while (c < 0x96) // Proceed till SPA (96 hex) charset[i++] = c++; charset[i++] = 0x99; // Skip SPA, EPA, SOS c = 0xa0; // Skip DECID, CSI, ST, OSC, PM, APC while (c <= 0xff) // Proceed with the rest of 8-bit codes charset[i++] = c++; /* Zero-terminate it, and cache the first character */ charset[i] = 0; c0 = charset[0]; last = minlength - 1; i = 0; while (i <= last) { id[i] = 0; word[i++] = c0; } lastid = -1; word[i] = 0; } void generate() { int i; /* Handle the typical case specially */ if (word[last] = charset[++lastid]) return; lastid = 0; word[i = last] = c0; while (i--) { // Have a preceding position? if (word[i] = charset[++id[i]]) return; id[i] = 0; word[i] = c0; } if (++last < maxlength) { // Next length? id[last] = lastid = 0; word[last] = c0; word[last + 1] = 0; } else // We're done word = 0; } void restore() { int i, c; /* Calculate the current length and infer the character indices */ last = 0; while (c = word[last]) { i = 0; while (charset[i] != c && charset[i]) i++; if (!charset[i]) i = 0; // Not found id[last++] = i; } lastid = id[--last]; } # Generic implementation of exhaustive search for a partially-known password. # This is pre-configured for length 8, lowercase and uppercase letters in the # first 4 positions (52 different characters), and digits in the remaining 4 # positions - however, the corresponding part of init() may be modified to use # arbitrary character sets or even fixed characters for each position. [List.External:KnownForce] int last; // Last character position, zero-based int lastofs; // Last character position offset into charset[] int lastid; // Current character index in the last position int id[0x7f]; // Current character indices for other positions int charset[0x7f00]; // Character sets, 0x100 elements for each position void init() { int length, maxlength; int pos, ofs, i, c; if (req_minlen) length = req_minlen; else length = 8; // Password length to try (NOTE: other [eg. shorter] // lengths will not be tried!) if (req_maxlen) maxlength = req_maxlen; else maxlength = cipher_limit; // the format's limit /* This defines the character sets for different character positions */ if (length > maxlength) length = maxlength; pos = 0; while (pos < 4) { ofs = pos++ << 8; i = 0; c = 'a'; while (c <= 'z') charset[ofs + i++] = c++; c = 'A'; while (c <= 'Z') charset[ofs + i++] = c++; charset[ofs + i] = 0; } while (pos < length) { ofs = pos++ << 8; i = 0; c = '0'; while (c <= '9') charset[ofs + i++] = c++; charset[ofs + i] = 0; } last = length - 1; pos = -1; while (++pos <= last) word[pos] = charset[id[pos] = pos << 8]; lastid = (lastofs = last << 8) - 1; word[pos] = 0; } void generate() { int pos; /* Handle the typical case specially */ if (word[last] = charset[++lastid]) return; word[pos = last] = charset[lastid = lastofs]; while (pos--) { // Have a preceding position? if (word[pos] = charset[++id[pos]]) return; word[pos] = charset[id[pos] = pos << 8]; } word = 0; // We're done } void restore() { int i, c; /* Calculate the current length and infer the character indices */ last = 0; while (c = word[last]) { i = lastofs = last << 8; while (charset[i] != c && charset[i]) i++; if (!charset[i]) i = lastofs; // Not found id[last++] = i; } lastid = id[--last]; } # A variation of KnownForce configured to try likely date and time strings. [List.External:DateTime] int last; // Last character position, zero-based int lastofs; // Last character position offset into charset[] int lastid; // Current character index in the last position int id[0x7f]; // Current character indices for other positions int charset[0x7f00]; // Character sets, 0x100 elements for each position void init() { int length; int pos, ofs, i, c; length = 8; // Must be one of: 4, 5, 7, 8 /* This defines the character sets for different character positions */ pos = 0; while (pos < length - 6) { ofs = pos++ << 8; i = 0; c = '0'; while (c <= '9') charset[ofs + i++] = c++; charset[ofs + i] = 0; } if (pos) { ofs = pos++ << 8; charset[ofs] = '/'; charset[ofs + 1] = '.'; charset[ofs + 2] = ':'; charset[ofs + 3] = 0; } while (pos < length - 3) { ofs = pos++ << 8; i = 0; c = '0'; while (c <= '9') charset[ofs + i++] = c++; charset[ofs + i] = 0; } ofs = pos++ << 8; charset[ofs] = '/'; charset[ofs + 1] = '.'; charset[ofs + 2] = ':'; charset[ofs + 3] = 0; while (pos < length) { ofs = pos++ << 8; i = 0; c = '0'; while (c <= '9') charset[ofs + i++] = c++; charset[ofs + i] = 0; } last = length - 1; pos = -1; while (++pos <= last) word[pos] = charset[id[pos] = pos << 8]; lastid = (lastofs = last << 8) - 1; word[pos] = 0; } void generate() { int pos; /* Handle the typical case specially */ if (word[last] = charset[++lastid]) return; word[pos = last] = charset[lastid = lastofs]; while (pos--) { // Have a preceding position? if (word[pos] = charset[++id[pos]]) return; word[pos] = charset[id[pos] = pos << 8]; } word = 0; // We're done } void restore() { int i, c; /* Calculate the current length and infer the character indices */ last = 0; while (c = word[last]) { i = lastofs = last << 8; while (charset[i] != c && charset[i]) i++; if (!charset[i]) i = lastofs; // Not found id[last++] = i; } lastid = id[--last]; } # A variation of KnownForce configured to try all the 385641000 possible # auto-generated passwords of DokuWiki versions up to at least 2013-05-10. [List.External:DokuWiki] int last; // Last character position, zero-based int lastofs; // Last character position offset into charset[] int lastid; // Current character index in the last position int id[0x7f]; // Current character indices for other positions int charset[0x7f00]; // Character sets, 0x100 elements for each position void init() { int A[26], C[26], V[26]; int length; int pos, ofs, i, c; i = 0; while (i < 26) { A[i] = C[i] = 1; V[i++] = 0; } i = 'a' - 'a'; C[i] = 0; V[i] = 1; i = 'e' - 'a'; C[i] = 0; V[i] = 1; i = 'i' - 'a'; C[i] = 0; V[i] = 1; i = 'o' - 'a'; C[i] = 0; V[i] = 1; i = 'u' - 'a'; C[i] = 0; V[i] = 1; i = 'q' - 'a'; A[i] = C[i] = 0; i = 'x' - 'a'; A[i] = C[i] = 0; i = 'y' - 'a'; A[i] = C[i] = 0; length = 8; /* This defines the character sets for different character positions */ pos = 0; while (pos < 6) { ofs = pos++ << 8; i = 0; c = 'a' - 1; while (++c <= 'z') if (C[c - 'a']) charset[ofs + i++] = c; charset[ofs + i] = 0; ofs = pos++ << 8; i = 0; c = 'a' - 1; while (++c <= 'z') if (V[c - 'a']) charset[ofs + i++] = c; charset[ofs + i] = 0; ofs = pos++ << 8; i = 0; c = 'a' - 1; while (++c <= 'z') if (A[c - 'a']) charset[ofs + i++] = c; charset[ofs + i] = 0; } c = '1'; while (pos < length) { ofs = pos++ << 8; i = 0; while (c <= '9') charset[ofs + i++] = c++; charset[ofs + i] = 0; c = '0'; } last = length - 1; pos = -1; while (++pos <= last) word[pos] = charset[id[pos] = pos << 8]; lastid = (lastofs = last << 8) - 1; word[pos] = 0; } void generate() { int pos; /* Handle the typical case specially */ if (word[last] = charset[++lastid]) return; word[pos = last] = charset[lastid = lastofs]; while (pos--) { // Have a preceding position? if (word[pos] = charset[++id[pos]]) return; word[pos] = charset[id[pos] = pos << 8]; } word = 0; // We're done } void restore() { int i, c; /* Calculate the current length and infer the character indices */ last = 0; while (c = word[last]) { i = lastofs = last << 8; while (charset[i] != c && charset[i]) i++; if (!charset[i]) i = lastofs; // Not found id[last++] = i; } lastid = id[--last]; } # Strip 0.5 ("Secure Tool for Recalling Important Passwords") cracker, # based on analysis done by Thomas Roessler and Ian Goldberg. This will # crack passwords you may have generated with Strip; other uses of Strip # are unaffected. [List.External:Strip] int minlength, maxlength, mintype, maxtype; int crack_seed, length, type; int count, charset[128]; void init() { int c; /* Password lengths to try; Strip can generate passwords of 4 to 16 * characters, but traditional crypt(3) hashes are limited to 8. */ minlength = req_minlen; if (minlength < 4) minlength = 4; if (req_maxlen) maxlength = req_maxlen; else // the format's limit maxlength = cipher_limit; if (maxlength >16) maxlength = 16; /* Password types to try (Numeric, Alpha-Num, Alpha-Num w/ Meta). */ mintype = 0; // 0 maxtype = 2; // 2 crack_seed = 0x10000; length = minlength - 1; type = mintype; count = 0; c = '0'; while (c <= '9') charset[count++] = c++; } void generate() { int seed, random; int i, c; if (crack_seed > 0xffff) { crack_seed = 0; if (++length > maxlength) { length = minlength; if (++type > maxtype) { word[0] = 0; return; } } count = 10; if (type >= 1) { c = 'a'; while (c <= 'f') charset[count++] = c++; c = 'h'; while (c <= 'z') charset[count++] = c++; c = 'A'; while (c <= 'Z') charset[count++] = c++; } if (type == 2) { charset[count++] = '!'; c = '#'; while (c <= '&') charset[count++] = c++; c = '('; while (c <= '/') charset[count++] = c++; c = '<'; while (c <= '>') charset[count++] = c++; charset[count++] = '?'; charset[count++] = '@'; charset[count++] = '['; charset[count++] = ']'; charset[count++] = '^'; charset[count++] = '_'; c = '{'; while (c <= '~') charset[count++] = c++; } } seed = (crack_seed++ << 16 >> 16) * 22695477 + 1; i = 0; while (i < length) { random = ((seed = seed * 22695477 + 1) >> 16) & 0x7fff; word[i++] = charset[random % count]; } word[i] = 0; } /* * This takes advantage of CVE-2013-2120 to find seeds that KDE Paste applet * uses to generate passwords. * * This software is Copyright (c) Michael Samuel , * and it is hereby released to the general public under the following terms: * Redistribution and use in source and binary forms, with or without * modification, are permitted. */ [List.External:KDEPaste] int charset[95]; int charset_length, password_length, endTime, startTime, msec; void init() { password_length = 8; /* Change this to match config */ endTime = session_start_time; startTime = 1343743200; /* Aug 1 2012 - Change this as necessary */ msec = 1; /* msec is never 0 - it would crash the applet */ charset_length = 0; int c; /* Comment out classes that you don't need, but keep the order the same */ /* Lowers */ c = 'a'; while (c <= 'z') charset[charset_length++] = c++; /* Uppers */ c = 'A'; while (c <= 'Z') charset[charset_length++] = c++; /* Numbers */ c = '0'; while (c <= '9') charset[charset_length++] = c++; charset[charset_length++] = '0'; /* Yep, it's there twice */ /* Symbols */ c = '!'; while (c <= '/') charset[charset_length++] = c++; c = ':'; while (c <= '@') charset[charset_length++] = c++; c = '['; while (c <= '`') charset[charset_length++] = c++; c = '{'; while (c <= '~') charset[charset_length++] = c++; } void generate() { int i, rand_seed, rand_result; /* Terminate once we've generated for all * * of the time range (Plus a bit more...) */ if (endTime + 1000 < startTime) { word = 0; return; } /* Skip msecs that would generate dupes */ while (endTime % msec != 0) { if (++msec > 999) { endTime--; msec = 1; } } rand_seed = endTime / msec; i = 0; while (i < password_length) { /* this works like rand_r() from eglibc */ rand_seed = rand_seed * 1103515245 + 12345; rand_result = (rand_seed >> 16) & 2047; rand_seed = rand_seed * 1103515245 + 12345; rand_result <<= 10; rand_result ^= (rand_seed >> 16) & 1023; rand_seed = rand_seed * 1103515245 + 12345; rand_result <<= 10; rand_result ^= (rand_seed >> 16) & 1023; word[i++] = charset[rand_result % charset_length]; } word[i] = 0; if (++msec > 999) { endTime--; msec = 1; } } void restore() { int i, rand_seed, rand_result; i = 0; /* Very crude restore, just dry-run until we hit last word */ while (i != password_length) { while (endTime % msec != 0) { if (++msec > 999) { endTime--; msec = 1; } } rand_seed = endTime / msec; i = 0; while (i < password_length) { /* this works like rand_r() from eglibc */ rand_seed = rand_seed * 1103515245 + 12345; rand_result = (rand_seed >> 16) & 2047; rand_seed = rand_seed * 1103515245 + 12345; rand_result <<= 10; rand_result ^= (rand_seed >> 16) & 1023; rand_seed = rand_seed * 1103515245 + 12345; rand_result <<= 10; rand_result ^= (rand_seed >> 16) & 1023; if (charset[rand_result % charset_length] != word[i++]) break; } if (++msec > 999) { endTime--; msec = 1; } } } /* Awesome Password Generator RNG replay * Written by Michael Samuel * Public Domain. * * This takes advantage of a subtle bug, where a crypto RNG is used to * seed the C# System.Random() class, which takes a 32-bit input, but * converts negative numbers into non-negative numbers, resulting in * only 31 bits of security. * * This only implements "easy to type" being *unticked*, and numbers, * lowers, uppers and symbols being ticked, in random password mode. * Changing the password length is easy, anything else is left as an * exercise to the reader. * * Running Awesome Password Generator (1.3.2 or lower) in Mono is still * vulnerable, but uses a different RNG, so this mode isn't compatible. */ /* Awesome Password Generator 1.3.2 does a two-pass run, selecting which * charset each position will have, then picking the character. This * leads to heavy bias, and is fixed in 1.4.0 (along with many other * fixes). If you have been using Awesome Password Generator, you should * upgrade immediately and change your passwords. */ [List.External:AwesomePasswordGenerator] int numbers[10]; int lowers[26]; int uppers[26]; int symbols[32]; /* Since we don't have a double datatype, I simply pre-calculated the * transition numbers calculating the scale formula: * (double)randNum * 4.656612873077393e-10 * {4/10/26/32} */ int boundaries_charclass[4]; int boundaries_numbers[10]; int boundaries_letters[26]; int boundaries_symbols[32]; /* This is the bug we're exploiting - the seed for the RNG is 32 bits * from the crypto rng. The non-crypto RNG converts negative numbers * into non-negative numbers, so there's only 2^31 possible seeds. */ int seed; int password_length; void init() { password_length = 16; /* Change this to match config */ int c, i; c = '0'; i = 0; while (c <= '9') numbers[i++] = c++; c = 'a'; i = 0; while (c <= 'z') lowers[i++] = c++; c = 'A'; i = 0; while (c <= 'Z') uppers[i++] = c++; /* Symbols */ i = 0; symbols[i++] = '!'; symbols[i++] = '@'; symbols[i++] = '#'; symbols[i++] = '$'; symbols[i++] = '%'; symbols[i++] = '^'; symbols[i++] = '&'; symbols[i++] = '*'; symbols[i++] = '('; symbols[i++] = ')'; symbols[i++] = '~'; symbols[i++] = '-'; symbols[i++] = '_'; symbols[i++] = '='; symbols[i++] = '+'; symbols[i++] = '\\'; symbols[i++] = '|'; symbols[i++] = '/'; symbols[i++] = '['; symbols[i++] = ']'; symbols[i++] = '{'; symbols[i++] = '}'; symbols[i++] = ';'; symbols[i++] = ':'; symbols[i++] = '`'; symbols[i++] = '\''; symbols[i++] = '"'; symbols[i++] = ','; symbols[i++] = '.'; symbols[i++] = '<'; symbols[i++] = '>'; symbols[i++] = '?'; i = 0; boundaries_charclass[i++] = 536870912; boundaries_charclass[i++] = 1073741824; boundaries_charclass[i++] = 1610612736; boundaries_charclass[i++] = 2147483647; i = 0; boundaries_numbers[i++] = 214748365; boundaries_numbers[i++] = 429496730; boundaries_numbers[i++] = 644245095; boundaries_numbers[i++] = 858993460; boundaries_numbers[i++] = 1073741824; boundaries_numbers[i++] = 1288490189; boundaries_numbers[i++] = 1503238554; boundaries_numbers[i++] = 1717986919; boundaries_numbers[i++] = 1932735284; boundaries_numbers[i++] = 2147483647; i = 0; boundaries_letters[i++] = 82595525; boundaries_letters[i++] = 165191050; boundaries_letters[i++] = 247786575; boundaries_letters[i++] = 330382100; boundaries_letters[i++] = 412977625; boundaries_letters[i++] = 495573150; boundaries_letters[i++] = 578168675; boundaries_letters[i++] = 660764200; boundaries_letters[i++] = 743359725; boundaries_letters[i++] = 825955250; boundaries_letters[i++] = 908550775; boundaries_letters[i++] = 991146300; boundaries_letters[i++] = 1073741824; boundaries_letters[i++] = 1156337349; boundaries_letters[i++] = 1238932874; boundaries_letters[i++] = 1321528399; boundaries_letters[i++] = 1404123924; boundaries_letters[i++] = 1486719449; boundaries_letters[i++] = 1569314974; boundaries_letters[i++] = 1651910499; boundaries_letters[i++] = 1734506024; boundaries_letters[i++] = 1817101549; boundaries_letters[i++] = 1899697074; boundaries_letters[i++] = 1982292599; boundaries_letters[i++] = 2064888124; boundaries_letters[i++] = 2147483647; i = 0; boundaries_symbols[i++] = 67108864; boundaries_symbols[i++] = 134217728; boundaries_symbols[i++] = 201326592; boundaries_symbols[i++] = 268435456; boundaries_symbols[i++] = 335544320; boundaries_symbols[i++] = 402653184; boundaries_symbols[i++] = 469762048; boundaries_symbols[i++] = 536870912; boundaries_symbols[i++] = 603979776; boundaries_symbols[i++] = 671088640; boundaries_symbols[i++] = 738197504; boundaries_symbols[i++] = 805306368; boundaries_symbols[i++] = 872415232; boundaries_symbols[i++] = 939524096; boundaries_symbols[i++] = 1006632960; boundaries_symbols[i++] = 1073741824; boundaries_symbols[i++] = 1140850688; boundaries_symbols[i++] = 1207959552; boundaries_symbols[i++] = 1275068416; boundaries_symbols[i++] = 1342177280; boundaries_symbols[i++] = 1409286144; boundaries_symbols[i++] = 1476395008; boundaries_symbols[i++] = 1543503872; boundaries_symbols[i++] = 1610612736; boundaries_symbols[i++] = 1677721600; boundaries_symbols[i++] = 1744830464; boundaries_symbols[i++] = 1811939328; boundaries_symbols[i++] = 1879048192; boundaries_symbols[i++] = 1946157056; boundaries_symbols[i++] = 2013265920; boundaries_symbols[i++] = 2080374784; boundaries_symbols[i++] = 2147483647; seed = 0; } void generate() { int i, j, s, next, nextp, val, bucket, randnum, used_charsets; int seedarray[56]; /* BEGIN System.Random(seed) */ if(seed < 0) { /* Only bother with non-negative integers */ word = 0; return; } s = 161803398 - seed++; seedarray[55] = s; i = val = 1; while(i < 55) { bucket = 21 * i % 55; seedarray[bucket] = val; val = s - val; if(val < 0) val += 2147483647; s = seedarray[bucket]; i++; } i = 1; while(i < 5) { j = 1; while(j < 56) { seedarray[j] -= seedarray[1 + (j + 30) % 55]; if(seedarray[j] < 0) seedarray[j] += 2147483647; j++; } i++; } next = 0; nextp = 21; /* END System.Random(seed) */ used_charsets = 0; while(used_charsets != 15) { i = 0; while(i < password_length) { /* BEGIN Random.Sample() */ if (++next >= 56) next = 1; if (++nextp >= 56) nextp = 1; randnum = seedarray[next] - seedarray[nextp]; if (randnum == 2147483647) randnum--; if (randnum < 0) randnum += 2147483647; seedarray[next] = randnum; /* END Random.Sample() */ j = 0; while(boundaries_charclass[j] < randnum) j++; word[i] = j; /* Temporarily store in word[] */ used_charsets |= (1 << j); i++; } } i = 0; while(i < password_length) { /* BEGIN Random.Sample() */ if (++next >= 56) next = 1; if (++nextp >= 56) nextp = 1; randnum = seedarray[next] - seedarray[nextp]; if (randnum == 2147483647) randnum--; if (randnum < 0) randnum += 2147483647; seedarray[next] = randnum; /* END Random.Sample() */ j = 0; if(word[i] == 0) { while(boundaries_letters[j] < randnum) j++; word[i++] = lowers[j]; } else if (word[i] == 1) { while(boundaries_letters[j] < randnum) j++; word[i++] = uppers[j]; } else if (word[i] == 2) { while(boundaries_numbers[j] < randnum) j++; word[i++] = numbers[j]; } else { /* if (word[i] == 3) */ while(boundaries_symbols[j] < randnum) j++; word[i++] = symbols[j]; } } word[i] = 0; } void restore() { int i, j, s, next, nextp, val, bucket, randnum, used_charsets; int seedarray[56]; int candidate[32]; /* This needs to be at-least as big as password-length */ seed = 0; while(seed > 0) { /* BEGIN System.Random(seed) */ s = 161803398 - seed++; seedarray[55] = s; i = val = 1; while(i < 55) { bucket = 21 * i % 55; seedarray[bucket] = val; val = s - val; if(val < 0) val += 2147483647; s = seedarray[bucket]; i++; } i = 1; while(i < 5) { j = 1; while(j < 56) { seedarray[j] -= seedarray[1 + (j + 30) % 55]; if(seedarray[j] < 0) seedarray[j] += 2147483647; j++; } i++; } next = 0; nextp = 21; /* END System.Random(seed) */ used_charsets = 0; while(used_charsets != 15) { i = 0; while(i < password_length) { /* BEGIN Random.Sample() */ if (++next >= 56) next = 1; if (++nextp >= 56) nextp = 1; randnum = seedarray[next] - seedarray[nextp]; if (randnum == 2147483647) randnum--; if (randnum < 0) randnum += 2147483647; seedarray[next] = randnum; /* END Random.Sample() */ j = 0; while(boundaries_charclass[j] < randnum) j++; candidate[i] = j; used_charsets |= (1 << j); i++; } } i = 0; while(i < password_length) { /* BEGIN Random.Sample() */ if (++next >= 56) next = 1; if (++nextp >= 56) nextp = 1; randnum = seedarray[next] - seedarray[nextp]; if (randnum == 2147483647) randnum--; if (randnum < 0) randnum += 2147483647; seedarray[next] = randnum; /* END Random.Sample() */ j = 0; if(candidate[i] == 0) { while(boundaries_letters[j] < randnum) j++; if(lowers[j] != word[i++]) break; } else if (candidate[i] == 1) { while(boundaries_letters[j] < randnum) j++; if(uppers[j] != word[i++]) break; } else if (candidate[i] == 2) { while(boundaries_numbers[j] < randnum) j++; if(numbers[j] != word[i++]) break; } else { /* if (word[i] == 3) */ while(boundaries_symbols[j] < randnum) j++; if(symbols[j] != word[i++]) break; } } if(i == password_length) return; } } # Append the Luhn algorithm digit to arbitrary all-digit strings. Optimized # for speed, not for size nor simplicity. The primary optimization trick is to # compute the length and four sums in parallel (in two SIMD'ish variables). # Then whether the length is even or odd determines which two of the four sums # are actually used. Checks for non-digits and for NUL are packed into the # SIMD'ish bitmasks as well. [List.External:AppendLuhn] int map1[0x100], map2[0x1fff]; void init() { int i; map1[0] = ~0x7fffffff; i = 1; while (i < 0x100) map1[i++] = ~0x7effffff; i = -1; while (++i < 10) map1['0' + i] = i + ((i * 2 % 10 + i / 5) << 12); i = -1; while (++i < 0x1fff) { if (i % 10) map2[i] = '9' + 1 - i % 10; else map2[i] = '0'; } } void filter() { int i, o, e; i = o = e = 0; while ((o += map1[word[i++]]) >= 0) { if ((e += map1[word[i++]]) >= 0) continue; if (e & 0x01000000) return; // Not all-digit, leave unmodified word[i--] = 0; word[i] = map2[(e & 0xfff) + (o >> 12)]; return; } if (o & 0x01000000) return; // Not all-digit, leave unmodified word[i--] = 0; word[i] = map2[(o & 0xfff) + (e >> 12)]; } # Simple password policy matching: require at least one digit. [List.External:AtLeast1-Simple] void filter() { int i, c; i = 0; while (c = word[i++]) if (c >= '0' && c <= '9') return; // Found at least one suitable character, good word = 0; // No suitable characters found, skip this "word" } # The same password policy implemented in a more efficient and more generic # fashion (easy to expand to include other "sufficient" characters as well). [List.External:AtLeast1-Generic] int mask[0x100]; void init() { int c; mask[0] = 0; // Terminate the loop in filter() on NUL c = 1; while (c < 0x100) mask[c++] = 1; // Continue looping in filter() on most chars c = '0'; while (c <= '9') mask[c++] = 0; // Terminate the loop in filter() on digits } void filter() { int i; i = -1; while (mask[word[++i]]) continue; if (word[i]) return; // Found at least one suitable character, good word = 0; // No suitable characters found, skip this "word" } # An efficient and fairly generic password policy matcher. The policy to match # is specified in the check at the end of filter() and in mask[]. For example, # lowercase and uppercase letters may be treated the same by initializing the # corresponding mask[] elements to the same value, then adjusting the value to # check "seen" for accordingly. [List.External:Policy] int mask[0x100]; void init() { int c; mask[0] = 0x100; c = 1; while (c < 0x100) mask[c++] = 0x200; c = 'a'; while (c <= 'z') mask[c++] = 1; c = 'A'; while (c <= 'Z') mask[c++] = 2; c = '0'; while (c <= '9') mask[c++] = 4; } void filter() { int i, seen; /* * This loop ends when we see NUL (sets 0x100) or a disallowed character * (sets 0x200). */ i = -1; seen = 0; while ((seen |= mask[word[++i]]) < 0x100) continue; /* * We should have seen at least one character of each type (which "add up" * to 7) and then a NUL (adds 0x100), but not any other characters (would * add 0x200). The length must be 8. */ if (seen != 0x107 || i != 8) word = 0; // Does not conform to policy } # Trivial Rotate function, which rotates letters in a word # by a given number of places (like 13 in case of ROT13). # Words which don't contain any letters (and thus wouldn't be changed # by this filter) are skipped, because these unchanged words probably # should have been tried before trying a mangled version. [List.External_base:Filter_Rotate] int rot; // The number of places to rotate each letter in a word void filter() { int i, j, c; i = 0; j = 0; // j counts the number of changed characters while (c = word[i]) { if (c >= 'a' && c <= 'z') { c = c - 26 + rot; if (c < 'a') c += 26; word[i] = c; j++; } else if (c >= 'A' && c <= 'Z' ) { c = c - 26 + rot; if (c < 'A') c += 26; word[i] = c; j++; } i++; } if (j == 0) // Nothing changed. Reject this word. word = 0; } # ROT13 Example [List.External:Filter_ROT13] .include [List.External_base:Filter_Rotate] void init() { // Just in case someone wants to "rotate" by other values, // adjust the value of the rot variable // (may be in a copied external mode): // 13: "abcABCxyzXYZ" -> "nopNOPklmKLM" // 1: "abcABCxyzXYZ" -> "bcdBCDyzaYZA" // 25: "abcABCxyzXYZ" -> "zabZABwxyWXY" // -1: "abcABCxyzXYZ" -> "zabZABwxyWXY" // and so on // Allowed range: -25 <= rot <= -1, or 1 <= rot <= 25 rot = 13; // Don't change the following statement. // It is supposed to "sanitize" the value to be in the // range rot = (rot + 26) % 26; } # Trivial parallel processing example (obsoleted by the "--node" option) [List.External:Parallel] /* * This word filter makes John process some of the words only, for running * multiple instances on different CPUs. It can be used with any cracking * mode except for "single crack". Note: this is not a good solution, but * is just an example of what can be done with word filters. */ int node, total; // This node's number, and node count int number; // Current word number void init() { node = 1; total = 2; // Node 1 of 2, change as appropriate number = node - 1; // Speedup the filter a bit } void filter() { if (number++ % total) // Word for a different node? word = 0; // Yes, skip it } # Interrupt the cracking session after "max" words tried [List.External:AutoAbort] int max; // Maximum number of words to try int number; // Current word number void init() { max = 1000; number = 0; } void filter() { if (++number > max) abort = 1; // Interrupt the cracking session } # Print the status line after every "interval" words tried [List.External:AutoStatus] int interval; // How often to print the status int number; // Current word number void init() { interval = 1000; number = 0; } void filter() { if (number++ % interval) return; status = 1; // Print the status line } # # Reference example hybrid-mode external. same as jtr-rule: $[0-9]$[0-9] # this format is to be used similar to a filter, in that it requires some # other word generator (markov, wordlist, etc). However, this type external # will get new() called with each word, and then have next() called, until # the word[0]=0 is seen (meaning all candidates for the base word have been # generated. Prior to new() or restore(), word[] is the 'base' word. # if the script is able to properly resume, then it should set the global # variable hybrid_total to the count of candidates that will be generated # for this word (in new() / restore(), then in the body of restore() there # is a global variable set 'hybrid_resume' that was the prior number of # canidates generated for this base-word. Resume should start at the NEXT # If the script is not able to easily resume, then simply do NOT set the # global hybrid_total to anything either function. JtR will 'still' resume # propery, but it will do so by calling new()/next()/next().../next() until # back to the proper resume location. # # script changed to append a _ character before the number, each time within # the next() function. Done this way to better validate that -restore within # jtr is working properly. # [List.External:Hybrid_example] /* static vars for the script */ int cnt, length, total; void init() { /* in this simple example, we always generate 100 candidates per word */ total = 100;/* this is a VERY simple example */ } /* new word */ void new() { /* get the word length) */ length = 0; while (word[length++]) ; --length; /* * If this was a more complex script, we would compute total candidates * at this location, if we can. If we can not compute total candidates * then it is likely we can not resume 'easily', so if that is the * case, we would simply set hybrid_total to -1, or do nothing, since * do_external_hybrid_crack() sets it to -1 before calling this function. */ hybrid_total = total; /* Reset or counter for THIS word. */ cnt = 0; /* * word will be too long to be used, or too short to be used. If so * then set hybrid_total to 0 and this entire word will be skipped. */ if (req_minlen > length - 2 || (req_maxlen && req_maxlen < length + 2)) hybrid_total = 0; } void next() { /* in this simple script, if cnt is 100, this word is DONE */ if (cnt == 100) { word[0] = 0; return; } /* set word[] to the next candidate */ word[length++] = '_'; word[length ] = '0' + cnt / 10; word[length+1] = '0' + cnt % 10; word[length+2] = 0; ++cnt; } /* Called when restoring an interrupted session */ void restore() { int i; length = 0; while (word[length++]) ; --length; /* for this simple script, simply setting cnt resumes */ cnt = hybrid_resume + 1; if (cnt > 100) cnt=100; i = 0; while (i++ < cnt) word[length++] = '_'; word[length] = 0; /* tell john that we have properly 'resumed', by setting a 'proper' total */ hybrid_total = total; } # External hybrid 'leet code [List.External:Leet] /* * 1337 language in this script: * a -> a4@ * b -> b8 * e -> e3 * g -> g9 * i -> i1! * l -> l1 * o -> o0 * s -> s$5 * t -> t7 */ int rotor[626]; /* max length input is 125 bytes [125*5+1]; */ int rotors[125]; int rotor_ptr[125]; int rotor_idx[125]; int rotor_cnt[125]; int current_word_count; int max_mangle; /* controls how many bytes we run through our 'leet' code */ int max_mangle_letters; int original_word; /* if set to 1 then we start with original word. If 0, then start with first mangled word */ void init() { /* note, 3^10 is 59k so aaaaaaaaaa will produce that many words! */ max_mangle_letters = 10; /* only mangle 10 characters max */ max_mangle = 4000; /* Stop building new letters if our count goes over this value */ original_word = 0; } /* new word */ void new() { int rotor_off, idx, wlen; idx = rotor_off = wlen = 0; hybrid_total = 1; while (word[wlen++]) ; --wlen; if (req_minlen > wlen || (req_maxlen && req_maxlen < wlen )) { hybrid_total = 0; return; } wlen = 0; while (word[wlen] && idx < max_mangle_letters && hybrid_total < max_mangle) { rotor_cnt[wlen] = rotor_idx[wlen] = 0; rotor_ptr[wlen] = rotor_off; if (word[wlen] == 'a') { rotor[rotor_off++] = 'a'; rotor[rotor_off++] = '4'; rotor[rotor_off++] = '@'; } else if (word[wlen] == 'b') { rotor[rotor_off++] = 'b'; rotor[rotor_off++] = '8'; } else if (word[wlen] == 'e') { rotor[rotor_off++] = 'e'; rotor[rotor_off++] = '3'; } else if (word[wlen] == 'g') { rotor[rotor_off++] = 'g'; rotor[rotor_off++] = '9'; } else if (word[wlen] == 'i') { rotor[rotor_off++] = 'i'; rotor[rotor_off++] = '1'; rotor[rotor_off++] = '!'; } else if (word[wlen] == 'l') { rotor[rotor_off++] = 'l'; rotor[rotor_off++] = '1'; } else if (word[wlen] == 'o') { rotor[rotor_off++] = 'o'; rotor[rotor_off++] = '0'; } else if (word[wlen] == 's') { rotor[rotor_off++] = 's'; rotor[rotor_off++] = '$'; rotor[rotor_off++] = '5'; } else if (word[wlen] == 't') { rotor[rotor_off++] = 't'; rotor[rotor_off++] = '7'; } if (rotor_off > rotor_ptr[wlen]) { rotor_cnt[wlen] = rotor_off-rotor_ptr[wlen]; hybrid_total *= rotor_cnt[wlen]; rotors[idx++] = wlen; } ++wlen; } /* hybrid_total+666 is our indicator that this is the original word */ if (original_word) current_word_count = hybrid_total+666; else { current_word_count = 1; /* skip the 'original' word */ } } /* next iteration of this word word */ void next() { int idx, idx2; if (current_word_count >= hybrid_total) { if (current_word_count == hybrid_total+666) { /* first word (starting word) we leave alone */ /* by making it > hybrid_total, we avoid a 2nd if statement */ current_word_count = 1; return; } word[0] = 0; return; } idx = rotors[idx2=0]; while (++rotor_idx[idx] >= rotor_cnt[idx]) { rotor_idx[idx] = 0; word[idx] = rotor[ rotor_ptr[idx] ]; idx = rotors[++idx2]; } word[idx] = rotor[ rotor_ptr[idx]+rotor_idx[idx] ]; ++current_word_count; } /* restore() not needed. john properly restores fast enough without it */ # External hybrid CaSE mutation code [List.External:Case] int rotor[251]; /* max length input is 125 bytes [125*5+1]; */ int rotors[125]; int rotor_ptr[125]; int rotor_idx[125]; int rotor_cnt[125]; int current_word_count; int max_mangle; /* controls how many bytes we run through our 'leet' code */ int original_word; /* if set to 1 then we start with original word. If 0, then start with first mangled word */ void init() { max_mangle = 20; /* only mangle 20 characters max (2^20 is 1 million) */ original_word = 1; /* for case mangle, unless the data is 100% lower case, we really can not skip the original word */ } /* new word */ void new() { int rotor_off, idx, wlen, ch; idx = rotor_off = wlen = 0; hybrid_total = 1; while (word[wlen++]) ; --wlen; if (req_minlen > wlen || (req_maxlen && req_maxlen < wlen )) { hybrid_total = 0; return; } wlen = 0; while (word[wlen] && idx < max_mangle) { rotor_cnt[wlen] = rotor_idx[wlen] = 0; rotor_ptr[wlen] = rotor_off; ch = word[wlen]; if (ch >= 'A' && ch <= 'Z') { ch += 0x20; word[wlen] = ch; rotor[rotor_off++] = ch; rotor[rotor_off++] = ch-0x20; } if (ch >= 'a' && ch <= 'z') { rotor[rotor_off++] = ch; rotor[rotor_off++] = ch-0x20; rotor_cnt[wlen] = 2; hybrid_total *= 2; rotors[idx++] = wlen; } ++wlen; } /* hybrid_total+666 is our indicator that this is the original word */ if (original_word) current_word_count = hybrid_total+666; else { current_word_count = 1; /* skip the 'original' word */ } } /* next iteration of this word word */ void next() { int idx, idx2; if (current_word_count >= hybrid_total) { if (current_word_count == hybrid_total+666) { /* first word (starting word) we leave alone */ /* by making it > hybrid_total, we avoid a 2nd if statement */ current_word_count = 1; return; } word[0] = 0; return; } idx = rotors[idx2=0]; while (++rotor_idx[idx] >= rotor_cnt[idx]) { rotor_idx[idx] = 0; word[idx] = rotor[ rotor_ptr[idx] ]; idx = rotors[++idx2]; } word[idx] = rotor[ rotor_ptr[idx]+rotor_idx[idx] ]; ++current_word_count; } /* restore() not needed. john properly restores fast enough without it */ # Alternate hybrid external 'leet' mode (HybridLeet) .include # dumb-force UTF-16, in an external file .include # dumb-force UTF-32, in an external file .include # repeats UTF-16, in an external file .include # repeats UTF-32, in an external file .include # Dynamic ($dynamic_n$) scripting code, in an external file .include # Regex alphabets .include # NOTE, this file (john.local.conf) is deprecated. If you had any modified logic in this # file, please create and move it to john-local.conf. The file simply can be renamed to # the new john-local.conf if you so choose. .include '$JOHN/john.local.conf' # include john-local.conf (This file can be created by user, to override defaults in this john.conf file) .include '$JOHN/john-local.conf' # include john-local.conf in local dir, it can override john.conf, john-local.conf (or any other conf file loaded) .include './john-local.conf' # End of john.conf file. # Keep this comment, and blank line above it, to make sure a john-local.conf # that does not end with \n is properly loaded.