Weak Registry Permissions for Windows Privilege Escalation
Windows services store their configuration in the registry under HKLM\System\CurrentControlSet\Services\. If your user has write access to a service's registry key, you can change the ImagePath value to point to any binary: effectively the same as service binary hijacking but without needing to touch the filesystem ACL of the binary itself. Changing ServiceDLL in service parameters achieves the same via DLL injection.
This technique works when filesystem ACLs are locked but registry ACLs are misconfigured. Third-party software installations frequently create service keys with overly broad permissions. Enterprise environments with legacy software are especially prone. The attack uses only reg.exe commands, avoiding the need to drop additional tools to disk. Registry modification events log under Security Event ID 4657, but many environments do not alert on this. Check this vector before reaching for noisier techniques.
You need write access to the service key and the ability to restart the service. Without restart capability, the modified binary does not execute until a reboot or a service manager trigger. Confirm both before building your payload.
Enumerate service registry keys with
accesschkor PowerShell ACL inspectionModify
ImagePathorServiceDllto point to your payloadRestart the service to trigger execution as the service account
Restore the original registry value after escalation
Prerequisites Check
Step 1: Find Weak Registry Permissions on Windows Services
accesschk outputs one line per writable key, showing the permission mask and the key path. The service name appears after Services\ in the path. Run it against your username and against the standard low-privilege groups separately. A group-based check can catch permissions a username-only query misses when the ACE targets the group.
Using accesschk:
Look for KEY_SET_VALUE, KEY_ALL_ACCESS, or WRITE_DAC. KEY_SET_VALUE is the minimum: it lets you write any named value under the key. That is sufficient to overwrite ImagePath. KEY_ALL_ACCESS is a superset of that. WRITE_DAC lets you modify the ACL on the key, so you can grant yourself further rights before proceeding. Any of these three is enough to proceed.
The PowerShell script below uses native Windows ACL inspection and needs no additional binary. Use it when accesschk is unavailable or blocked by endpoint controls. It reports the same information: service name, identity, and the effective rights.
Using PowerShell:
# Check registry permissions on all services
$services = Get-ChildItem "HKLM:\System\CurrentControlSet\Services"
foreach ($service in $services) {
$acl = Get-Acl $service.PSPath
foreach ($access in $acl.Access) {
if ($access.IdentityReference -match "Users|Everyone|Authenticated" -and
$access.RegistryRights -match "SetValue|FullControl|WriteKey") {
Write-Host "WRITABLE: $($service.Name) | $($access.IdentityReference) | $($access.RegistryRights)"
}
}
}
Step 2: Confirm the Service Runs as SYSTEM
Not every service runs as LocalSystem. A service running as a virtual account or domain user still allows hijacking. The access you gain depends entirely on that account's rights. A service running as NT AUTHORITY\NetworkService gives you network credentials but no local admin. Confirm the account before building your payload. If the service runs as a domain account, check whether it has privileged access elsewhere before deciding to proceed.
ObjectName of LocalSystem or StartName of LocalSystem confirms SYSTEM execution. A service showing NT AUTHORITY\LocalService runs with restricted local rights and no outbound network access. A domain account may still be worth targeting. Check whether it carries admin rights or privileged ACLs elsewhere in the environment.
Before modifying ImagePath, record the original value using reg query. You need it for cleanup. Use a path under C:\Windows\Temp for your payload. That directory is writable by all users and reachable from the SYSTEM context. Avoid paths under user profiles: SYSTEM may not have read access depending on the profile ACL.
Step 3a: Modify ImagePath
Change the service's binary path to your payload. The service manager reads ImagePath on each start. The change takes effect when the service next starts.
Step 3b: Modify ServiceDLL
Some services load a DLL specified in Parameters\ServiceDll rather than a standalone binary. Services with an ImagePath containing svchost.exe -k use this pattern. The Parameters subkey is sometimes writable even when the parent key is not, so check it separately. Replacing the DLL is more discreet than replacing a binary. The outer process stays as svchost.exe, which is a trusted Windows host process. Endpoint detection is less likely to flag a DLL load from a known host process. If this key is writable:
Your DLL must export ServiceMain for services that use this pattern. Use a proxy DLL as described in https://hackindex.io/platforms/windows/privilege-escalation/windows-dll-hijacking-for-privilege-escalation. A DLL that does not export ServiceMain causes the service to fail to start. The service manager logs the failure and does not restore the original DLL automatically. The service stays down until you manually restore the registry value.
Step 4: Create and Transfer Payload
Use -f exe-service with msfvenom. A plain executable does not send the service readiness signal the manager expects. The manager marks the service as failed after a short timeout. The exe-service format wraps the payload in a service stub that handles the handshake. Transfer the payload before modifying any registry value. Verify the file exists at the exact target path before restarting the service.
Step 5: Restore Original Configuration
Restore the original ImagePath immediately after your payload executes. A service pointing to a missing or broken binary fails on the next start or health check. Failed starts generate Event ID 7023 and 7024 entries in the System log. On monitored systems, repeated failures can trigger alerts. Restart the service after restoring the value and confirm it enters a running state. If you modified ServiceDll, restore that value in the same step. Leave the service running cleanly to minimize your detection surface.
References
-
Service ConfigurationDOCS: Service Configuration, docs.microsoft.com/en-us/windows/win32/services/service-configuration-programs (opens in new tab)
Microsoft Docs Registry key structure for Windows services including ImagePath and ServiceDll.
-
accesschkDOCS: accesschk, docs.microsoft.com/en-us/sysinternals/downloads/accesschk (opens in new tab)
Sysinternals Registry key permission enumeration with KEY_SET_VALUE detection.