itm4n / PrivescCheck

Privilege Escalation Enumeration Script for Windows
BSD 3-Clause "New" or "Revised" License
2.91k stars 422 forks source link

Service Control Manager with permissive rights check #14

Closed phackt closed 3 years ago

phackt commented 3 years ago

Hello again,

So in a training lab, they implemented a (not so common) privesc scenario where the service control manager itself suffers from permissive rights (see https://docs.microsoft.com/en-us/windows/win32/services/service-security-and-access-rights).

This builtin service can not be listed in the function Get-ServiceList which enumerates all keys in the reg path HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services.

How i was able to spot it:

PS C:\> sc.exe sdshow scmanager

D:(A;;CC;;;AU)(A;;CCLCRPRC;;;IU)(A;;CCLCRPRC;;;SU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;S-1-5-21-948911695-1962824784-4291460660-1124)(A;;KA;;;BA)(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1024-528118966-3876874398-709513571-1907873084-3598227634-3698730060-278077788-3990600205)

PS C:\> ConvertFrom-SddlString -Sddl "D:(A;;CC;;;AU)(A;;CCLCRPRC;;;IU)(A;;CCLCRPRC;;;SU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;S-1-5-21-948911695-1962824784-4291460660-1124)(A;;KA;;;BA)(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1024-528118966-3876874398-709513571-1907873084-3598227634-3698730060-278077788-3990600205)" | select -ExpandProperty DiscretionaryAcl
NT AUTHORITY\INTERACTIVE: AccessAllowed (CreateDirectories, GenericExecute, ListDirectory, ReadPermissions, WriteExtendedAttributes)
NT AUTHORITY\SERVICE: AccessAllowed (CreateDirectories, GenericExecute, ListDirectory, ReadPermissions, WriteExtendedAttributes)
NT AUTHORITY\Authenticated Users: AccessAllowed (ListDirectory)
NT AUTHORITY\SYSTEM: AccessAllowed (CreateDirectories, GenericExecute, ListDirectory, ReadPermissions, Traverse, WriteExtendedAttributes)
BUILTIN\Administrators: AccessAllowed (ChangePermissions, CreateDirectories, Delete, ExecuteKey, FullControl, GenericExecute, GenericWrite, ListDirectory, ReadExtendedAttributes, ReadPermissions, TakeOwnership, Traverse, WriteData, WriteExtendedAttributes, WriteKey)
DOM\REDACTEDGroup: AccessAllowed (ChangePermissions, CreateDirectories, Delete, ExecuteKey, FullControl, GenericExecute, GenericWrite, ListDirectory, ReadExtendedAttributes, ReadPermissions, TakeOwnership, Traverse, WriteData, WriteExtendedAttributes, WriteKey)
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES: AccessAllowed (ListDirectory)
: AccessAllowed (ListDirectory)

Do you think it could be a good idea to add this kind of check ? i can help / work on it also but before i would like to confirm it s relevant from your point of view.

Cheers !

itm4n commented 3 years ago

Hello!

At first, I thought that it was an edge case but then, I did some research. I found quite a lot of resources that explain how to modify the DACL of the Service Manager (official documentation of third-party products and forums). Such manipulation is dangerous and prone to errors, which could explain why it was used as a privesc scenario in this lab environment.

The problem is that the Service Manager is not really a Service per se. So, finding a way to add it to the Service list seems complicated. Besides, doing so would probably mess with the existing checks. However, I can create a dedicated check to query and test its DACL. This would also enable me to easily improve it in the future if I also need to check the owner and the primary group for example.

If already found how to query the DACL of the SCM in C as an SDDL string. This is pretty simple and straightforward.

C:\Users\Lab-User\Desktop>TestApplication.exe
[*] SC Manager handle: 0x0000023ED4102820
[*] Required size: 212
[*] Security descriptor @: 0x0000023ED41039A0
[*] QueryServiceObjectSecurity OK
[*] SC Manager DACL:
D:(A;;CC;;;AU)(A;;CCLCRPRC;;;IU)(A;;CCLCRPRC;;;SU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;BA)(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1024-528118966-3876874398-709513571-1907873084-3598227634-3698730060-278077788-3990600205)

Here is what I need to do next:

  1. Convert the C code into C#/powershell.
  2. Convert the SDDL string into an ACL object.
  3. Check the permissions of the current user.

This is definitely doable! 🙂

I'll keep you posted.

itm4n commented 3 years ago

Hello again!

In the end, it was easier than I thought because I was able to reuse some code I already implemented in other functions.

First, I added a helper function - Get-ServiceManagerDacl - which allows me to retrieve the DACL of the SCM. Basically, it's more or less a C#/PowerShell implementation of the code I originally wrote in C. It invokes OpenSCManager and QueryServiceObjectSecurity to get a Security Descriptor representing the DACL, which I can then convert to a list of ACE objects.

Then, I implemented a new check: Invoke-SCMPermissionsCheck. This function simply iterates the list of ACEs which is returned by Get-ServiceManagerDacl. For each ACE, it checks if the identity matches one of the current user's (user and group SIDs) and if it corresponds to a privileged right such as CreateService or AllAccess. I also had to create a custom enumeration in order to get a proper match between the access mask and the access rights that are specific to the SCM.

Here is the result. In this example, I invoked the function as a local admin just to make sure it works as expected.

PS C:\Users\Lab-User\Desktop> Invoke-SCMPermissionsCheck

AceType      : AccessAllowed
AccessRights : AllAccess
IdentitySid  : S-1-5-32-544
IdentityName : BUILTIN\Administrators

And, if you want to get all the ACEs, you can invoke Get-ServiceManagerDacl.

PS C:\Users\Lab-User\Desktop> Get-ServiceManagerDacl

AccessRights       : Connect
BinaryLength       : 20
AceQualifier       : AccessAllowed
IsCallback         : False
OpaqueLength       : 0
AccessMask         : 1
SecurityIdentifier : S-1-5-11
AceType            : AccessAllowed
AceFlags           : None
IsInherited        : False
InheritanceFlags   : None
PropagationFlags   : None
AuditFlags         : None

AccessRights       : Connect, Read
BinaryLength       : 20
AceQualifier       : AccessAllowed
IsCallback         : False
OpaqueLength       : 0
AccessMask         : 131093
SecurityIdentifier : S-1-5-4
AceType            : AccessAllowed
AceFlags           : None
IsInherited        : False
InheritanceFlags   : None
PropagationFlags   : None
AuditFlags         : None

AccessRights       : Connect, Read
BinaryLength       : 20
AceQualifier       : AccessAllowed
IsCallback         : False
OpaqueLength       : 0
AccessMask         : 131093
SecurityIdentifier : S-1-5-6
AceType            : AccessAllowed
AceFlags           : None
IsInherited        : False
InheritanceFlags   : None
PropagationFlags   : None
AuditFlags         : None

AccessRights       : Connect, ModifyBootConfig, Read
BinaryLength       : 20
AceQualifier       : AccessAllowed
IsCallback         : False
OpaqueLength       : 0
AccessMask         : 131125
SecurityIdentifier : S-1-5-18
AceType            : AccessAllowed
AceFlags           : None
IsInherited        : False
InheritanceFlags   : None
PropagationFlags   : None
AuditFlags         : None

AccessRights       : AllAccess
BinaryLength       : 24
AceQualifier       : AccessAllowed
IsCallback         : False
OpaqueLength       : 0
AccessMask         : 983103
SecurityIdentifier : S-1-5-32-544
AceType            : AccessAllowed
AceFlags           : None
IsInherited        : False
InheritanceFlags   : None
PropagationFlags   : None
AuditFlags         : None

AccessRights       : Connect
BinaryLength       : 24
AceQualifier       : AccessAllowed
IsCallback         : False
OpaqueLength       : 0
AccessMask         : 1
SecurityIdentifier : S-1-15-2-1
AceType            : AccessAllowed
AceFlags           : None
IsInherited        : False
InheritanceFlags   : None
PropagationFlags   : None
AuditFlags         : None

AccessRights       : Connect
BinaryLength       : 56
AceQualifier       : AccessAllowed
IsCallback         : False
OpaqueLength       : 0
AccessMask         : 1
SecurityIdentifier : S-1-15-3-1024-528118966-3876874398-709513571-1907873084-3598227634-3698730060-278077788-3990600205
AceType            : AccessAllowed
AceFlags           : None
IsInherited        : False
InheritanceFlags   : None
PropagationFlags   : None
AuditFlags         : None

Thanks for suggesting the idea! This was a nice little challenge. 🙂

And, if you still have access to your lab environment, it would be very interesting to see if the script is now able to detect the vulnerability.

phackt commented 3 years ago

Wow you've already done the job, chapeau l'artiste !. I will test it in the lab i think tomorrow, and i will have a look at what interesting rights you are looking for dealing with the SCM. Really a nice work.

Thanks a lot !

phackt commented 3 years ago

I just tested in my lab environment and the privesc got spotted ! Thanks again @itm4n, it works like a charm

itm4n commented 3 years ago

Nice! Glad to hear that! 😎