cabecera blog BlackArrow

AD CS: de ManageCA a RCE

Introducción

En el artículo anterior, describimos un ejercicio llevado a cabo sobre un cliente donde fue necesaria la ejecución del ataque ESC7 para conseguir escalar privilegios a nivel de dominio abusando del Servicio de Certificados del Directorio Activo (AD CS). Durante este ejercicio de Red Team, se llevó a cabo una profunda investigación que concluyó con la publicación de varios módulos para la herramienta Certify, los cuales permiten abusar de los permisos ManageCA y ManageCertificates tal y como se sugiere en el paper original

Posteriormente a la publicación del artículo hemos continuado con esta investigación, lo que nos ha llevado a descubrir dos nuevas formas de comprometer el propio servidor de la CA (Certificate Authority) abusando del privilegio ManageCA. Estos ataques podrían resultar útiles en diferentes escenarios: 

  • Cuando no existan plantillas de certificados disponibles para usuarios bajo nuestro control, impidiendo la ejecución de los ataques ESC6 y ESC7. 
  • En el caso de que no sea posible llevar a cabo ninguno de los escenarios de ataque propuestos por SpecterOps debido a la imposibilidad de autenticarse en el dominio mediante certificados. Esta fue de los impedimentos encontrados en el ejercicio que se explica en el artículo anterior. 
  • En cualquier situación donde el servidor de la CA y la información contenida en el mismo sean el objetivo a alcanzar. 

Como resultado de la investigación, en este artículo explicamos como comprometer el servidor de la CA abusando la extensión CDP: 

  • Forzando su autenticación hacia un servidor remoto, abriendo la puerta a ataques de NTLM relay, entre otros. 
  • Obteniendo ejecución remota de código en el servidor a través de la escritura de una webshell. 

Además, hemos publicado dos nuevos módulos de Certify que permiten la explotación automática de estos nuevos vectores de ataque. 

Abusando los puntos de distribución de CRL (CDP) 

Un CRL (Certificate Revocation List) es un fichero que contiene los identificadores de los certificados emitidos por la CA que han sido revocados y, por lo tanto, han dejado de ser válidos. Para que la validez de un certificado pueda ser comprobada por los diferentes clientes que hagan uso de este, la CA ha de publicar de manera periódica el CRL en una ruta accesible, lo cual se consigue indicando en su configuración uno o varios CDP: 

Configuración de CDPs en la CA
Configuración de CDPs en la CA

De cara a especificar un nuevo CDP podemos indicar tanto una ruta local como una ruta remota, permitiéndose para la segunda el uso de distintos protocolos de red (HTTP, LDAP, FTP o SMB). Hay que tener en cuenta que a la hora de añadir un nuevo CDP, éste puede ser de lectura, de escritura o mixto: 

  • CDP de lectura (opción “Incluir en la extensión CDP de los certificados emitidos”): significa que la ruta será añadida en la extensión CDP de los certificados emitidos, con el objetivo de indicar a un posible cliente que quiera comprobar la validez de dicho certificado la localización en la que puede encontrar un CRL. Los protocolos HTTP, FTP y LDAP pueden ser utilizados para especificar este tipo de CDPs. 
  • CDP de escritura (opción “Publicar las listas de revocación de certificados (CRL) en esta ubicación”): indicamos a la CA la ruta local o remota donde ha de publicar un CRL. Para especificar una ruta remota, únicamente se pueden utilizar los protocolos LDAP y SMB, además de que el servidor de la CA ha de tener acceso y permiso de escritura en la localización remota indicada. 

Dado que un CRL normal contiene los identificadores de todos los certificados revocados previamente a su publicación (lo que se conoce como un CRL Base), el tamaño de estos ficheros puede llegar a aumentar considerablemente pasado cierto tiempo, lo cual puede provocar un aumento significativo en el tráfico de red generado por parte de los clientes que requieren de su descarga para verificar un certificado.  

Para optimizar este proceso, existe la posibilidad de utilizar un CRL Delta, el cual únicamente contendrá los identificadores de los certificados revocados desde la última publicación de CRL. Además, para que un cliente pueda encontrar la localización de un CRL Delta, la CA permite añadir las rutas donde se ubican en el contenido de los CRL Base (utilizando la opción “Incluir en las CRL”), lo cual será importante a la hora de explotar uno de los vectores de ataque que vamos a comentar a continuación.  

Forzando la autenticación remota 

