
If you're concerned with IT security, you can't miss the OWASP Top 10. The non-profit organization Open Web Application Security
The first two articles in our password cracking series have covered the basics of password cracking and some cool tricks. The approaches shown are important for understanding, but so far they have been rather theoretical.
Now we confront the lessons learned with reality and demonstrate their practical applicability: In this article, we present two cases in which we successfully performed password cracking in real pentests.
The two case studies discussed here have some things in common: In both cases, the companies tested were working with classic Active Directory. In each case, our pentesters took over the DC and then downloaded the NTDS.dit using DC Sync.
Company A is a larger company that did not have any password policy in place. Company B is a medium-sized company with different password policies for administrators and users. The respective password policies were configured in a reasonable way.
It is probably not surprising that we were able to recover about 80% of the passwords at company A after a short time by password cracking. But we were also able to recover about 60% of the passwords (of users and administrators) at company B. How was this possible?
Company A had no password policy and the minimum length of 8 characters made password cracking very easy. In addition, some passwords were not set at all or were used multiple times. These conditions explain the high success rate in recovering the passwords.
Company B's password policy looks very secure at first glance: It forced passwords to be updated after 30 days, stored a history of 24 previous passwords, and required three out of 4 complexity features. However, the admin network still allowed LM hashes for password storage. The minimum length for passwords was 14 characters. Thus, Company B had fully complied with the old requirements of "NIST Special Publication 800 - 63. Appendix A."
Sounds really safe, doesn't it?
In reality, well-intentioned password policies unfortunately often lead to insecure passwords.
In the following sections, we take a closer look at the individual requirements and show where the weaknesses of Company B's policy lie. (Spoiler Alert: The biggest weakness is usually people).
Complexity requirements should, in theory, make cracking passwords more difficult by increasing possible character combinations. In practice, however, users often fulfill the requirements by using typical schemes and thus, on the contrary, facilitate cracking:
Capitalized first letters, followed by lowercase letters, and then numbers or special characters. Do your "secure" passwords look like this by any chance?
With knowledge of such patterns, masks, rules, and dictionaries can be created that target just such patterns.
Example:
example.local\user:Straßenbahn01#
example.local\user:Neuseeland1997!
example.local\user:Westfranken!!!!
example.local\user:Gabelstapler2000
The password history in AD is intended to prevent password reuse after password changes, but by storing expired passwords it can reveal extensive information about user behavior. Thus, the forced regular changes do not increase security, but instead provide weaker passwords that are created once and then minimally changed each time. This weakens security in that a single cracked password from the password history can reveal all other passwords. Rules and masks are a good way to crack a user's password history.
The password history is not downloaded with the "normal" NTDS dump. Even frameworks like Crackmapexec are currently not able to do this. However, Secretsdump offers a suitable option with -history.
Example:
secretsdump.py example.local/Administrator:password123@10.0.0.1 -history
example.local\user:Hash:München1976
example.local\user_history0:Hash:München1975
example.local\user_history1:Hash:München1974
example.local\user_history2:Hash:München1973
example.local\user_history3:Hash:München1972
So are you on the safer side if you don't force users to renew their passwords regularly? Not really, because once created, passwords are often used more than once. Thanks to the lack of salts in NTLM, password reuse is already recognizable from the hashes.
Due to password reuse, up to 30% of systems can have the same password.
This high number is partly due to the default passwords assigned by the administrator for machine accounts in Active Directorys. In addition, typical passwords are used multiple times by different people.
The password summer+year is an inglorious example here.
Example:
example.local\user:Sommer2022!
example.local\user01:Firma1234#
example.local\user02:Firma1234#
example.local\user03:Sommer2022!
Sometimes it still happens that LM hashes were not deactivated on older systems or for reasons of backward compatibility. The LM hash is the predecessor of the NT hash and has numerous cryptographic weaknesses, making it easily crackable today.
LM_Hashes should be disabled by default nowadays.
Example:
LM deaktivert bzw. leerer LM Hash
example.local\user01:aad3b435b51404eeaad3b435b51404ee :9b1b37b966345526850732e17aed49f8:Sommer2022!
LM nicht deaktiviert
example.local\user02:628eddc897eb8d8cfb12c634df37c04f :9b1b37b966345526850732e17aed49f8:Sommer2022!
First, I used some methods against passwords that you know from the first articles: Dictionary, Hybrid and Mask/Bruteforce attacks. My first approach to both NTDS dumps consisted of:
1. LM-Hashes vorhanden?
Wenn ja:
hashcat -a3 -m3000 a?a?a?a?a?a?a?
2. Bruteforce bis 8 Zeichen:
hashcat -a3 -m1000 -O -w4 ntds.txt "?a?a?a?a?a?a?a?a"
3. Wörterbuchangriffe mit Regeln und Loopback:
hashcat -a0 -m1000 -O -w4 ntds.txt wörterbuch.txt -r rule.rule --loopback
4. OSINT & Cewl
Erstellung von gezielten Wörterbüchern mittels Cewl
Suche nach weiteren Informationen über das Ziel
5. Gezieltere Wörterbuchangriffe mit Regeln und Loopback
hashcat -a0 -m1000 -O -w4 ntds.txt eigenes_Wörterbuch.txt -r --loopback rule.rule
In this way, I cracked about 60% (Company A) and 40% (Company B) of the hashes in the first step. Afterwards, I performed a password analysis to identify and exploit statistical peculiarities.
The cracked passwords had some peculiarities:
Example:
Wortwiederholungen:
Sommer_Sommer18wdefrgthzj
UrlaubUrlaubUrlaub
Sätze:
Back_me.up12
Derbaum4mal
Keyboardwalk:
qwertzuiop
wdefrgthzj
q2w3e4r5t67z8u9i0o
Ähnliche Suffixe bzw. Präfixe:
Playstation.4
Bananenbieger1984!
Sommer2022!
2008anna
These are all typical password combinations that can be easily cracked with the right rules and dictionaries.
The knowledge for this is publicly available, so an attacker could easily crack about 50% of the passwords.
However, to crack more than 50%, knowledge about the optimization of Hashcat and the attacks used is necessary. This is what the next step deals with.
In the further analysis of the cracked passwords, tools like Pack and Pipal come into play to find commonalities. Based on this analysis, statistics, rules and masks are then generated to crack passwords with similar schemes. If, as in this case, information about the password policy is available, you can generate masks using Pack. This section introduces Pack and its included programs, as well as Pipal as an alternative, and gives tips on how to use them.
Peter Kacherginsky developed Pack (Password Analysis and Cracking Kit) several years ago. Nowadays there is a rewrite in Python3 by Hydraze. With Pack you can analyze passwords, evaluate them and design your own masks, rules and statistics. Pack consists of several programs: Statsgen, Maskgen, Policygen, Rulegen. With these subroutines all functions of Pack are mapped.
Installation:
git clone https://github.com/Hydraze/pack
Für RuleGen benötigt
sudo apt install python3-enchant
python3 statsgen.py
The basis of Pack is StatsGen, which is used to analyze passwords. Statsgen creates statistics about passwords, length distribution, character sets, password complexity and possible masks. Pack needs this information for its further use.
Other possibilities with Statsgen are the parameter -hiderare, in order not to falsify the statistics by rare passwords. Furthermore, filters can be used to examine certain passwords more closely. For this one uses the options -charset,-simplemask,-maxlength,-minlength. Created masks can be saved with -O and used by Hashcat.
Syntax:
Syntax examples:
Analyse von Passwörtern:
python3 statsgen.py cracked_hashes.txt
Analyse und Ausschluss von seltenen Passwörtern:
python3 statsgen.py cracked_hashes.txt --hiderare
Analyse und Speicherung als Maske:
python3 statsgen.py cracked_hashes.txt -o
Analyse und Filterung + alles vorherige:
python3 statsgen.py cracked_hashes.txt --simplemask=stringdigit --hidereare -o
MaskGen optimizes the masks generated by StatsGen by sorting and analyzing masks. This allows better hashcracking results to be achieved.
Masks can be sorted by complexity, frequency or OptIndex (mixture of complexity and frequency). Mostly -optindex is a good method for sorting, for password policies -Complexity may be worth a look. The parameter for sorting -occurrence is, in my opinion, negligible, since it produces only a few useful masks.
Often, not all attacks can be carried out during pentests. This is always a time problem, especially with masks or bruteforce attacks. The maximum allowed time duration of all masks can be specified with -targettime. With -targettime the total time duration of the engagement can be specified, i.e. the maximum possible time. Individual masks can be displayed with -showmasks and evaluated for their length, frequency and duration. This can be useful to find time outliers or masks that do not fit into the scheme for other reasons.
The -showmasks parameter can be used to output the individual masks with their respective length, frequency and duration. The parameter -pps is important to keep the calculation realistic: It includes the computing power in passwords per second. With higher computing power, more extensive masks can be searched faster or vice versa. With -o the masks can be stored in the .hcmasks format, with which Hashcat can work without problems. The Maskgen headers can be hidden with -q.
Individual filters:
Masks can also be sorted by length, time, complexity or frequency using individual filters. The parameters -minlength or -maxlength are useful if, for example, everything is cracked up to 8 characters or you want to refrain from masks above a certain length. The parameters -mintime or -maxtime can be used to specify the duration of a single mask.
Personally, I would specify the duration of the available time with -targettime and the time for the respective individual mask with -mintime to avoid outliers. With -min/maxcomplexity and -min/maxoccurrence you can fine-tune the masks, but for the beginning the above parameters are usually sufficient.
Custom masks generated with Maskgen can be tested on password lists for their functionality against real passwords. However, I would advise caution here, because most password leaks come from websites and/or from the English-speaking area. Therefore, many of these dumps are not comparable with the typical passwords from the "German" AD environment. It is nevertheless possible with the option -checkmasksfile, where two masks are compared with each other.
Syntax:
Syntax examples:
Analyse von Masken, Anzeige aller Masken und eigener Geschwindigkeit:
python maskgen.py --showmasks --pps 10000000
Analyse von Masken und Sortierung nach optindex:
python maskgen.py --optindex
Analyse von Masken und Filterung nach Länge:
python maskgen.py --minlength=9 --maxlength=14
Analyse von Masken und Sortierung nach einzelner Maskenlaufzeit
python maskgen.py --targettime 21600
Analyse von Masken und Filterung nach gesamter Maskenlaufzeit:
python maskgen.py --maxtime=3600
Überprüfung
PolicyGen is the tool of choice when it comes to enterprise password policies. In AD environments, minimum complexity is often enforced by password policies (link to article 1). This enforces the use of upper and lower case letters, numbers and special characters. PoliyGen creates masks that fulfill this scheme.
PolicyGen can be used to perform a variety of tasks: Verify compliance with password policies, support password cracking in pentests and verify password policies.
The hashes per second can be specified using -pps as with MaskGen. This also applies to other parameters like -o for saving, -showmasks and -q. With the parameters -min/maxlength the length of the passwords can be specified. It should be noted here that masks that are too large can no longer be cracked in an acceptable time. The individual policy parameters can be defined using -min/maxspecial, -min/maxdigit , -min/maxupper, -min/maxlower. If an audit is performed to find passwords that violate the policy, this can be done with -noncompliant.
However, with Windows Password Policies there is a peculiarity: natively only 3 of 4 complexity requirements are needed, which is not provided for in PolicyGen in this way. The workaround consists of manually executing all 4 combinations, then merging them into one file and deduplicating them. Also, -noncompliant would be a useful option here to find passwords that violate the policy.
./policygen.py --minlength=9 --maxlength=10 --mindigit=1 --minspecial=1 --minlower=1 -o testing/mask01.hcmask
./policygen.py --minlength=9 --maxlength=10 --mindigit=1 --minspecial=1 --minupper=1 -o testing/mask02.hcmask
./policygen.py --minlength=9 --maxlength=10 --mindigit=1 --minlower=1 --minupper=1 -o testing/mask03.hcmask
./policygen.py --minlength=9 --maxlength=10 --minspecial=1 --minlower=1 --minupper=1 -o testing/mask04.hcmask
cat *.hcmask >> allmasks
sort allmasks | uniq -u > 9-10_chars_3_off_4.hcmask
Syntax
Syntax examples:
Passwort Policy zwischen 9 und 14 Zeichen
./policygen.py --minlength=9 --maxlength=14
Passwort Policy mit verschiedenen Zeichen als Mindestanforderung:
./policygen.py --minspecial=1 --minlower=1 --minupper=1 --mindigit=1
Passwort Policy mit verschiedenen Zeichen als Maximalanforderung:
./policygen.py --maxdigit=5 --maxlower=3 --maxupper=4 --maxspecial=2
Passwort Policy mit verschiedenen Zeichen und Filterung nach noncompliant
./policygen.py --minspecial=1 --minlower=1 --minupper=1 --mindigit=1 --noncompliant
RuleGen provides tools and possibilities to analyze, generate and optimize rules. For this purpose, cracked passwords are analyzed using the Python library Enchant and language engines such as Aspell, Myspell and Hunspell. Rulegen can analyze single passwords as well as whole word lists and create matching rules. You can also analyze and further optimize created rules.
In order for Rulegen to work properly, some dictionaries must be used for the various spelling corrections. It is recommended to install as wide a variety of dictionaries as possible: different languages, dialects, subject-specific dictionaries or even old/new spelling.
Eine kleine Auswahl an Wörterbüchern:
sudo apt install aspell-de-1901
sudo apt install aspell-de
sudo apt install aspell-nl
sudo apt install aspell-fr
sudo apt install hunspell-de-de
sudo apt install hunspell-de-med
sudo apt install hunspell-de-at
sudo apt install hunspell-de-ch
Individual passwords:
Anschließend können einzelne Passwörter mit der Option –password <Input> analysiert werden. Hierbei ist es sinnvoll, den Verbose-Modus zu nutzen, um die Regelerstellung mitverfolgen zu können.
Exotic words can be forced as root words using -word, since they are often not recognized by the language engine. An example of use here would be the customer name in the pentest. For several such own words can be specified by means of -wordlist own dictionaries, which are to be considered likewise. Own word lists are particularly meaningful if one already has cracked passwords or special language/words with to use would like.
To generate more rule or word suggestions, the parameters -morerules and -morewords are suitable. These options allow the generation of suboptimal rules and words. A further option for the adjustment of RuleGen would be the option -maxworddist=10, with which the permitted Levenshtein distance is adjusted. With these options, it should be noted that more root words or rules can be generated as a result, but the quality does not necessarily increase as a result.
Comparison of different RuleGen options in terms of the amount of hashes cracked:
It can be seen that Aspell is the more efficient language correction and the default settings are more than sufficient in most cases.
Note: The evaluation does not fulfill any scientific claim and was only performed with a limited number of different NTDS dumps.
Standardeinstellungen mit Aspell
./rulegen.py hash.txt --providers=aspell -b test03
Recovered........: 3309/9061 (36.52%) Digests (total), 3309/9061 (36.52%) Digests (new)
Standart Einstelllungen mit hunspell
./rulegen.py hash.txt --providers=hunspell -b test02
Recovered........: 2963/9061 (32.70%) Digests (total), 2963/9061 (32.70%) Digests (new)
Einstellungen mit verschiedenen Parametern zusammen
./rulegen.py hash.txt --maxworddist=15 --morewords --morerules --providers=aspell,myspell,hunspell -b test01
Recovered........: 2656/9061 (29.31%) Digests (total), 2656/9061 (29.31%) Digests (new)
Password lists:
Password lists can simply be specified as a file and are interpreted directly by RuleGen. The passwords in the lists must be specified without the respective hash value or other additions. Passwords that do not provide sufficient patterns are skipped. The same applies to numbers and non-ASCII characters, which is a certain limitation for different languages.
Mit der Option -b <Name> lassen sich die Ergebnisse in einer Datei speichern. Es wird jeweils eine unsortierte Regel- und Stammwörter-Datei erstellt.
Syntax:
Syntax examples:
Rulegen Analyse einzelner Passwörter im Verbose Modus:
./rulegen.py Hashlist --password WinterS8793! -verbose
Rulegen Analyse von Passwortlisten mit Speicherung der Regeln
./rulegen.py Hashlist -b
Rulegen Analyse von Passwortlisten mit verschiedenen Sprachprovidern:
./rulegen.py Hashlist --providers=aspell,hunspell,myspell
Rulegen Analyse von Passwortlisten mit erzwungenen Stammwörtern:
./rulegen.py Hashlist —word=
Rulegen Analyse von Passwortlisten mit eigenen Wörterbüchern:
./rulegen.py Hashlist -w /path/to/the/dict
Rulegen Analyse von Passwortlisten mit Fine-Tuning der Regel/Wort Generierung:
./rulegen.py Hashlist --maxworddist=10 --maxwords=7 --maxrulelen=15 --maxrules = 5
An alternative to Pack is Pipal, which is programmed by Robin Wood aka Digininja. It analyzes passwords just like Pack and offers some special features, which I will discuss in the following.
The program is modular, so that all functions can be activated or deactivated. The modules are called checkers and each offers individual specific functions. The modular structure offers the great advantage that functions that are not required can be temporarily deactivated. This brings time advantages, especially with large password lists.
By default, Pipal uses only the Basic Checker, which analyzes the most common passwords and root words, password length and distribution, and letter/digit usage. Other checkers add methods to analyze languages like English, German, French and Dutch. Furthermore, there are checkers that (similar to StatsGen) generate masks for Hashcat or match passwords with the default Windows password policy.
In my opinion, the crucial difference to Pack and StatsGen is that Pipal is designed much more for the pure analysis and evaluation of passwords. StatsGen, on the other hand, is more intended for creating masks in combination with MaskGen and plays to its strengths there.
Installation:
https://github.com/digininja/pipal.git
././pipal.rb
Für manche Module sollte auch noch das Gem "levenshtein-ffi" installiert sein:
gem install levenshtein-ffi
# Checkers:
Aktivieren des Basic Checkers:
ln -s ../checkers_available/basic.rb .
Aktiveren aller anderen Checker:
ln -s ../checkers_available/*rb .
Note that enabling more checkers can significantly increase the duration of the password analysis: The more checkers are used, the longer the process takes. Since these are symlinks, unneeded checkers can be easily deleted from the checkers_enabled file.
Usage:
Usingdifferent checkers can unlock different options, so I will now assume the following setup:
ls checkers_enabled/
01basic.rb DE_emotion_checker.rb DE_religion_checker.rb DE_season_checker.rb DE_vehicle_checker.rb README
DE_colour_checker.rb DE_family_checker.rb DE_road_checker.rb DE_sport_checker.rb hashcat_mask_generator.rb windows_complexity_checker.rb
Pipal needs a file with the respective passwords and the desired checkers for the analysis of passwords. Afterwards the analysis takes place automatically and is written with -o into an output file. Hashcat masks for all analyzed words can be output with the option -hashcat.all.
Syntax
Syntax examples:
Pipal Analyse einer Passwortliste:
./pipal.rb
Pipal Analyse einer Passwortliste und Speicherung:
./pipal.rb -o
Pipal Analyse einer Passwortliste und Anzeigen der Top Passwörter:
./pipal.rb --top
Pipal Analyse einer Passwortliste und Ausgabe aller Hashcat-Masken:
./pipal.rb --hashcat.all
Using the tools, techniques, and methods described in the text, we were able to significantly increase the amount of hashes cracked with little effort in both case studies.
With all analysis tools, however, you should always keep in mind that while programs can do a lot, humans can recognize more patterns than programs. So my advice is to do the analysis yourself and if necessary write your own rules or masks for the particular case. Programming or scripting helps enormously to simplify this work.
Nevertheless, Pack & Pipal are two extremely valuable tools in advanced password cracking. Due to the previously described capabilities of Pack, we were able to crack a significant amount of additional hashes in both cases.
As a pentester (or attacker in general), I would use the statistical methods to find patterns and exploit them. The topic still offers a lot of room for further research and own developments.
I will describe the further procedure in detail in the following articles, because there are a lot of methods, especially for cracking the last third of the passwords. Password cracking is a very extensive topic and therefore this article can only give an extract of the different possibilities of password analysis.
Our first article on the topic of password cracking dealt with password policies, which, with the right settings, are an important element for protection against attackers. In the case studies mentioned above, the password policy of company B meant that instead of 80%, we were able to crack "only" 60% of the passwords with relatively simple means.
However, the still quite high percentage of cracked passwords also shows the weaknesses of the password policy instrument: Users are "only human" and often look for the most convenient way to comply with policies. For example, a well-intentioned password history can in reality lead to passwords that have only been minimally changed being even easier to crack.
As a sysadmin (or defender in general), I would advise to combine passwords with a lot of user awareness and MFA due to human weaknesses. Human generated passwords are always very vulnerable to statistical or even probalistic attacks.
If you're concerned with IT security, you can't miss the OWASP Top 10. The non-profit organization Open Web Application Security
Burp Suite by Portswigger and OWASP ZAP are both programs with a proxy server that run on your local device. With
Our co-founder Immanuel was a guest at Radio Bonn/ Rhein-Sieg and told the presenter team Nico Jansen and Jasmin Lenz and