-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathGet-VulnerableGPO.ps1
244 lines (202 loc) · 11.3 KB
/
Get-VulnerableGPO.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
<#
.Synopsis
v1. Written by Darren Mar-Elia (github.com/gpoguy), Semperis (https://semperis.com), 2018. Searches GPOs that have sensitive security settings in them, that grant Authenticated Users read access
.DESCRIPTION
Searches GPOs that have sensitive security settings in them, that grant Authenticated Users read access (i.e. World Readable GPOs)
The goal is to call out GPOs that contains settings that grant privileged access, so that their delegation can be modified to prevent
attackers from easily determining where privileged access is granted in your environment.
This function requires the free SDM GPMC PowerShell Module, which can be downloaded from: https://s3.amazonaws.com/sdmsoftware.com/dl/SDM-GPMC-Module2.0Setup.zip
which is used to parse settings across suspect GPOs. The function requires read access to GPOs in order to succeeed.
Time to run varies based on how big the environment is, but took about 35 minutes to run in a GPO test environment of 500 GPOs, with a robust collection of settings
.EXAMPLE
Get-VulnerableGPO
.EXAMPLE
Get-VulnerableGPO -Domain cpandl.com
#>
Add-Type -AssemblyName System.DirectoryServices.Protocols
Import-Module SDM-GPMC
$secGPOs
$lugsGPOs
function Get-VulnerableGPO
{
[CmdletBinding()]
[Alias()]
[OutputType([int])]
Param
(
# Provide a DNS domain name other than the default one
[Parameter(Mandatory=$false,
ValueFromPipelineByPropertyName=$true,
Position=0)]
$Domain
)
Begin
{
#$startTime = [DateTime]::Now
#$startTime
if ($Domain -eq $null)
{
$Domain = $env:USERDNSDOMAIN
}
$DN = GetDN $Domain
$GPCContainer = "CN=Policies, CN=System, "+$DN
#first, find the GPOs that contain security or GP Preferences Local Users and Groups by searching for the appropriate CSEs
$secGPOs =ADFind $Domain "displayName","gpcMachineExtensionNames" $GPCContainer "OneLevel" "(&(objectClass=groupPolicyContainer)(gpcMachineExtensionNames=*{827D319E-6EAC-11D2-A4EA-00C04F79F83A}*))" 1000
$lugsGPOS = ADFind $Domain "displayName","gpcMachineExtensionNames" $GPCContainer "OneLevel" "(&(objectClass=groupPolicyContainer)(gpcMachineExtensionNames=*{17D89FEC-5C44-4972-B12D-241CAEF74509}*))" 1000
}
Process
{
#now use SDM GP module to find vulnerable GPOs (i.e. grant Authn Users Read access and also contain privileged policy settings)
#we will look for the following policies that grant some kind of privileged access
#Restricted Groups policy that controls Local Administrators or Power Users
#User Rights Assignment that grants Debug Progams, Load/Unload Device Drivers and Take Ownership
#GPP Local Users and Groups policy that controls Local Administrators or Power Users
#First set up the setting Paths we care about looking for:
$AreasPol =@{}
$AreasPref = @{}
$AreasPol.Add("Computer Configuration|Policies|Windows Settings|Security Settings|Restricted Groups|BUILTIN\Administrators|Members","Restricted Groups--Administrators")
$AreasPol.Add("Computer Configuration|Policies|Windows Settings|Security Settings|Restricted Groups|BUILTIN\Power Users|Members","Restricted Groups--Power Users")
$AreasPol.Add("Computer Configuration|Policies|Windows Settings|Security Settings|Local Policies|User Rights Assignment|Debug programs","User Rights Assignment--Debug Programs")
$AreasPol.Add("Computer Configuration|Policies|Windows Settings|Security Settings|Local Policies|User Rights Assignment|Load and unload device drivers","User Rights Assignment--Load/Unload Device Drivers")
$AreasPol.Add("Computer Configuration|Policies|Windows Settings|Security Settings|Local Policies|User Rights Assignment|Take ownership of files or other objects","User Rights Assignment--Take Ownership")
$AreasPref.Add("Computer Configuration|Preferences|Control Panel Settings|Local Users and Groups|Group: Administrators (built-in)|Add members","GPP Local Users & Groups--Administrators")
$AreasPref.Add("Computer Configuration|Preferences|Control Panel Settings|Local Users and Groups|Group: Power Users (built-in)|Add members","GPP Local Users & Groups--Power Users")
#first process the security CSE GPOs
foreach ($foundGPO in $secGPOs)
{
#now check to see if the GPO has vulnerable delegation, which means Authn Users, Read or ReadApply--otherwise we don't care
if ($foundGPO.Attributes -eq $null)
{
continue
}
$perms = Get-SDMGPOSecurity -DisplayName $foundGPO.Attributes["displayName"][0] -Domain $Domain
[bool]$found = $false
foreach ($ACE in $perms)
{
if ($ACE.Trustee -eq "NT AUTHORITY\Authenticated Users" -and ($ACE.Permission -eq "permGPOApply" -or $ACE.Permission -eq "permGPORead"))
{
$found = $true
break
}
}
if ($found -eq $false)
{
continue
}
$object = New-Object PSObject
Add-Member -InputObject $object -MemberType NoteProperty -Name GPOName -Value ""
Add-Member -InputObject $object -MemberType NoteProperty -Name PolicyArea -Value ""
Add-Member -InputObject $object -MemberType NoteProperty -Name Permission -Value ""
#generate settings for current GPO
$settings = Out-SDMGPSettings -Domain $Domain -DisplayName $foundGPO.Attributes["displayName"][0] -Areas "Security"
#now search for our settings
foreach ($item in $settings)
{
foreach ($area in $AreasPol.Keys)
{
if ($item.SettingPath -eq $area)
{
if ($object.PolicyArea -ne $AreasPol[$area]) #only add this one if we haven't found it already
{
$object.GPOName = $foundGPO.Attributes["displayName"][0]
$object.PolicyArea = $AreasPol[$area]
$object.Permission = "Authenticated Users"+":"+$ACE.Permission
$object
break
}
}
}
}
}
# now process the LUGs settings
foreach ($foundGPO in $lugsGPOs)
{
if ($foundGPO.Attributes -eq $null)
{
continue
}
#now check to see if the GPO has vulnerable delegation, which means Authn Users, Read or ReadApply--otherwise we don't care
$perms = Get-SDMGPOSecurity -DisplayName $foundGPO.Attributes["displayName"][0] -Domain $Domain
[bool]$found = $false
foreach ($ACE in $perms)
{
if ($ACE.Trustee -eq "NT AUTHORITY\Authenticated Users" -and ($ACE.Permission -eq "permGPOApply" -or $ACE.Permission -eq "permGPORead"))
{
$found = $true
break
}
}
$object = New-Object PSObject
Add-Member -InputObject $object -MemberType NoteProperty -Name GPOName -Value ""
Add-Member -InputObject $object -MemberType NoteProperty -Name PolicyArea -Value ""
Add-Member -InputObject $object -MemberType NoteProperty -Name Permission -Value ""
$settings = Out-SDMGPSettings -Domain $Domain -DisplayName $foundGPO.Attributes["displayName"][0] -Areas "Local Users and Groups"
#now search for our settings
foreach ($item in $settings)
{
foreach ($area in $AreasPref.Keys)
{
if ($item.SettingPath.Contains($area))
{
if ($object.PolicyArea -ne $AreasPref[$area]) #only add this one if we haven't found it already
{
$object.GPOName = $foundGPO.Attributes["displayName"][0]
$object.PolicyArea = $AreasPref[$area]
$object.Permission = "Authenticated Users"+":"+$ACE.Permission
$object
break
}
}
}
}
}
}
End
{
# $endTime = [DateTime]::Now
# $endTime
}
}
function ADFind #using System.DS.Protocols to do LDAP searches of GPCs
{
param(
[string]$dnsDomain,[string[]]$attributes, [string]$baseDN,[System.DirectoryServices.Protocols.SearchScope]$scope, [string]$filter,[int]$pageSize
)
$results = new-object "System.Collections.Generic.List[System.DirectoryServices.Protocols.SearchResultEntry]"
[System.DirectoryServices.Protocols.LdapConnection] $conn = new-object System.DirectoryServices.Protocols.LdapConnection($dnsDomain)
[System.DirectoryServices.Protocols.SearchRequest] $search = new-object System.DirectoryServices.Protocols.SearchRequest($baseDN,$filter,$scope,$attributes)
[System.DirectoryServices.Protocols.PageResultRequestControl] $pageRequest = new-object System.DirectoryServices.Protocols.PageResultRequestControl($pageSize)
$search.Controls.Add($pageRequest)
[System.DirectoryServices.Protocols.SearchOptionsControl] $searchOptions = new-object System.DirectoryServices.Protocols.SearchOptionsControl([System.DirectoryServices.Protocols.SearchOption]::DomainScope)
$search.Controls.Add($searchOptions)
[int] $pageCount = 0
while ($true)
{
$pageCount++
[System.DirectoryServices.Protocols.SearchResponse] $response = [System.DirectoryServices.Protocols.SearchResponse]$conn.SendRequest($search)
[System.DirectoryServices.Protocols.PageResultResponseControl] $pageResponse = [System.DirectoryServices.Protocols.PageResultResponseControl]$response.Controls[0]
if ($response.Entries.Count -gt 0)
{
foreach ($entry in $response.Entries)
{
$results.Add($entry)
}
}
if ($pageResponse.Cookie.Length -eq 0)
{
break
}
$pageRequest.Cookie = $pageResponse.Cookie
}
return $results
}
function GetDN #calculates Distinguished Name
{
param(
[string]$dnsDomain
)
$domContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext([System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Domain, $dnsDomain);
$selectedDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($domContext);
return $selectedDomain.GetDirectoryEntry().Properties["distinguishedName"][0].ToString();
}
Get-VulnerableGPO