Como ya hemos comentado, es posible especificar en la CA un CDP de escritura utilizando el protocolo SMB, utilizando para ello la sintaxis file://server/test/file.crl. Esto permite añadir como ruta de publicación de un CRL una carpeta compartida alojada en un equipo remoto aunque este no forme parte del dominio, lo cual tiene sentido dado que los certificados emitidos por una CA pueden necesitar ser verificados más allá de los límites del Directorio Activo.  

El problema radica en que, si la carpeta compartida solicita credenciales de acceso, el servidor de la CA realiza un intento de autenticación para tratar de acceder a la ruta (utilizando NTLM o Kerberos para la autenticación dependiendo de si se introduce una IP o un nombre de equipo como CDP). Esto significa que un usuario con permiso ManageCA puede obtener un desafío NTLM de la cuenta de máquina donde se ejecuta el Servicio de Certificados a través de un CDP que apunte a un equipo bajo su control, abriendo la puerta a la ejecución de ataques de tipo NTLM relay. De la misma manera, en caso de tener bajo control un equipo con Kerberos Unconstrained Delegation sería posible obtener un TGT válido para esta misma cuenta de máquina, permitiendo su suplantación en el dominio. 

Abuso de la extensión para forzar la autenticación NTLM hacia un servidor remoto
Abuso de la extensión para forzar la autenticación NTLM hacia un servidor remoto

Por desgracia, desde que Microsoft publicó el parche MS16-075 dejó de ser posible hacer relay de una autenticación NTLM hacia el mismo destino del que proviene (incluso utilizando protocolos distintos), por lo que no es posible utilizar esta primitiva para, en línea con lo que se hace en el ataque ESC8, redirigir la autenticación al propio servicio web de inscripción de la CA y obtener así un certificado “para sí misma”. Sin embargo, lo que sí podríamos hacer es redirigir la autenticación hacia el servicio web de inscripción de otra CA presente en el entorno permitiendo, ahora sí, obtener un certificado válido para el equipo donde se ejecuta la CA vulnerable: 

ntlmrelayx.py NTLM relay de una CA a otra
NTLM relay de una CA a otra

Si bien este caso de abuso requiere de la presencia de varias CAs, no consideramos que esto sea extraño en entornos de tamaño considerable, donde pueden coexistir varias CAs independientes utilizadas para diferentes tareas o donde puede darse la existencia de una cadena de CAs subordinadas.  

Este proceso de autenticación forzada a través de la configuración de un CDP ha sido implementado en el módulo coerceauth de Certify: 

Uso de Certify para forzar la autenticación NTLM de la CA a una IP remota
Uso de Certify para forzar la autenticación NTLM de la CA a una IP remota

Tras forzar la autenticación, el módulo se encarga de restaurar la configuración previa a la ejecución de la herramienta, evitando de esta manera dejar a la CA apuntando a un CDP inexistente o distinto al utilizado habitualmente. 

Ejecución de código vía despliegue de webshell 

Dado que el método recomendado para descarga y consumo de los CRL es a través del protocolo HTTP, una de las hipótesis planteadas en la investigación fue el abuso de los CDP para desplegar webshells. Además, esta hipótesis cobra más fuerza cuando descubrimos que los CDP, si bien su misión es escribir CRLs (cuya extensión es .crl), permiten escribir ficheros con cualquier extensión

El principal obstáculo para conseguir este objetivo fue obtener la capacidad de controlar parte del contenido del CRL publicado de una manera estable, sobre todo teniendo en cuenta que el código de una webshell habitualmente utiliza caracteres problemáticos como <, % o >.  

Nuestra primera aproximación fue solicitar certificados con el contenido web malicioso insertado en distintos campos con el objetivo de que, al ser revocados, esta información se insertase en el CRL. Sin embargo, no encontramos ningún campo lo suficientemente grande y maleable como para poder llevar a cabo este proceso. 

Tras múltiples intentos, reparamos en la opción comentada anteriormente que permite añadir la ruta de un CRL Delta en el contenido de un CRL Base. A través de esta opción, nos dimos cuenta de que era posible controlar de manera parcial pero estable el contenido de los CRL publicados.  

La unión de estos dos tipos de CDP, permite el despliegue de una webshell:  

  • Un primer CDP que escribiese un CRL en la localización deseada, añadiéndole la extensión adecuada para la webshell (e.g. .asp)  
  • Un segundo CDP malicioso con el contenido de la webshell como ruta, que sería insertado en el CRL generado mediante el primer CDP. 
