¿Necesita Cloud Computing? Empiece ahora

Aprovechamiento de una vulnerabilidad crítica de suplantación en CryptoAPI de Windows

Akamai Wave Blue

escrito por

Tomer Peled y Yoni Rozenshein

January 25, 2023

Tomer Peled

escrito por

Tomer Peled

Tomer Peled es investigador de seguridad en Akamai. En su trabajo diario, lleva a cabo investigaciones que incluyen desde las vulnerabilidades hasta los aspectos internos del sistema operativo. En su tiempo libre, le gusta cocinar, practicar krav magá y jugar en su PC.

Onda azul de Akamai

escrito por

Yoni Rozenshein

Yoni Rozenshein es un desarrollador de bajo nivel e investigador con amplia experiencia de Akamai. Durante los últimos años, ha estado desarrollando controladores (y, por tanto, depurando pantallas azules y mensajes "kernel panic") en Guardicore (adquirido por Akamai). Sus pasiones son los aspectos internos del sistema operativo, las matemáticas y la criptografía, y no es difícil hablar con él sobre ellos durante horas.

Los certificados desempeñan un papel fundamental en la verificación de identidad online, lo que hace que esta vulnerabilidad resulte lucrativa para los atacantes.
Los certificados desempeñan un papel fundamental en la verificación de identidad online, lo que hace que esta vulnerabilidad resulte lucrativa para los atacantes.

Edición y contribuciones adicionales de Tricia Howard

Resumen ejecutivo

  • El grupo de inteligencia sobre seguridad de Akamai ha analizado recientemente una vulnerabilidad crítica en CryptoAPI de Windows, revelada a Microsoft por la Agencia Nacional de Seguridad (NSA) y el Centro Nacional de Ciberseguridad (NCSC) de EE. UU.

  • La vulnerabilidad, que ha recibido el código CVE-2022-34689, obtuvo una puntuación de CVSS de 7,5. Se aplicó el parche en agosto de 2022, pero se anunció públicamente en el Patch Tuesday de octubre de 2022.

  • Según Microsoft, la vulnerabilidad permite que un atacante se haga pasar por una entidad legítima. 

  • La causa principal del error es la suposición de que la clave de índice de caché de certificados, que está basada en MD5, no tiene colisiones. Desde 2009, se sabe que la resistencia a la colisión de MD5 está rota

  • El flujo de ataque es doble. La primera fase requiere seleccionar un certificado legítimo, modificarlo y entregar la versión modificada a la víctima. La segunda fase implica la creación de un nuevo certificado cuyo MD5 colisione con el certificado legítimo modificado, y el uso del nuevo certificado para falsificar la identidad del sujeto del certificado original.

  • Hemos buscado aplicaciones en circulación que utilizan CryptoAPI de una forma vulnerable a este ataque de suplantación. Hasta ahora, hemos descubierto que se pueden usar para efectuar ataques en versiones antiguas de Chrome (v48 y anteriores) y aplicaciones basadas en Chromium. Creemos que existen objetivos más vulnerables en circulación y nuestra investigación sigue en curso.

  • Hemos descubierto que menos del 1 % de los dispositivos visibles de los centros de datos tienen parches, por lo que el resto queda desprotegido de la explotación de esta vulnerabilidad.

  • En esta entrada del blog, ofrecemos una explicación detallada del flujo y las consecuencias potenciales del ataque, así como una prueba de concepto (PoC) que demuestra el ataque completo. También proporcionamos una consulta de OSQuery para detectar versiones vulnerables de la biblioteca de CryptoAPI.

Antecedentes

Hace tres meses, en nuestro análisis de Patch Tuesday de 2022, compartimos una descripción básica de una vulnerabilidad de suplantación crítica en CryptoAPI de Windows: CVE-2022-34689. Según Microsoft, esta vulnerabilidad permite a un atacante “falsificar su identidad y realizar acciones, incluidas la autenticación o firma de código, como si se tratara del certificado de destino”.

