This is a function from my PowerShellAccessControl module that is used to take the SDDL or binary form of a security descriptor (SD) as input and output an object that resembles an SD from Get-Acl. Right off the bat, let me say that this thing is missing a lot of functionality. It currently only works with discretionary ACLs (the ACLs that control access to objects). Also, the script methods that it exposes aren’t very discoverable via Get-Member since they were added with Add-Member. This thing really deserves to have a true C# object be its output, and I’ll probably go in that direction at some point in the future.
Even with its flaws, I still think it’s a very useful function. Here’s the functionality of a Get-Acl SD that it currently mimics:
- Access property lists each ACE
- AccessToString property lists the value of the Access property in a single string
- Sddl property gives the SDDL representation of the entire SD object
- GetSecurityDescriptorBinaryForm method gives the binary form of the entire SD object
- AddAccessRule method takes an ACE as input and adds it to the discretionary ACL
- RemoveAccessRule takes either an index to an ACE or an ACE object and removes it from the discretionary ACL
So, if you can get to either the SDDL or binary form of a SD, you can pass that to this function and get an object that is much more readable, and that has the ability to change the discretionary ACL.
Besides the two SD input parameters (SDDL or BinarySD; you can only use one at a time), the function has two parameters: AccessMaskEnumeration and Path.
The AccessMaskEnumeration is an optional parameter that the output object can use to translate the access rights of the object into a readable string. In an SD, all access rights are stored as a bitmask. If you don’t have an enumeration to do the translating of rights, you’ll just see an integer in each ACE where the access rights should go. You’ll still be able to see what users/groups have rights to the object, but you won’t know what rights they have (unless you know what the numeric values mean). The function comes with several enumerations for different types of objects, and I’m going to devote a blog post to creating one for printers to show how you can easily make your own for future use. Here is a list of the enumerations that the module comes with:
PS> [System.AppDomain]::CurrentDomain.GetAssemblies().GetTypes() |
Where-Object FullName -match "^PowerShellAccessControl\."
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True LogicalShareRights System.Enum
True True WmiNamespaceRights System.Enum
True True WsManAccessRights System.Enum
True True ServiceAccessRights System.Enum
The Path parameter is another optional parameter. It gives you the ability to look at the output SD object and tell where it came from. This is very useful when you have more than one SD object and you use the Get-AccessControlEntry function from the module.
Let’s go over some examples!
Here’s a way to get the WMI namespace access rights for the root\cimv2 namespace (NOTE: I’m using the GetSD WMI method on the class directly instead of a different function that I included in the module called Get-Win32SecurityDescriptor. I’ll explain why I used this WMI method directly when I cover the Get-Win32SecurityDescriptor function).
PS> # This should be run from an elevated PS prompt:
PS> $BinarySD = Get-CimClass __SystemSecurity -Namespace root\cimv2 |
Invoke-CimMethod -MethodName GetSD |
Select-Object -ExpandProperty SD
PS> $SD = New-AdaptedSecurityDescriptor -BinarySD $BinarySD -Path "root\CIMV2 NameSpace"
PS> $SD.Access | ft
ObjectRights AccessControlType IdentityReference IsInherited InheritanceFlags PropagationFlags
------------ ----------------- ----------------- ----------- ---------------- ----------------
393279 AccessAllowed BUILTIN\Administrators True ContainerInherit None
19 AccessAllowed NT AUTHORITY\NETWORK SERVICE True ContainerInherit None
19 AccessAllowed NT AUTHORITY\LOCAL SERVICE True ContainerInherit None
19 AccessAllowed NT AUTHORITY\Authenticated Users True ContainerInherit None
PS> # Notice the ObjectRights listed are numeric. Let's try this again with an enumeration:
PS> $SD = New-AdaptedSecurityDescriptor -BinarySD $BinarySD -Path "root\CIMV2 Namespace" -AccessMaskEnumeration ([PowerShellAccessControl.WmiNamespaceRights])
PS> $SD.Access | ft # Some columns are dropped:
ObjectRights AccessControlType IdentityReference IsInherited
------------ ----------------- ----------------- -----------
... RemoteEnable, ReadSecurity, EditSecurity AccessAllowed BUILTIN\Administrators True
EnableAccount, ExecuteMethods, ProviderWrite AccessAllowed NT AUTHORITY\NETWORK SERVICE True
EnableAccount, ExecuteMethods, ProviderWrite AccessAllowed NT AUTHORITY\LOCAL SERVICE True
EnableAccount, ExecuteMethods, ProviderWrite AccessAllowed NT AUTHORITY\Authenticated Users True
Show the ACEs for the microsoft.powershell session configuration:
PS> # This should be run from an elevated PS prompt
PS> dir WSMan:\localhost\Plugin\microsoft.powershell\Resources -Recurse |
Where Name -eq Sddl |
ForEach-Object {
New-AdaptedSecurityDescriptor -Sddl $_.Value -Path $_.PsPath -AccessMaskEnumeration ([PowerShellAccessControl.WsManAccessRights])
} |
Select -exp Access
ObjectRights : Full
AccessControlType : AccessAllowed
IdentityReference : BUILTIN\Administrators
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
ObjectRights : Full
AccessControlType : AccessAllowed
IdentityReference : BUILTIN\Remote Management Users
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
Show the AccessToString property for all of the shares on a remote computer named ‘server’ (I’m using another function from the module that I will devote a blog post to soon):
PS> Get-CimInstance -ClassName Win32_LogicalShareSecuritySetting -ComputerName server |
Get-Win32SecurityDescriptor -Sddl |
New-AdaptedSecurityDescriptor -AccessMaskEnumeration ([PowerShellAccessControl.LogicalShareRights]) |
Select Path, AccessToString |
fl
Path : \\server\root\cimv2:Win32_LogicalShareSecuritySetting.Name="share01"
AccessToString : Everyone AccessAllowed FullControl
BUILTIN\Users AccessAllowed Read
Path : \\server\root\cimv2:Win32_LogicalShareSecuritySetting.Name="share02"
AccessToString : BUILTIN\Administrators AccessAllowed FullControl
Everyone AccessAllowed FullControl
Show all ACEs from any object named Sddl in the local WSMan configuration (I’m using another function that will be described later this week; you’ll have to run this and see the results):
PS> # This should be run from an elevated PS prompt
PS> dir WSMan:\localhost -Recurse |
Where Name -eq Sddl |
ForEach-Object {
New-AdaptedSecurityDescriptor -Sddl $_.Value -Path $_.PsPath -AccessMaskEnumeration ([PowerShellAccessControl.WsManAccessRights])
} |
Get-AccessControlEntry |
Out-GridView
So, if you can get access to a hard to read SDDL form or an impossible to read binary form of an SD, you should be able to turn it into something that’s readable with New-AdaptedSecurityDescriptor. If you have an enumeration that translates the object rights into a readable form, that’s even better (but not necessary). You can then use that object to audit and/or modify the SD (those are for another day).
I hope that you find this function useful. Please try it out and tell me what you think. Stay tuned for more posts on the module, including more on this function!