-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDumbADPasswordChecker.ps1
executable file
·201 lines (150 loc) · 9.71 KB
/
DumbADPasswordChecker.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<#
Name: DumbADPasswordChecker
Author: AJ Van Beest
Last modified: 20210887T0555
Description:
Audit your active directory passwords for easily-guessed passwords, ask people who have them to change them, force the change if need be, and build statistics about these efforts to report out.
Requirements:
- Powershell 7.x
Roadmap:
- Proper PS headers / documentation
- Functions? Does that even make sense?
- .md re: How to dump hashes
- Statistical analysis of passwords
- Historical user reporting
- Secure credential handling
- Move email config to their own directory
- Secure-wipe the hashes / .pot file
- Tools
+ Check for existing installs
+ Verify file integrity of downloads
+ Offer to install the tool
#>
<# ======== User Variables (feel free to tweak to your liking) ======== #>
# Set the working directory to a nice secure-by-default location
$WorkingDir = "C:\users\avanbeest\testing\"; mkdir $WorkingDir
$Days = 4 # How many days do people have to change their passwords? (integer)
$YourOrg = "Contoso" # The name of your organization
# Create a timestamp for file names
$Time = get-date -f "yyyyMMddTHHMM"
<# ======== Script Variables (please leave as is) ======== #>
# Build directory structure
# These directories will auto-build in your working directory
$DataDir = $WorkingDir + "data\"; mkdir $DataDir
$EmailDir = $WorkingDir + "email\"; mkdir $EmailDir
$SecretsDir = $WorkingDir + "secrets\"; mkdir $SecretsDir
$WordlistsDir = $WorkingDir + "wordlists\"; mkdir $WordlistsDir
$Installers = $WorkingDir + "installers"; mkdir $Installers
$Dir7Zip = $Installers + "\7Zip"; mkdir $Dir7Zip
$DirHashcat = $Installers + "\hashcat"; mkdir $DirHashcat
$DirMentalist = $Installers + "\mentalist"; mkdir $DirMentalist
$DirGPG = $Installers + "\GPG"; mkdir $DirGPG
# Get environmental information
$AllAccounts = get-aduser -filter * | Select-Object name, mail, whenChanged | Export-Csv -path $SecretsDir + $Time + "_all-AD-accounts.csv"
# Get AD password policies as per https://devblogs.microsoft.com/scripting/use-powershell-to-get-account-lockout-and-password-policy/
<# ======== Handle credentials ======== #>
<# ======== Download tools ======== #>
<# Check for, and get (if necessary) the tools we're going to use:
- 7Zip
- Python
- Hashcat
- Mentalist
- PGP4Win
#>
#7zip
$Installer7Zip = $Dir7Zip + "\7z1900-x64.msi";
Invoke-WebRequest "https://www.7-zip.org/a/7z1900-x64.msi" -OutFile $Installer7Zip
#Python
# >> Check for python installation; if not installed, do it.
$VersionPython = python --version
if ($VersionPython -match '.*not found.*'){<# INSTALL THE THING #>} else {write-host "`n==========`n`nPython should be good to go:" $VersionPython"`n`n=========="}
# Hashcat
$InstallerHashcat = $DirHashcat + "\hashcat-6.2.3.7z"
$HashHashcat = $DirHashcat + "\hashcat-6.2.3.7z.asc"
Invoke-WebRequest "https://hashcat.net/files/hashcat-6.2.3.7z" -OutFile $InstallerHashcat
Invoke-WebRequest "https://hashcat.net/files/hashcat-6.2.3.7z.asc" -OutFile $HashHashcat
Expand-7Zip $InstallerHashcat $DirHashcat
#Mentalist
$InstallerMentalist = $DirMentalist + "\Mentalist-v1.0-Win.zip"
Invoke-WebRequest "https://github.com/sc0tfree/mentalist/releases/download/v1.0/Mentalist-v1.0-Win.zip" -OutFile $InstallerMentalist
#Invoke-WebRequest "https://github.com/sc0tfree/mentalist/archive/refs/heads/master.zip" -OutFile $InstallerMentalist
Expand-Archive $InstallerMentalist $DirMentalist
#GnuPG
<# ==== Don't have trust-worthy file hash for the latest version of the installer :( ====
$InstallerGPG = $DirGPG + "\gnupg-2.3.2.tar.bz2"
Invoke-WebRequest "https://www.gnupg.org/ftp/gcrypt/gnupg/gnupg-2.3.2.tar.bz2" -OutFile $InstallerGPG
$HashGPGWeb = -split ((Invoke-webrequest https://gnupg.org/download/integrity_check.html).tostring() -split "[`r`n]" | select-string '[\d\D]{40}\s{2}gnupg-2\.2\.29\.tar.bz2') | Select-Object -first 1
$HashGPGCalc = Get-FileHash -Algorithm SHA1 $InstallerGPG |select-object -ExpandProperty Hash
if ($HashGPGWeb -eq $HashGPGCalc) {Write-Host "Hey, good news: The GPG hashes match, so the file's legit!"} else {Write-Host "Yo. There seems to be a mismatch with the hash values for GPG. Check that out, will ya?"}
#>
<# ======== Build a "Dictionary of Dumb Passwords" ======== #>
# Run mentalist to build a wordlist
write-host "`n==========`n`nStarting Mentalist for wordlist creation`n`n==========";
cd $DirMentalist; .\Mentalist.exe
<# ======== Dump you some hashes ======== #>
<# Best practice here is to work with your SecEng / AD Admin team to safely
copy the ntsd.dit file and extract it into crackable hashes.
If you *are* the SecEng/AD Admin team, please see the accompanying .md file
for further instructions.
#>
<# ======== Crack you some hashes ======== #>
<# Run Hashcat against the hashes using the Mentalist wordlist
Remove the hashes; delete the .pot file!
Keep two separate lists:
- People with weak passwords: For communication, education, and remediation.
- The actual weak passwords: For statistics and reporting.
#>
# $Users = | Export-Csv -Path $DataDir + "people_who_need_change.csv" # Hashcat results! All the people who were found with easy-to-guess passwords
# $Pass = | Export-Csv -Path $DataDir + "weak_pws.csv" # All the easy-to-guess passwords found
<# ======== Send nice emails ======== #>
$Users | ForEach-Object {
$From = "[email protected]"
$To = $_.mail
#$Cc = "manager's email address here"
$Subject = "Something less spammy than 'Action required re: your password'"
$Body = "
<h2>A quick note about your password</h2>
<h3>Please verify this message with your supervisor!</h3>
Hi, $_.name,</p>
I'm Alicia Jones from the $YourOrg information security team.</p>
First thing first: I know that this email feels totally suspicious. Before going any further, please verify it's legitimacy with either your supervisor or the $YourOrg help desk.</p>
We've recently started auditing the strenght of people's passwords, here at $YourOrg, and this is kind of a good news, bad news message about your account.</p>
While your current password meets the $YourOrg complexity policy (length, numbers, symbols, etc.), unfortunately it's pretty easy to guess with an automated system, and that's what we just did.</p>
<h3>So what's next?</h3>
The $YourOrg security team is asking you to change your password ASAP. In a perfect world, we'd like you to change it *now*. But we also understand the hassle of this change, so we're asking you to set a stronger password within the next $Days days.</p>
<h3>Building a better password</h3>
For this next password, please consider using a passphrase. That means several (hopefully unrelated) words along with numbers and symbols. A somewhat-famous example of this (<a href='https://xkcd.com/936/?correct=horse&battery=staple'>thanks XKCD!</a>) is 'CorrectHorse!BatteryStaple.' Please don't use that, though; it's easy to guess, too!</p>
<h3>Thanks for helping secure $YourOrg!</h3>
I want to end this message, $aduser.name, with a bit of heart-felt thanks. It's by taking relatively simple-yet-direct actions -- like checking out a sus email with your boss or the help desk, and, yes, by setting a stronger password for oyour account -- that you make a really ppowerful, positive impact to the security of $YourOrg.</p>
Thank you!</p>
Sincerely,</p>
Alicia Jones, CISSP</br>
Information Security Analyst, $YourOrg</p>"
$SMTPServer = "smtp.mailtrap.io"
$SMTPPort = "587"
Send-MailMessage -From $From -to $To -Cc $Cc -Subject $Subject -Body $Body -BodyAsHtml -SmtpServer $SMTPServer -Port $SMTPPort -UseSsl -Credential (Get-Credential)
}
<# ======== Initial reporting ========
- How many passwords were guessed
- Who dun it
- How many people vs. service accounts
- Employees vs. vendors
- Top 10 passwords
#>
<# ======== Send "Now it's gettin' real emais" ======== #>
$GettingRealUsers = $Users | foreach-object {
get-aduser -filter * -properties * | where {$_.whenChanged -lt (get-date).adddays(-($Days-1)) -and $_.Enabled -eq "True"} | Select-Object name, mail, whenChanged
}
<# ======== Send sorry/not-sorry emails ======== #>
$SorryNotSorry = $GettingRealUsers | foreach-object {
get-aduser -filter * -properties * | where {$_.whenChanged -lt (get-date).adddays(-1) -and $_.Enabled -eq "True"} | Select-Object name, mail, whenChanged
}
<# ======== Final reporting ========
- Same as inital, plus:
- Total easy-to-guess passwords detected
- Total changed / percent of all pws
- How many people / who changed pw voluntarially?
- How many / who were forcibly reset?
- People detected multiple times
- Month over month trends
#>