Offense/ACLAudits.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
function Get-CSVulnerableServicePermission {
<#
.SYNOPSIS
 
Lists each group granted potentially vulnerable service access permissions.
 
Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause
 
.DESCRIPTION
 
Get-CSVulnerableServicePermission is used to perform service ACL audits at scale. For each computer, it iterates through the service and associated file permissions and groups potentially vulnerable access rights granted to each user. This can be used to quickly identify if members of lower privileged groups can elevate privileges via service misconfigurations.
 
.PARAMETER IncludeDrivers
 
Specifies that driver file permissions should be queried in addition to user-mode services. Read the notes section for more information about the limitations of driver audits.
 
.PARAMETER NoProgressBar
 
Do not display a progress bar. This parameter is designed to be used with wrapper functions.
 
.PARAMETER CimSession
 
Specifies the CIM session to use for this cmdlet. Enter a variable that contains the CIM session or a command that creates or gets the CIM session, such as the New-CimSession or Get-CimSession cmdlets. For more information, see about_CimSessions.

.PARAMETER OperationTimeoutSec

Specifies the amount of time that the cmdlet waits for a response from the computer.
 
By default, the value of this parameter is 0, which means that the cmdlet uses the default timeout value for the server.
 
If the OperationTimeoutSec parameter is set to a value less than the robust connection retry timeout of 3 minutes, network failures that last more than the value of the OperationTimeoutSec parameter are not recoverable, because the operation on the server times out before the client can reconnect.
 
.OUTPUTS
 
CimSweep.ServiceACLAudit
 
Outputs objects representing each group granted potentially vulnerable service and file access rights.
 
.NOTES
 
Driver services (Win32_SystemDriver) do not expose the GetSecurityDescriptor method so service ACLs cannot be obtained. File permissions can be obtained, however. Just be mindful of this if you notice that driver services appear to not be granted any service access rights.
 
Service ACL sweep across a large amount of hosts will take a long time.
#>


    [CmdletBinding()]
    [OutputType('CimSweep.ServiceACLAudit')]
    param (
        [Switch]
        $IncludeDrivers,

        [Switch]
        $NoProgressBar,

        [Alias('Session')]
        [ValidateNotNullOrEmpty()]
        [Microsoft.Management.Infrastructure.CimSession[]]
        $CimSession,

        [UInt32]
        [Alias('OT')]
        $OperationTimeoutSec
    )

    BEGIN {
        if (-not $PSBoundParameters['CimSession']) {
            $CimSession = ''
            $CIMSessionCount = 1
        } else {
            $CIMSessionCount = $CimSession.Count
        }

        $CurrentCIMSession = 0

        $UserModeServices = @{}
        if (-not $IncludeDrivers) {
            $UserModeServices['UserModeServices'] = $True
        }

        $Timeout = @{}
        if ($PSBoundParameters['OperationTimeoutSec']) { $Timeout['OperationTimeoutSec'] = $OperationTimeoutSec }
    }

    PROCESS {
        foreach ($Session in $CimSession) {
            $ComputerName = $Session.ComputerName
            if (-not $Session.ComputerName) { $ComputerName = 'localhost' }

            if (-not $PSBoundParameters['NoProgressBar']) {
                # Display a progress activity for each CIM session
                Write-Progress -Id 1 -Activity 'CimSweep - Service ACL sweep' -Status "($($CurrentCIMSession+1)/$($CIMSessionCount)) Current computer: $ComputerName" -PercentComplete (($CurrentCIMSession / $CIMSessionCount) * 100)
                $CurrentCIMSession++
            }

            $CommonArgs = @{}

            if ($Session.Id) { $CommonArgs['CimSession'] = $Session }

            $UserGrouping = @{}

            Get-CSService -NoProgressBar -IncludeAcl -IncludeFileInfo @UserModeServices @CommonArgs @Timeout | ForEach-Object {
                $ServiceName = $_.Name

                if (-not $PSBoundParameters['NoProgressBar']) {
                    Write-Progress -Id 2 -ParentId 1 -Activity " Current service:" -Status $ServiceName
                }

                foreach ($FileDACL in $_.FileInfo.ACL.Access) {
                        $GroupName = $FileDACL.IdentityReference.ToString()

                        if (-not $UserGrouping.ContainsKey($GroupName)) {
                            $Permissions = [PSCustomObject] @{
                                ServiceCanStart = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                                ServiceCanStop = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                                ServiceCanChangeConfig = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                                ServiceHasAllAccess = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                                FileCanChangePermissions = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                                FileCanDelete = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                                FileCanModify = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                                FileCanTakeOwnership = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                                FileCanWrite = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                                FileCanWriteData = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                                FileHasFullControl = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            }
                        } else {
                            $Permissions = $UserGrouping[$GroupName]
                        }

                        $UserGrouping[$GroupName] = $Permissions
        
                        if (($FileDACL.AccessControlType -eq 'Allow') -and $FileDACL.FileSystemRights.HasFlag([Security.AccessControl.FileSystemRights]::ChangePermissions)) {
                            $UserGrouping[$GroupName].FileCanChangePermissions.Add($ServiceName)
                        }

                        if (($FileDACL.AccessControlType -eq 'Allow') -and $FileDACL.FileSystemRights.HasFlag([Security.AccessControl.FileSystemRights]::Delete)) {
                            $UserGrouping[$GroupName].FileCanDelete.Add($ServiceName)
                        }

                        if (($FileDACL.AccessControlType -eq 'Allow') -and $FileDACL.FileSystemRights.HasFlag([Security.AccessControl.FileSystemRights]::Modify)) {
                            $UserGrouping[$GroupName].FileCanModify.Add($ServiceName)
                        }

                        if (($FileDACL.AccessControlType -eq 'Allow') -and $FileDACL.FileSystemRights.HasFlag([Security.AccessControl.FileSystemRights]::TakeOwnership)) {
                            $UserGrouping[$GroupName].FileCanTakeOwnership.Add($ServiceName)
                        }

                        if (($FileDACL.AccessControlType -eq 'Allow') -and $FileDACL.FileSystemRights.HasFlag([Security.AccessControl.FileSystemRights]::Write)) {
                            $UserGrouping[$GroupName].FileCanWrite.Add($ServiceName)
                        }

                        if (($FileDACL.AccessControlType -eq 'Allow') -and $FileDACL.FileSystemRights.HasFlag([Security.AccessControl.FileSystemRights]::WriteData)) {
                            $UserGrouping[$GroupName].FileCanWriteData.Add($ServiceName)
                        }

                        if (($FileDACL.AccessControlType -eq 'Allow') -and $FileDACL.FileSystemRights.HasFlag([Security.AccessControl.FileSystemRights]::FullControl)) {
                            $UserGrouping[$GroupName].FileHasFullControl.Add($ServiceName)
                        }
                }

                foreach ($DACL in $_.ACL.Access) {
                    $RightsType = $DACL.Rights.GetType()

                    $GroupName = $DACL.IdentityReference.ToString()

                    if (-not $UserGrouping.ContainsKey($GroupName)) {
                        $Permissions = [PSCustomObject] @{
                            ServiceCanStart = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            ServiceCanStop = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            ServiceCanChangeConfig = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            ServiceHasAllAccess = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            FileCanChangePermissions = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            FileCanDelete = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            FileCanModify = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            FileCanTakeOwnership = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            FileCanWrite = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            FileCanWriteData = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                            FileHasFullControl = (New-Object 'Collections.ObjectModel.Collection`1[System.String]')
                        }
                    } else {
                        $Permissions = $UserGrouping[$GroupName]
                    }

                    $UserGrouping[$GroupName] = $Permissions
        
                    if (($DACL.AccessControlType -eq 'Allow') -and $DACL.Rights.HasFlag($RightsType::Start)) {
                        $UserGrouping[$GroupName].ServiceCanStart.Add($ServiceName)
                    }

                    if (($DACL.AccessControlType -eq 'Allow') -and $DACL.Rights.HasFlag($RightsType::Stop)) {
                        $UserGrouping[$GroupName].ServiceCanStop.Add($ServiceName)
                    }

                    if (($DACL.AccessControlType -eq 'Allow') -and $DACL.Rights.HasFlag($RightsType::ChangeConfig)) {
                        $UserGrouping[$GroupName].ServiceCanChangeConfig.Add($ServiceName)
                    }

                    if (($DACL.AccessControlType -eq 'Allow') -and $DACL.Rights.HasFlag($RightsType::AllAccess)) {
                        $UserGrouping[$GroupName].ServiceHasAllAccess.Add($ServiceName)
                    }
                }
            }

            foreach ($Group in $UserGrouping.Keys) {
                $Permissions = $UserGrouping[$Group]

                [PSCustomObject] @{
                    PSTypeName = 'CimSweep.ServiceACLAudit'
                    GroupName = $Group
                    CanStartService = $Permissions.ServiceCanStart
                    CanStopService = $Permissions.ServiceCanStop
                    CanChangeServiceConfig = $Permissions.ServiceCanChangeConfig
                    AllAccessToService = $Permissions.ServiceHasAllAccess
                    CanChangePermissionsOfFile = $Permissions.FileCanChangePermissions
                    CanDeleteFile = $Permissions.FileCanDelete
                    CanModifyFile = $Permissions.FileCanModify
                    CanTakeOwnershipOfFile = $Permissions.FileCanTakeOwnership
                    CanWriteToFile = $Permissions.FileCanWrite
                    CanWriteDataToFile = $Permissions.FileCanWriteData
                    FullControlOfFile = $Permissions.FileHasFullControl
                    PSComputerName = $Session.ComputerName
                }
            }
        }
    }
}