CryptoAPI es la API estándar de Windows para gestionar todo lo relacionado con la criptografía. En concreto, gestiona los certificados, desde su lectura y análisis hasta su validación frente a las entidades de certificación (CA) verificadas. Los navegadores también utilizan CryptoAPI para la validación de certificados TLS, un proceso que da como resultado el icono de candado que todo el mundo debe comprobar.

Sin embargo, la verificación de certificados no es exclusiva de los exploradores y también la utilizan otros clientes de TLS, como la autenticación web de PowerShell, curl, wget, administradores de FTP, EDR y muchas otras aplicaciones. Además, los certificados de firma de código se verifican en ejecutables y bibliotecas, y los certificados de firma de controladores se verifican al cargar controladores. Como se puede imaginar, una vulnerabilidad en el proceso de verificación de certificados es muy lucrativa para los atacantes, ya que les permite enmascarar su identidad y eludir las protecciones de seguridad críticas.

Esta no es la primera vez que la Agencia de Seguridad Nacional de EE. UU. informa de una vulnerabilidad en CryptoAPI. En 2020, se detectó CurveBall (CVE-2020-0601) y se informó sobre ello. Al explotar CurveBall o CVE-2022-34689 se puede suplantar la identidad pero, si bien CurveBall afecta a muchas aplicaciones, CVE-2022-34689 tiene más requisitos previos y, por lo tanto, tiene un alcance más limitado de objetivos vulnerables.

Detalles de la vulnerabilidad

Para analizar la vulnerabilidad, primero intentamos localizar el código revisado. Utilizamos BinDiff, una conocida herramienta de difusión binaria, para observar los diversos cambios de código en CryptoAPI. En crypt32.dll, solo ha cambiado una función: CreateChainContextFromPathGraph. Como parte de esta función, se comparan dos certificados: uno que se recibe como entrada y otro que reside en la caché de certificados de la aplicación receptora (más adelante mencionaremos en detalle esta caché).

La inspección de los cambios revela que las comprobaciones de mincmp se añadieron a la función en dos ubicaciones (figura 1).

La inspección de los cambios reveló que las comprobaciones de memcmp se agregaron a la función en dos ubicaciones (figura 1). Fig. 1: Código agregado a CreateChainContextFromPathGraph en el parche (resaltado)

Antes del parche, la función determinaba si un certificado recibido ya estaba en la caché (y, por lo tanto, estaba verificado) únicamente basándose en su huella digital de MD5. Después del parche, la adición de mincmp requiere que el contenido real de los dos certificados coincida completamente. 

En este punto, nuestra teoría se basaba en que si un atacante pudiera entregar un certificado malicioso cuyo MD5 colisiona con uno que ya estuviera en la caché de certificados de la víctima, podría omitir la comprobación de vulnerabilidad y hacer que su certificado malicioso pasara por uno de confianza (figura 2).

Flujo de ataque Fig. 2: Flujo de ataque de alto nivel

Caché de certificados de CryptoAPI

CryptoAPI puede utilizar una caché para los certificados finales recibidos con el fin de mejorar el rendimiento y la eficiencia. Este mecanismo está desactivado de forma predeterminada. Para activarlo, el desarrollador de la aplicación debe pasar determinados parámetros a CertGetCertificateChain, la función de la API de Windows que finalmente conduce al código vulnerable (figura 3).

CertGetCertificateChain, la función de la API de Windows que lleva al código vulnerable (figura 3). Fig. 3: Declaración de la función CertGetCertificateChain

CertGetCertificateChain recibe varios parámetros interesantes:

  • hChainEngine : objeto configurable utilizado para controlar la forma en que se validan los certificados

  • pCertContext : contexto del certificado de entrada, una estructura de datos creada con el certificado de entrada por la función CertCreateCertificateContext de WinAPI

  • dwFlags : indicadores que especifican una configuración adicional

  • ppChainContext : objeto de salida que contiene (entre otros campos) el estado de confianza; es decir, el veredicto de verificación de la cadena