Escritura parcial de ficheros
Escritura parcial de ficheros

Como primera aproximación, intentamos escribir una webshell ASP de tamaño mínimo en el directorio web local C:\inetpub\wwwroot, el cual es creado cuando se instala cualquiera de los roles web disponibles dentro del Servicio de Certificados, tal y como comentaremos más adelante. 

Error al utilizar el carácter porcentaje
Error al utilizar el carácter porcentaje

Al llevar a cabo este intento de escritura, obtuvimos un error debido al uso del carácter % a la hora de insertar nuestro CDP malicioso con el contenido de la webshell. Esto es debido a que los CDP hacen uso de la funcionalidad conocida como replacement tokens, que permite la inclusión de ciertos campos o cadenas dinámicas en la ruta especificada a través de la escritura del signo % seguido de un número. Dependiendo del valor que siga al porcentaje se insertará un valor u otro, permitiendo de esta manera añadir CDP dinámicos.  

Comparando los CDP que por defecto tiene una CA recién instalada con el valor almacenado en la clave del registro correspondiente (HKLM:\SYSTEM\CurrentControlSet\
Services\CertSvc\Configuration\<CAName>\CRLPublicationURLs) se puede ver que, si bien en el registro se almacenan los replacement tokens, su valor es sustituido por la cadena correspondiente de manera dinámica al ser leída la configuración por la CA: 

Relación de CDP y valor almacenado en el registro
Relación de CDP y valor almacenado en el registro 

Tras hacer ingeniería inversa del binario del servicio de AD CS (certsrv.exe) conseguimos identificar que la función certsrv.exe!myFormatCertsrvStringArray genera un array con los distintos valores para los replacement token y, posteriormente, tras llamar a certsrv.exe!myFormatMessageFromSource acaba invocando a la función FormatMessageW para generar la ruta final. Internamente, esta función es la que lleva a cabo el reemplazo de las ocurrencias de los replacement tokens por el valor correspondiente almacenado en el array. A todo esto, hay que añadirle que la CA también hace uso de la función InternetCanonicalizeUrlW para completar el proceso de filtrado y canonización de la ruta insertada.  

Extracto del decompilado de la función certsrv.exe!myFormatCertsrvStringArray
Extracto del decompilado de la función certsrv.exe!myFormatCertsrvStringArray

Como curiosidad, cabe destacar que la función FormatMessageW permite el uso de cadenas de formato mediante la sintaxis %n!format string!. Podemos confirmar esto, por ejemplo, imprimiendo en un CRL la dirección de memoria del primer elemento dentro del array con los valores de los replacement tokens (e.g. %1!p!):  

Evidencia de la expansión de cadenas de formato
Evidencia de la expansión de cadenas de formato

Si bien esto podría abrir la puerta a Format String Attacks o corrupciones de memoria, no hemos visto forma alguna de introducir caracteres no imprimibles. Dicho esto, sí que es posible provocar una denegación de servicio en la CA al especificar un CDP con una cadena de formato que expanda a un tamaño mayor que 2^16 (e.g. %1!65536s!). 

Tras haber identificado el proceso de formateo y el filtrado de las URLs que lleva a cabo la CA, de cara a utilizar un CDP como contenedor para nuestra webshell, será necesario escapar ciertos caracteres especiales mediante un % para que no desaparezcan tras las sustituciones realizadas por FormatMessageW. Por otro lado, también nos percatamos de que añadiendo un salto de línea (%n) al inicio del CDP con el contenido de la webshell se evita parte del filtrado que lleva a cabo la función InternetCanonicalizeUrlW

Teniendo en cuenta todo lo expuesto anteriormente, decidimos implementar un nuevo módulo de Certify que permita la escritura de un fichero arbitrario en una ruta local o remota a través de los CDP. Para ello, hemos hecho uso una vez más del método DCOM  ICertAdmin2::SetConfigEntry para modificar el valor de la clave de registro CRLPublicationURLs

Uso de Certify para escribir una webshell a partir de un archivo ASP local
Uso de Certify para escribir una webshell a partir de un archivo ASP local 

Además, si no se especifica ningún fichero de entrada a través de la opción /input se escribe una webshell ASP o PHP por defecto según la extensión de la ruta de destino: 

Ejemplo de webshell por defecto generada si no se especifica fichero de entrada
Ejemplo de webshell por defecto generada si no se especifica fichero de entrada 

