-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathInvoke-DHCPCheckup.ps1
371 lines (273 loc) · 11.9 KB
/
Invoke-DHCPCheckup.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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
Import-Module DHCPServer
Import-Module ActiveDirectory
Import-Module DnsServer
function GetActiveActiveDhcpServers
{
$DhcpServers = Get-DhcpServerInDC
$activeServers = @()
if (!$DhcpServers)
{
Write-Host "[*] Error - No DHCP servers found in the domain"
throw
}
foreach ($server in $DhcpServers)
{
# Check if the server is responding
$error.Clear()
try
{
$res = Get-DhcpServerSetting -ComputerName $server.DnsName -ErrorAction SilentlyContinue
}
catch
{
}
if (!$error[0])
{
$activeServers += $server
}
else
{
Write-Host "[*] DHCP server $($server.DnsName.ToUpper()) is not responding!"
}
}
return $activeServers.DnsName
}
function GetStrongUsers
{
$strongGroups = ("Domain Controllers", "Domain Admins", "Enterprise Admins", "DnsAdmins", "Administrators")
$strongGroupsMembers = @()
foreach ($group in $strongGroups)
{
$strongGroupsMembers += Get-ADGroupMember $group | select name
}
$strongGroupsMembers = $strongGroupsMembers | select name -unique
return $strongGroupsMembers.name
}
function Check-DnsCredentialSettings
{
param(
[parameter(Mandatory=$True)][String[]]$ActiveDhcpServers,
[parameter(Mandatory=$True)][String[]]$strongGroupsMembers
)
# Check DNS Credentials Configuration
$DhcpCredentials = @()
foreach ($server in $ActiveDhcpServers)
{
$serverDisplayName = $server.ToUpper()
$serverCN = $server.Split(".")[0].ToUpper()
$serverDnsCredential = Get-DhcpServerDnsCredential -ComputerName $server
if ($serverDnsCredential.UserName -ne "")
{
Write-Host "[*] $($serverDisplayName) - The credential used to create and own DNS records by the server is: '$($serverDnsCredential.UserName)'"
$DhcpCredentials += ,($serverDnsCredential.UserName, $serverDisplayName)
# Check if the DNS credential is strong
if ($serverDnsCredential.UserName -in $strongGroupsMembers)
{
Write-Host "[*] $($serverDisplayName) - The credential '$($serverDnsCredential.UserName)' is a Member of a strong group. This means that a malicious DHCP client could spoof any DNS record in the zone."
}
}
# If no DNS credential is configured, the machine account would be used
else
{
Write-Host "[*] $($serverDisplayName) - DNS credential is not configured. The machine account '$($serverCN)$' would be used to create and own DNS records."
$DhcpCredentials += ,(($serverCN + "$"), $serverDisplayName)
# Check if the DNS credential is strong
if ($serverCN -in $strongGroupsMembers)
{
Write-Host "[*] $($serverDisplayName) - The credential '$($serverCN)$' is a Member of a strong group. This means that a malicious DHCP client could spoof any DNS record in the zone."
}
}
Write-Host ""
}
return $DhcpCredentials
}
function Check-DhcpNameProtectionSettings
{
param(
[parameter(Mandatory=$True)][String[]]$ActiveDhcpServers
)
foreach ($server in $ActiveDhcpServers)
{
$printed = $False
$serverDisplayName = $server.ToUpper()
# IPv4 scopes settings
$serverV4DnsSettings = Get-DhcpServerv4DnsSetting -ComputerName $server
if ($serverV4DnsSettings.NameProtection -eq $False)
{
Write-Host "[*] $($serverDisplayName) - Name protection disabled on the server level for IPv4. This means that new scopes would be created without name protection."
$printed = $True
}
$serverV4Scopes = Get-DhcpServerv4Scope -ComputerName $server
foreach ($scopeID in $serverV4Scopes)
{
$scopeV4DnsSettings = Get-DhcpServerv4DnsSetting -ComputerName $server -ScopeId $scopeID.ScopeId.IPAddressToString
if ($scopeV4DnsSettings.NameProtection -eq $False)
{
Write-Host "[*] $($serverDisplayName) - Name protection disabled for the IPv4 scope: $($scopeID.Name) - $($scopeID.ScopeId.IPAddressToString)"
$printed = $True
}
}
# IPv6 scopes settings
$serverV6DnsSettings = Get-DhcpServerv6DnsSetting -ComputerName $server
if ($serverV6DnsSettings.NameProtection -eq $False)
{
Write-Host "[*] $($serverDisplayName) - Name protection disabled on the server level for IPv6. This means that new scopes would be created without name protection."
$printed = $True
}
$serverV6Scopes = Get-DhcpServerv6Scope -ComputerName $server
foreach ($scopeID in $serverV6Scopes)
{
$scopeV6DnsSettings = Get-DhcpServerv6DnsSetting -ComputerName $server -prefix $scopeID.prefix.IPAddressToString
if ($scopeV6DnsSettings.NameProtection -eq $False)
{
Write-Host "[*] $($serverDisplayName) - Name protection disabled for the IPv6 scope: $($scopeID.Name) - $($scopeID.prefix.IPAddressToString)"
$printed = $True
}
}
if ($printed)
{
Write-Host ""
}
}
}
function Check-DnsUpdateProxyMembership
{
$allDhcpServers = Get-DhcpServerInDC
# Check for members of DNSUpdateproxy
$updateProxymembers = Get-ADGroupMember "DNSUpdateProxy"
foreach ($member in $updateProxymembers)
{
if (($member.name + "." + $domainName) -in $allDhcpServers.DnsName)
{
Write-Host "[*] $($member.name) is a DHCP server and a member of DNSUpdateProxy. DNS records created by this server are vulnerable to spoofing.`n"
}
else
{
Write-Host "[*] $($member.name) is not a DHCP server and a member of DNSUpdateProxy, it should be removed from the group.`n"
}
}
}
function Find-VulnerableDnsRecords
{
param(
[parameter(Mandatory=$True)][String[]]$DhcpCredentials
)
# Scan the permissions of all the DNS records in the zone to find vulnerable ones
$authenticatedUsersRecords = @()
$vulnerableRecords = @()
$printed = $False
$DnsRecords = Get-DnsServerResourceRecord -ZoneName $domainName -ComputerName $dnsServerName
foreach ($record in $DnsRecords)
{
$recordDisplayName = $record.HostName.ToUpper()
$recordAcl = get-acl -path "AD:$($record.DistinguishedName)"
# Check if the "Authenticated Users" group has write permissions over the record
$authenticatedUsersWrite = $recordAcl.Access | Where-Object {($_.ActiveDirectoryRights -eq "GenericWrite") -and ($_.IdentityReference -eq "NT AUTHORITY\Authenticated Users")}
if ($authenticatedUsersWrite)
{
$authenticatedUsersRecords += $recordDisplayName
}
# Check if any of the DHCP servers owns the record
# DhcpCredentials were extracted at the previous "DNS Credentials" section
foreach ($cred in $DhcpCredentials)
{
$DhcpServerCredential = $cred.split(' ')[0]
$DhcpServerName = $cred.split(' ')[1]
if ($recordAcl.Owner -ne $null)
{
if ($recordAcl.Owner.Split('\\')[1] -eq $DhcpServerCredential)
{
if (!($recordDisplayName -in $vulnerableRecords))
{
Write-Host "[*] The record '$($recordDisplayName)' is owned by the DHCP server $($DhcpServerName) with the credential '$($DhcpServerCredential)'. It is vulnerable to spoofing by malicious DHCP clients."
$vulnerableRecords += $recordDisplayName
$printed = $True
}
}
}
}
}
if ($printed)
{
Write-Host ""
}
if ($authenticatedUsersRecords)
{
Write-Host "[*] Found DNS Records Writeable By Authenticated Users. Any user in the domain could spoof these records:"
foreach ($record in $authenticatedUsersRecords)
{
Write-Host "`t* $($record)"
}
}
}
function Invoke-DHCPCheckup
{
<#
.SYNOPSIS
This function performs a security checkup on all DHCP servers in the domain, finding common misconfigurations that could cause security risks.
Author: Ori David (@oridavid123)
.DESCRIPTION
This function checks for the following misconfigurations:
- DHCP DNS Credential security risks
- DHCP name protection settings
- DNSUpdateProxy group members
- DNS records with weak permissions
.PARAMETER domainName
The name of the Active Directory domain that we are scanning
.PARAMETER dnsServerName
The name of the DNS server that hosts the ADI-DNS zone in the domain
.EXAMPLE
Invoke-DHCPCheckup -domainName akamai.test -dnsServerName dc2022.akamai.test
.LINK
https://akamai.com/blog/security-research/spoofing-dns-by-abusing-dhcp
#>
[CmdletBinding()]
param
(
[parameter(Mandatory=$True)][String]$domainName,
[parameter(Mandatory=$True)][String]$dnsServerName,
[parameter(ValueFromRemainingArguments=$true)]$invalid_parameter
)
if($invalid_parameter)
{
Write-Host "[*] Error - $($invalid_parameter) is not a valid parameter"
throw
}
Write-Host @"
_____ _ _____ _ _ _____ _____ _____ _ _
|_ _| | | | __ \| | | |/ ____| __ \ / ____| | | |
| | _ ____ _____ | | _____ ______| | | | |__| | | | |__) | | | |__ ___ ___| | ___ _ _ __
| | | '_ \ \ / / _ \| |/ / _ \______| | | | __ | | | ___/| | | '_ \ / _ \/ __| |/ / | | | '_ \
_| |_| | | \ V / (_) | < __/ | |__| | | | | |____| | | |____| | | | __/ (__| <| |_| | |_) |
|_____|_| |_|\_/ \___/|_|\_\___| |_____/|_| |_|\_____|_| \_____|_| |_|\___|\___|_|\_\\__,_| .__/
| |
Microsoft DHCP Server Risk Assessment |_|
By Ori David of Akamai SIG
"@
Write-Host "`n-----------------------------------------`nFinding Active DHCP Servers`n-----------------------------------------`n"
# Get a list of active DHCP servers in the domain
$ActiveDhcpServers = GetActiveActiveDhcpServers
if ($ActiveDhcpServers.Count -ge 1)
{
Write-Host "[*] Found $($ActiveDhcpServers.Count) active DHCP servers:"
foreach ($server in $ActiveDhcpServers)
{
Write-Host "`t* $($server.toUpper())"
}
}
else
{
Write-Host "[*] No active DHCP servers found. Verify that the running user has permissions to access the DHCP servers."
throw
}
# Get a list of strong group members
$strongGroupMembers = GetStrongUsers
Write-Host "`n-----------------------------------------`nChecking DNS Credentials Settings`n-----------------------------------------`n"
$DhcpCredentials = Check-DnsCredentialSettings -ActiveDhcpServers $ActiveDhcpServers -strongGroupsMembers $strongGroupMembers
Write-Host "`n-----------------------------------------`nChecking DHCP Name Protection Settings`n-----------------------------------------`n"
Check-DhcpNameProtectionSettings -ActiveDhcpServers $ActiveDhcpServers
Write-Host "`n-----------------------------------------`nChecking DNSUpdateProxy Group Membership`n-----------------------------------------`n"
Check-DnsUpdateProxyMembership
Write-Host "`n-----------------------------------------`nSearching For Vulnerable DNS Records`n-----------------------------------------`n"
Find-VulnerableDnsRecords -DhcpCredentials $DhcpCredentials
}