Para activar el mecanismo de almacenamiento en caché para los certificados finales, el desarrollador debe definir el indicador CERT_CHAIN_CACHE_END_CERT en dwFlags, o crear un motor de cadena personalizado y establecer el indicador CERT_CHAIN_CACHE_END_CERT en su campo dwFlags .

Para comprender cómo se implementa y utiliza la caché, echemos un vistazo a la función FindIssuerObject que extrae el certificado de la caché. En términos generales, la función se comporta de la siguiente manera:

  1. Calcula el índice de depósito del certificado de entrada en la caché basándose en los cuatro bytes menos significativos de su huella digital de MD5.

  2. Si existe en la caché, la función compara la huella digital de MD5 completa del certificado almacenado en caché y el certificado de entrada.

  3. Si las huellas digitales coinciden (se produce un acierto de caché), el certificado de entrada se considera de confianza y se devuelve. Desde ese momento, la aplicación utiliza los atributos del certificado de entrada (como la clave pública, el emisor, etc.) y no el certificado almacenado en caché.

  4. Si las huellas digitales no coinciden (se produce un fallo de caché), se pasa al siguiente certificado del depósito, se compara su huella digital se MD5 y se repite.

Microsoft confía inherentemente en la validez de los certificados almacenados en caché y no realiza ninguna comprobación de validez adicional tras haber encontrado un certificado final en la caché. Esto, por sí mismo, es un supuesto de trabajo razonable. Sin embargo, el código asume que dos certificados son idénticos si sus huellas digitales de MD5 coinciden. Esta es una suposición incorrecta que se puede aprovechar con fines maliciosos, y fue la génesis del parche.

Para apoyar nuestra hipótesis, escribimos una pequeña aplicación que utiliza CertGetCertificateChain y depuramos el flujo de verificación de certificados en crypt32.dll. Con WinDbg, simulamos un escenario en el que la huella digital de MD5 de nuestro propio certificado (autofirmado) coincide con un certificado legítimo que ya estaba en la caché. Como se muestra en la figura 4, el certificado que creamos se consideró de confianza.

Como se muestra en la figura 4, el certificado que creamos se consideró de confianza. Fig. 4: Registros que muestran que CryptoAPI confió en el certificado almacenado en caché y en el certificado que nosotros creamos

Al omitir una comprobación, podríamos hacer que Windows creyera que nuestro certificado malicioso era legítimo.

Cómo se puede aprovechar la vulnerabilidad

La construcción de un certificado con una huella digital de MD5 que coincide exactamente con un valor de MD5 dado se denomina ataque de preimagen, y esto es inviable desde el punto de vista informático incluso hoy en día. Sin embargo, es posible generar de forma eficaz dos certificados con dos prefijos seleccionados que acabarán teniendo las mismas huellas digitales de MD5; este tipo de ataque se denomina colisión de prefijos elegidos.

Al elegir esta ruta, tendremos que proporcionar de alguna manera dos certificados a la aplicación de la víctima. Un certificado se firmará, verificará y almacenará en caché correctamente (lo denominaremos “certificado de destino modificado”). Se generará de forma que facilite un ataque de colisión de prefijo elegido. El segundo certificado (que denominaremos “certificado malicioso”) contendrá la identidad falsificada. Colisionará con la huella digital de MD5 del primer certificado (figura 5).

Colisionará con la huella digital de MD5 del primer certificado (figura 5). Fig. 5: La huella digital de MD5 del certificado malicioso colisionará con la del certificado de destino modificado

Suplantación de certificados mediante colisiones de MD5

Las colisiones de MD5 nos llevan unos 14 años atrás, a un momento en el que Beyoncé publicó “Single Ladies”, Obama fue elegido presidente por primera vez y las colisiones de MD5 colisiones se utilizaron inicialmente para falsificar certificados SSL. Hay una diferencia importante entre ese primer ataque y el escenario que tratamos hoy: el escenario anterior atacaba firmas de MD5 , pero en la vulnerabilidad actual estamos tratando con huellas digitales de MD5 . Comprendamos la diferencia.