De esta manera, un usuario con el permiso ManageCA obtiene la capacidad de llevar a cabo una escritura de ficheros arbitraria sobre cualquier ruta local en el servidor de la CA o en cualquier ruta remota donde dicho servidor tenga permisos de escritura. Además, conseguimos controlar parcialmente el contenido de este fichero así como su extensión, permitiendo obtener ejecución remota de código a través del despliegue de una webshell. Por defecto, la webshell es ejecutada en el contexto de la identidad del Application Pool (usuario DefaultAppPool), por lo que se podría elevar privilegios a SYSTEM abusando del privilegio SeImpersonate

Por otro lado, cabe destacar que el responsable de llevar a cabo la escritura de los CRL es la propia CA, cuyo proceso es ejecutado con permisos de NT AUTHORITY\SYSTEM. Esto significa que, a nivel local, podemos escribir en cualquier ruta del equipo y sobrescribir cualquier fichero del sistema. Esto podría ser utilizado de otras maneras que nosotros no hayamos detectado, si bien es cierto que el hecho de no poder controlar por completo el contenido del CRL y de que además no sea posible introducir contenido en formato binario reduce las posibilidades de explotación. En cualquier caso, este vector de ataque podría ser utilizado para corromper de manera remota el servidor de la CA a través de la sobreescritura de archivos del sistema. 

En este punto, el mayor obstáculo que podemos encontrarnos es la posibilidad de que el servidor de la CA no cuente con ningún servicio web donde alojar nuestra webshell. Por ello, hemos confirmado en nuestro laboratorio que la instalación de cualquiera de los diferentes roles de AD CS incluye el despliegue de un servidor IIS, donde el directorio raíz por defecto es C:\inetpub\wwwroot.  

Dependiendo de los roles instalados, será posible utilizar ficheros ASP o ASPX. A su vez, estos roles podrán ser detectados en función de los recursos disponibles:

AD CS paths

Durante nuestras pruebas, hemos detectado que la escritura de una shell en C:\Windows\System32 es detectada inmediatamente por el Windows Defender. 

En caso de que el servidor de la CA no tenga ningún servicio web instalado, todavía queda la posibilidad de que haya un CDP configurado en un servidor web externo, en el que potencialmente también sería posible escribir una webshell. En este artículo de Microsoft se explican varios escenarios en los que podría ser necesario el uso de un servidor aparte, motivo por el que el nuevo módulo permite indicar rutas locales o remotas para la escritura del fichero. 

Para detectar posibles directorios web remotos donde la CA ya esté publicando de manera habitual CRLs y por lo tanto ya cuente con permisos de escritura, se ha añadido la opción /readonly al módulo writefile para leer la lista de CDPs sin llevar a cabo ninguna modificación: 

Uso de Certify para listar los CDPs actuales
Uso de Certify para listar los CDPs actuales 

Detección 

En cuanto a la detección de estos ataques, la mejor opción es activar la auditoría de los eventos relacionados con AD CS tal y como se indica en el paper original. Una vez activados, podemos monitorizar los siguientes eventos: 

  • Evento 4871 (“Certificate Services received a request to publish the certificate revocation list”): dado que la publicación de CRLs suele ser una actividad automática que ocurre cada cierto tiempo establecido en la configuración de la CA, la generación de este evento fuera de dichos períodos de tiempo puede ser un indicador de la actividad maliciosa descrita en este artículo. 
  • Evento 4872 (“Certificate Services published the certificate revocation list (CRL)”): analizando la URL y la extensión del CDP se podrían detectar actividades sospechosas relacionadas con la escritura de archivos maliciosos. 
Evento de seguridad 4872 generado al publicar un CRL
Evento 4872, generado al publicar un CRL

Conclusión

En este segundo artículo dedicado a la infraestructura AD CS hemos descubierto dos nuevas maneras en las que los usuarios con el permiso ManageCA pueden comprometer el servidor de la CA aprovechando la extensión CDP. 

Por otro lado, hemos añadido dos nuevos módulos a Certify que permiten la explotación automática de los nuevos vectores de ataque expuestos en este artículo. Estas funcionalidades así como las publicadas en el artículo anterior pueden ser encontradas en el repositorio de BlackArrow

Más artículos de la serie AD CS

Este artículo forma parte de una serie de articulos sobre AD CS

  1. AD CS: automatizando el ataque ESC7
  2. AD CS: de ManageCA a RCE