PrivEsc: Abusing the Service Control Manager for Stealthy & Persistent LPE
Living off the Land
Earlier this week, Grzegorz Tworek posted a really cool way of establishing a persistent LPE that I haven’t previously seen in the wild. From a (compromised) privileged account we can abuse the Service Control Manager to allow any arbitrary non-administrative user to have full SYSTEM permissions on a machine persistently by feeding an overly permissive ACL to the service control manager with sdset
.
Some background knowledge
Understanding what this attack is doing will require some light reading into both sdset as well as Microsoft’s Security Descriptor Definition Language (SDDL). But… to summarize both articles for you, we just need to know the format of a Security Descriptor string contains tokens to indicate each of the four main components of a security descriptor: owner (O:), primary group (G:), DACL (D:), SACL (S:), as well as tokens for the access-control entity. Security Descriptors can contain any combination of these tokens, and not all are necessarily required as we will demonstrate below.
Per the tweet, we just need to run sc.exe sdset scmanager D:(A;;KA;;;WD)
from an elevated Windows shell (i.e. something with local admin privilege). Before I demonstrate the entire attack, let’s break this down a little more.
D:(A;;KA;;;WD) … wat.
If you’re like me, and have a very limited knowledge of how these Microsoft SDDL tokens work or what each portion represents, we should take some time to understand a little more. (You know, learn something new and all that jazz)
So what is this string actually representing? Let’s break each component down. To start, we should know the general access control entry syntax:
ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid;(resource_attribute)
- D: Discretionary ACL (DACL)
- A DACL identifies users and groups who are allowed or denied access to an object.
- A; Access Allowed (
ace_type
)- This first segment represents the beginning of the access-control entry (ACE). An ACL contains a list of ACEs. An ACE defines access to an object for a specific user or group or defines the types of access that generate system-administration messages or alarms for a specific user or group. The user or group is identified by a security identifier (SID).
ace_flags
is empty- KA; KEY_ALL_ACCESS (
rights
)- This token can also refer to Domain key credential administrators if used in the context of a SID, which isn’t at all confusing. All we need to know is this gives access to all registry keys related to SDDL.
object_guid
is emptyinherit_object_guid
is empty- WD - Security Principal of Everyone (
account_sid
)- Below you’ll find a table of some common security principals we can reference in an SDDL string.
ACE Security Principals
Abbreviation | Security Principal |
---|---|
AU | Authenticated Users |
BA | Built-in administrators |
SY | Local System |
BU | Built-in users |
WD | Everyone |
TL;DR
The TL;DR here is, this command grants everyone, all, permissions on the service control manager. Meaning, I can (as a non-privileged user) create a service that will allow me to execute any arbitrary command as if I were SYSTEM due to the scmanager
running as SYSTEM context. There’s a million articles you can read like this one if you want more technical references.
Example Attack Flow
Examining our normal user’s permissions.
So to start, we will use a non-privileged account and output the user information. Here I’m just basically demonstrating that the account we will privesc from has no administrative privileges.
Modify the permissions of SCMANAGER via SDSET
Next, we execute the command to modify the scmanager
ACL from our elevated command prompt. This must be done with an administrative account (the one that’s been compromised):
title: DACL Modification of Service Control Manager via sdset
id: 8998782b-66de-44e7-8335-305e2dd431b3
status: experimental
description: This rule detects usage of sdset to modify the DACL of the service-control manager service, scmanager.
references:
- https://twitter.com/0gtweet/status/1628720819537936386?cxt=HHwWhIC87Ze9sJotAAAA
tags:
- attack.persistence
- attack.privilege_escalation
author: Gabriel De Jesus (0xv1n)
date: 2023/02/28
logsource:
product: windows
category: process_creation
detection:
selection:
Image|endswith:
- '\sc.exe'
CommandLine|contains|all:
- ' sdset '
- ' scmanager '
- ' D:(A;;KA;;;WD) '
condition: selection
fields:
- Image
- CommandLine
falsepositives:
- Unknown
level: high
Confirm changes took place
We know the command was successful due to the feedback returned by the OS, but if we want to check the Security Descriptor for a service, we can do so with sdshow <service_name>
. In this case, we confirm that scmanager
indeed has the new security descriptor.
Additionally (and thanks to Grzegorz!), we can run sc.exe sdshow scmanager showrights
to enumerate the rights of the service. This essentially maps the tokens to their security descriptors and allows us to more easily understand the rights a particular service has:
Create a malicious Service for persistent LPE
We can now create a service from our non-privileged account to add our account to the local admin group of this machine:
sc create LPE displayName= "LPE" binPath= "C:\Windows\System32\net.exe localgroup Administrators nonpriv-user /add" start= auto
Restart Machine
At this point, all we need to do is restart the machine and allow the service control manager to execute our new service with SYSTEM privileges. Once it comes back online, we should see that our account now is added to local admins.
The best part of this mechanism, is that even if a smart admin removes the local admin privilege on the account, we still have the service. If the admin removes the service, we still have the ability to create a new one. The remediation for this type of persistence would be reverting the DACL of scmanager
to a hardened state.
Persistent Local Privilege Escalation
And now, any time we want, we can spawn an arbitrary process with administrator privileges:
Hope this helps!