Good afternoon, colleagues. I want to talk about my interesting experience. Maybe someone will come in handy.
In the modern world, passwords are used everywhere. On a corporate computer, on a personal phone and tablet, in the mail, etc. And it would seem everyone has repeatedly explained that the password must be strong. Recommendations were shown that the password should not contain personal data, vocabulary words, simple combinations, etc. Nevertheless, many more people continue to use simple passwords. That is not only a violation of security requirements, but also represents a serious danger to both personal and corporate data.
Accordingly, the problem arises with the help of available tools, without installing complex software, to check the domain user passwords for resistance to a dictionary attack. At the same time, you need to keep password confidentiality. Those. so that the verifier does not see the passwords in the clear, but at the same time he could definitely say that the password is a dictionary word.
')
Due to the fact that our domain is built on the basis of Microsoft Windows, to solve this problem, it was decided to compare the password hashes of the domain users with the dictionary hashes. In general, this approach can be applied to hashes from any systems. Only the methods for receiving user hashes will change.
Hashi user passwords in the Windows domain can be obtained from the ntds.dit file. But in normal mode, access to it is denied by the system. With the help of Google, an opportunity was found to get a copy of the ntds.dit file (containing including usernames / passwords of users of the domain) using standard tools of the domain controller.
To get a copy of ntds.dit, the capabilities of the ntdsutil.exe utility are used. With its help, you need to take a snapshot of the system (Volume Shadow Service) and get a copy of the SYSTEM file (it contains the key to extract hashes from the ntds.dit database).
To create a copy, execute the following commands:
C:\>ntdsutil ntdsutil: activate instance ntds ntdsutil: ifm ifm: create full c:\audit ifm: quit ntdsutil: quit
As a result of the work, the C: \ Audit directory appears. Inside the directory there are two folders: Active Directory and registry. Accordingly, the first one contains a copy of ntds.dit, and the second copy of the SYSTEM and SECURITY registry branches. These folders can be copied to another computer or left on a domain controller.
Next, you need to extract from ntds.dit usernames and passwords of domain users. To do this, use the small utility ntds_decrypt. You can get it at
ntds_decode.zip . We download archive, we unpack. We get two files. Actually executable file and readme with description of options.
ntds_decode -s FILE -d FILE -m -i -s <FILE> : SYSTEM registry hive -d <FILE> : Active Directory database -m : Machines (omitted by default) -i : Inactive, Locked or Disabled accounts (omitted by default)
To use the utility, you must run the command prompt with “Administrator” rights. On the cmd.exe file, right-click and select the "Run as Administrator" item. At the command prompt, run the utility:
ntds_decode -s C:\Audit\registry\SYSTEM -d "C:\Audit\Active Directory\ntds.dit"
Here we run the utility with the main parameters (paths to the ntds.dit and SYSTEM files), since we do not need blocked or disabled accounts (option -i), and computer accounts (option -m).
As a result, we get the file hashes.txt. The file format is similar to the pwdump format and is accepted by most brute-forcing programs (such as L0phtCrack). The file format is:
<username>:<rid>:<lm hash>:<ntlm hash>:<description>:<home directory>
Actually, in the hashes.txt file, we are primarily interested in the “username” and “ntlm hash” fields.
Well, we got the raw data. Now we need a dictionary. I took one of the dictionaries on the Internet for 9 million words with a size of 92 MB. However, I would like to expand it a bit with typical templates. For example, add a pair of numbers at the end, change the case of letters, etc. For this operation, the good old John the Ripper was a great fit. In its functionality it is possible to mutate the dictionary according to certain rules. I decided not to limit the possibilities of JtR and launched it in the standard version with all possible mutations.
john --wordlist=9mil.txt --rules dict.txt
After some time, I had a dict.txt file containing approximately 131 million words. Now for the words you need to get NTLM hashes. Since we wanted to compare hash with hash. To calculate the NTLM dictionary hashes, use the HashManager toolkit. You can
get it at
HashManager . By the way, it also includes utilities for the mutation of dictionaries. But we need a great utility GenerateHashList. It generates hashes for all passwords in the source file.
In the unpacked archive, go to the Bonus folder - GenerateHashList. And run the bat file with the parameters in the command line:
generate.bat NTLM dict.txt
After some (long) time we will get the file dictionary.txt containing the dictionary hashes. File size is about 4.3 GB. This is a very large file. And ideally, you need to move on to using SQL, but I didn’t want to, because it did not fit the requirements if possible to use available tools that do not require the installation of complex software.
Then, for a start, it was decided to use the features of Windows. Namely, FINDSTR utility. This utility allows you to search for a string in the file and is an updated version of the FIND utility. Using Google, a solution was found that read the hash from the hashes.txt file and searched for it in the dictioanry.txt file. Actually, here is the command:
(for /f "usebackq tokens=1,4 delims==:" %%i in ("hashes.txt") do FINDSTR /I /B "%%j" Dictionary_sort.txt && Echo %%i>>"audit.txt" && Echo %%i %%j>>"audit_full.txt")
The result of the utility will be two files:
- audit.txt, containing only user logins whose password hashes were found in the dictionary
- audit_full.txt containing, besides the login, the hash itself. This is in case the user has doubts that the hash was found in the dictionary.
The existing hashes.txt file contained approximately 20,000 lines. When I ran the find utility, I found that searching for a single hash in the dictionary takes about 40 seconds on my Lenovo X220 laptop. Having estimated the number of available strings and the average search time, it turned out that it would take about 10 days to search all the hashes. True result can be seen in the process. Since the found hashes immediately go to the audit.txt file. On a more powerful computer, the speed will be higher, but not by much. Linear search is quite time-consuming. And the search time depends on the volume of the dictionary. In general, this is a working version, but inconvenient.
Then it was decided to write your own search script. I have been interested in Python for a long time, and most recently, looking at Harvard CS50 lectures on Youtube, I remembered the binary search algorithm and decided to try to implement it for searching hashes in a dictionary. Here we go!
First you need to sort the dictionary. This is necessary for the implementation of a binary search and besides this will allow even more to ensure the safety of the password. Since after sorting it will not be possible to unambiguously associate the dictionary hash with the word. Based on the goal, use the available tools, use the utility SORT from the Windows. At the command prompt, run the command:
sort dictionary.txt > dictionary_sort.txt
Got a sorted dictionary of hashes. Now the script itself. I'm not an expert in Python, I'm just learning, so with the help of Google and various obscene words I collected a script and made it work. Naturally, the script is not optimal and looks scary, but it works. As parameters, it is passed the path to the hashes.txt file, the path to the dictionary file, and the path to record the result (audit.txt, audit_full.txt).
Startup format:
PassAudit.exe -ic:\audit\hashes.txt -dc:\audit\dictionary_sort.txt -oc:\audit\
Here is the script itself:
import argparse
For convenience, I compiled the script into an exe-file. After launch, on the same data set, the search time was about 3 minutes.
All the manipulations listed here for obtaining domain user password hashes and checking them with a dictionary are pretty well automated in a script. The generation of dictionary hashes is a one-time operation and is performed as needed.
Thus, you can configure a script that on a regular basis will upload user password hashes from a domain controller, check them with a dictionary and send the result to technical support to alert users about a weak password.
Perhaps all this could be done easier, faster and more beautiful, but in any case it was an interesting experience.