Según RFC 5280, sección 4.1, un certificado es una secuencia ASN.1 con dos secciones (figura 6):

  • tbsCertificate (o certificado “a firmar”, TBS): es la parte que contiene todos los detalles relacionados con la identidad (asunto, clave pública, número de serie, EKU, etc.). Esta es la parte que se firma.

  • signatureAlgorithm y signatureValue : estos campos comprenden la firma del TBS.

   Certificate  ::=  SEQUENCE  {
        tbsCertificate       TBSCertificate,
        signatureAlgorithm   AlgorithmIdentifier,
        signatureValue       BIT STRING  }

Fig. 6: Secuencia ASN.1 que define los certificados

Una firma de certificado es por tanto una estructura integrada dentro del certificado, que únicamente firma la parte TBS del certificado. Por otro lado, una huella digital de certificado es un hash de todo el certificado (incluida la firma).

Por lo tanto, si pudiéramos modificar cualquier parte del certificado que esté fuera del TBS sin invalidar el certificado, a continuación, modificaríamos la huella digital sin cambiar la firma. Si el analizador analiza la firma correctamente y el TBS no cambia, el certificado se considerará válido y firmado, aunque haya cambiado la estructura completa del certificado (figura 7).

 Si el analizador analiza la firma correctamente y el TBS no cambia, el certificado se considerará válido y firmado, aunque haya cambiado la estructura completa del certificado (figura 7). Fig. 7: Los datos añadidos fuera del TBS no afectan a la validez del certificado

Colisiones MD5 de prefijo elegido: Una breve descripción general

Supongamos que tiene dos cadenas arbitrarias, A y B, de la misma longitud. Entonces, dos cadenas, C y D, se podrían calcular de manera eficiente, así:

MD5(A || C) = MD5(B || D),

donde || indica la concatenación de cadenas.

El resultado final de MD5 sería el mismo, al igual que el interno de MD5 tras adjuntar C o D. Por lo tanto, si toma cualquier sufijo E, entonces tendría

MD5(A || C || E) = MD5(B || D || E)

(siempre que se añada el mismo sufijo E en ambos lados).

Espacio para bloques de colisión

Como atacantes, necesitaremos generar un certificado que parezca válido pero que también contenga espacio para bloques de colisión (las cadenas C y D en la explicación anterior). Esto nos permitirá crear nuestro certificado malicioso (con la misma huella digital de MD5), que le proporcionaremos a continuación.

Según RFC 5280, sección 4.1.1.2, la estructura de signatureAlgorithm es

  AlgorithmIdentifier  ::=  SEQUENCE  {
        algorithm               OBJECT IDENTIFIER,
        parameters              ANY DEFINED BY algorithm OPTIONAL  }

El campo de parámetros para el algoritmo RSA (basado en RFC 3279) “SHALL be the ASN.1 type NULL”. En otras palabras: RSA no utiliza parámetros de firma, sino que toma NULL como valor. ¿Es posible que CryptoAPI ignore este campo para las firmas RSA?

Para insertar bytes de marcador de posición en este campo (como preparación para bloques de colisión), hemos intentado cambiar su tipo ASN.1 de NULL a BIT STRING. Si probamos esto con CryptoAPI y OpenSSL, funciona : el certificado sigue considerándose válido. La firma no cambia ni se rompe porque no modificamos el TBS. (Por supuesto, la huella digital de MD5 cambia).

Colisiones de huellas digitales con el certificado de MD5

Ahora, podemos combinarlo todo y proporcionar una receta para manipular un certificado existente, ya firmado, para colisionar con la huella digital de MD5 de un certificado malicioso.

  1. Seleccione un certificado final firmado por RSA legítimo, como el certificado TLS de un sitio web (nuestro “certificado de destino”).

  2. Modifique cualquier campo interesante (asunto, extensiones, EKU, clave pública, etc.) en la parte TBS del certificado para crear el certificado malicioso. Nota: No tocamos la firma, por lo que el certificado malicioso está firmado incorrectamente. La modificación de la clave pública es importante aquí, ya que permite al atacante firmar como certificado malicioso.

  3. Modifique el campo de parámetros signatureAlgorithm de ambos certificados, de modo que haya suficiente espacio para colocar los bloques de colisión de MD5 (C y D en la explicación anterior) comenzando en la misma desviación de ambos certificados.

  4. Trunque los dos certificados en la posición en la que se colocarán los bloques de colisión de MD5.

  5. Realice un cálculo de colisión de prefijo elegido de MD5 y copie el resultado en los certificados.

  6. Concatene el valor de firma del certificado legítimo (sufijo E en la explicación anterior) a ambos certificados incompletos.

Un ejemplo real

Con nuestra comprensión de las colisiones de MD5, ahora podemos intentar aprovechar esta CVE con un objetivo real. Entre las numerosas aplicaciones que comprobamos, encontramos un objetivo vulnerable: Chrome v48. (Esta aplicación es vulnerable simplemente porque pasa el indicador CERT_CHAIN_CACHE_END_CERT a CertGetCertificateChain). Otras aplicaciones basadas en Chromium de ese momento también son vulnerables a esta CVE.

Para aprovechar esta vulnerabilidad, primero tuvimos que crear dos certificados con la misma huella digital de MD5, y utilizamos HashClash (figura 8).

Para poder aprovechar esta vulnerabilidad, primero necesitamos crear dos certificados que tengan la misma huella digital de MD5, lo que hicimos con HashClash (figura 8). Fig. 8: Generación de dos certificados con la misma huella digital de MD5 mediante el prefijo de colisión seleccionado

Entonces tuvimos que dar con una forma de inyectar nuestro certificado de destino modificado en la caché de Chrome. No fue tarea fácil, ya que es imposible servir un certificado sin conocer su clave privada.

En TLS 1.2, hay dos fases de verificación relevantes:

  1. El mensaje Server Key Exchange : este mensaje solo lo puede crear alguien que conozca la clave privada del certificado, ya que está firmado por el certificado

  2. El mensaje Server Handshake Finished : este mensaje incluye una verificación antimanipulación de todos los mensajes de protocolo de enlace anteriores

(TLS 1.3 es diferente y no nos hemos centrado en ello).

Recuerde que en la primera fase del ataque queremos inyectar el certificado modificado en la caché de certificados final de Chrome.

Mediante un script Python como proxy, realizamos un ataque de máquina intermediaria (MITM):

  1. Nuestro servidor MITM malicioso se comunica con el servidor real y refleja los primeros mensajes del protocolo de enlace TLS a la víctima.

  2. En el mensaje Server Certificate, nuestro servidor MITM malicioso modifica el mensaje del servidor real y sustituye el certificado de destino real por el certificado modificado.

  3. El mensaje de Server Key Exchange se puede reflejar sin cambios.

  4. Nuestro servidor malicioso no puede reenviar simplemente el mensaje de Server Handshake Finished, ya que el protocolo de enlace se ha manipulado. Por lo tanto, terminamos la conexión.

Para comprobar el mensaje de Server Key Exchange, Chrome debe cargar el certificado modificado con CryptoAPI y, por lo tanto, se inyectará en la caché. Chrome no trata la interrupción de la conexión como un problema de seguridad TLS; podría tratarse de un problema de red aleatorio. Chrome intenta volver a conectarse, y esta vez, en lugar de reflejar los mensajes del sitio web real, el servidor malicioso proporcionará un sitio web con el certificado malicioso. Chrome omitirá el proceso de verificación completo porque creerá que el certificado ya está en la caché. El resultado será una visita perfecta a un sitio web de Microsoft aparentemente legítimo (figuras 9 y 10). El flujo de explotación completo se puede ver en nuestro vídeo.

Visita perfecta a un sitio web de Microsoft aparentemente legítimo (figuras 9 y 10). Fig. 9: Flujo de ataque completo en Chrome v48
Certificado malicioso Fig. 10: El vulnerable Chrome confía en nuestro certificado malicioso

Detección

Proporcionamos una OSQuery para detectar versiones vulnerables de crypt32.dll, la biblioteca vulnerable (figura 11). Los clientes de Akamai Guardicore Segmentation pueden utilizar la función Insight junto con esta consulta para buscar activos vulnerables.

Tenga en cuenta que para que un activo sea vulnerable necesita tener una versión sin parches de crypt32.dll y ejecutar una aplicación vulnerable. (Por ahora, solo hemos detectado que Chrome v48 sea vulnerable).

  WITH product_version AS (
  WITH os_minor AS (
    WITH os_major AS (
      SELECT substr(product_version, 0, instr(product_version, ".")) as os_major, substr(product_version, instr(product_version, ".")+1) as no_os_major_substr
      FROM file
      WHERE path = "c:\windows\system32\crypt32.dll"
    )
    SELECT substr(no_os_major_substr, instr(no_os_major_substr, ".")+1) as no_os_minor_substr, substr(no_os_major_substr, 0, instr(no_os_major_substr, ".")) as os_minor, os_major
    FROM os_major
  )
  SELECT
    CAST(substr(no_os_minor_substr, instr(no_os_minor_substr, ".")+1) AS INTEGER) AS product_minor,
    CAST(substr(no_os_minor_substr, 0, instr(no_os_minor_substr, ".")) AS INTEGER) AS product_major,
    CAST(os_minor AS INTEGER) AS os_minor,
    CAST(os_major AS INTEGER) AS os_major
  FROM os_minor
)
SELECT
  CASE 
    WHEN os_major = 6 AND os_minor = 3 THEN "not supported"
    WHEN (
        (product_major = 20348 AND product_minor >= 887)
        OR
        (product_major = 17763 AND product_minor >= 3287)
        OR
        (product_major = 14393 AND product_minor >= 5291)
        OR
        (product_major >= 19041 AND product_minor >= 1889)
    )
    THEN
      "patched"
    ELSE
      "not patched"
  END is_patched
FROM product_version

Conclusión

Los certificados desempeñan un papel fundamental en la verificación de identidad online, lo que hace que esta vulnerabilidad resulte lucrativa para los atacantes. Sin embargo, aunque fue marcada como crítica, a la vulnerabilidad solo se le dio una puntuación CVSS de 7,5. Creemos que esto se debe al alcance limitado de las aplicaciones vulnerables y los componentes de Windows en los que se cumplen los requisitos previos para la vulnerabilidad.

Dicho esto, todavía hay mucho código que utiliza esta API y que podría estar expuesto a esta vulnerabilidad, lo que garantiza un parche incluso para versiones descontinuadas de Windows, como Windows 7.

Le aconsejamos que aplique a sus servidores y terminales Windows el parche de seguridad más reciente publicado por Microsoft. Para los desarrolladores, otra opción para mitigar esta vulnerabilidad es utilizar otras WinAPI para comprobar la validez de un certificado antes de utilizarlo, como CertVerifyCertificateChainPolicy. Tenga en cuenta que las aplicaciones que no utilizan el almacenamiento en caché de certificados finales no son vulnerables.

Nuestro código de validación técnica se puede encontrar en nuestro repositorio de GitHub. También puede estar al día de todas las publicaciones del grupo de inteligencia sobre seguridad de Akamai a través de nuestra cuenta de Twitter.



Akamai Wave Blue

escrito por

Tomer Peled y Yoni Rozenshein

January 25, 2023

Tomer Peled

escrito por

Tomer Peled

Tomer Peled es investigador de seguridad en Akamai. En su trabajo diario, lleva a cabo investigaciones que incluyen desde las vulnerabilidades hasta los aspectos internos del sistema operativo. En su tiempo libre, le gusta cocinar, practicar krav magá y jugar en su PC.

Onda azul de Akamai

escrito por

Yoni Rozenshein

Yoni Rozenshein es un desarrollador de bajo nivel e investigador con amplia experiencia de Akamai. Durante los últimos años, ha estado desarrollando controladores (y, por tanto, depurando pantallas azules y mensajes "kernel panic") en Guardicore (adquirido por Akamai). Sus pasiones son los aspectos internos del sistema operativo, las matemáticas y la criptografía, y no es difícil hablar con él sobre ellos durante horas.