Analytics

martes, 7 de abril de 2020

Seguridad SSL/TLS: LUCKY 13

¿Qué es LUCKY 13?

El ataque Lucky Thirteen es un ataque de tiempo criptográfico contra implementaciones del protocolo Transport Layer Security (TLS), explota un problema de diseño de este protocolo y permite obtener información en texto plano a partir de un texto cifrado.

El nombre proviene del hecho de que los paquetes TLS cifrados tienen trece bytes de encabezado que se consumen en uno de los cálculos criptográficos en los que se basa TLS.

El nombre de esta técnica roza la ironía, ya que en cierto sentido, el número trece es de la mala (o buena) suerte. Sin embargo, cuando se pone en práctica el ataque, “Lucky Twelve” sería un nombre más acertado, ya que los encabezados de 12 bytes harían que el ataque sea aún más eficiente.

Características y Conceptos

Este es más un ataque teórico debido a la escrupulosidad de la sincronización diferencial de la respuesta del servidor a través de la red. Sin embargo, los investigadores Nadhem J. AlFardan y Kenny Paterson demostraron el ataque en el laboratorio con resultados fehacientes.

El ataque es aplicable con el modo de cifrado  CBC (Cadena de Cifrado Por Bloques) y con el esquema MAC (Código de Autenticación de Mensaje). El cálculo TLS MAC incluye 13 bytes de información de encabezado (5 bytes de encabezado TLS más 8 bytes de número de secuencia TLS) y es por eso que se llama Lucky 13, el cual explota una falla mencionada en la RFC 5246.
   
Antes de profundizar en el ataque, primero comprendamos los componentes básicos.
  • CBC (Cadena de Cifrado Por Bloques)

    Este modo de operación comienza dividiendo el texto sin formato en bloques de tamaño específico, dependiendo del algoritmo de cifrado simétrico subyacente; 8 para DES y 16 para AES. Cada bloque de texto sin formato realiza primero una operación lógica de disyunción exclusiva (XOR) con el bloque de texto cifrado anterior antes de cifrarse, de esta manera, cada bloque de texto cifrado depende de todos los bloques de texto sin formato procesados hasta ese punto. Para que cada mensaje sea único, se debe utilizar un vector de inicialización en el primer bloque:

    Cadena de Bloques de Cifrado (referencia)

    Si el primer bloque tiene el índice 1, la fórmula matemática para el cifrado CBC es:

    Fórmula Matemática Para Cifrado CBC

  • Ejemplo de Cifrado:
    Cifrado de un Mensaje (referencia)
  • MAC

    El código de autenticación de mensaje (MAC) se utiliza para confirmar que el mensaje proviene del remitente declarado y no ha sido alterado.

    El modus operandi de este algoritmo es el siguiente:
    1. Se calcula el MAC del texto sin formato.
    2. El resultado se agrega al texto plano.
    3. Se añaden bytes de relleno de modo que se convierta en múltiplo integral de la longitud del bloque.

    El último byte del último bloque indica cuánto relleno hay y todo el byte de relleno debe contener el mismo valor numérico. El relleno debe consistir en "p+1" bytes del mismo valor "p". Por ejemplo, si el último byte es 0x00, entonces será solo 1 byte de 0x00 y ese será el byte en sí mismo. Si el byte de relleno es 0x01, entonces serán 2 bytes 0x01 0x01 del mismo valor 0x01.
  • Cifrado TLS

    Para un mensaje "M" (payload), primero se agrega un "HDR||SQN" (encabezado TLS de 13 bytes) y luego se calcula una etiqueta "MAC tag" según el algoritmo negociado (MD5 / SHA1 / SHA256). Después de eso, se agrega relleno para hacerlo múltiplo integral de tamaño de bloque (8 bytes para DES y 16 para AES).

    Cálculo de MAC y relleno TLS (referencia)
  • HMAC

    También se requiere una breve comprensión de HMAC para entender en profundidad el ataque.

    HMAC es un código de autentificación de mensajes en clave-hash (HMAC) es una construcción específica para calcular un código de autentificación de mensaje (MAC) que implica una función hash criptográfica en combinación con una clave  criptográfica secreta.

    Por lo general, HMAC se calcula con un bloque de 64 bytes, con un encabezado de 8 bytes , y al menos 1 byte de relleno , por lo que efectivamente 55 bytes de datos es el tamaño máximo que se puede calcular una etiqueta en 1 bloque:

    64 – 8 – 1 = 55 bytes

    Si los datos son más de 55 bytes, se requieren 2 bloques. La función HMAC usa compresión, lo que significa que, si los datos superan los 440 bits, se necesitaría más tiempo de ejecución y, por lo tanto, la respuesta del servidor también se retrasaría. En general, 64 bytes de datos requieren un ciclo de máquina adicional. El tamaño de la etiqueta MAC es de 16 bytes (HMAC-MD5), 20 bytes (HMAC-SHA-1) o 32 bytes (HMAC-SHA-256).

    Se debe tener en claro lo siguiente:
    • 55 bytes, utilizan 4 ciclos de CPU.
    • 56 o más bytes, utilizan 5 ciclos de CPU.

¿Cómo se realiza el ataque?

Se explicará el ataque para el esquema de cifrado por bloques AES , cuyo tamaño de bloque es de 16 bytes y HMAC-SHA1 , que calcula 20 bytes de etiqueta.

En primer lugar, un atacante modifica y trunca el texto cifrado. Veamos cuánto necesita truncar. Esto depende exclusivamente de cada ítem mencionado anteriormente:
  1. De HMAC, conocemos que el cálculo de MAC de 55 bytes de datos presenta diferencias computacionales certeras respecto a los 56 bytes de datos, ya que 56 bytes (o más) requieren un ciclo adicional completo de máquina. Entonces, nuestro objetivo es encontrar un bloque de cifrado tal que obtengamos estos 55 bytes de datos.
  2. Sabemos que el cálculo de MAC también usa 13 bytes de HDR (5 bytes) y SQN (8 bytes). Dado que el bloque de cifrado no contendrá estos bytes, restemos para obtener bytes reales, el bloque de cifrado debe tener:

    55-13 = 42 bytes

  3. Ahora agregue el tamaño de la etiqueta, ya que estamos usando SHA-1, son 20 bytes:

    42 + 20 = 62 bytes

  4. El tamaño de bloque más cercano (16) múltiplo de 62 es 64 ( 4 bloques de 16 bytes cada uno). Tenemos que sumar 2 bytes adicionales para obtener 64 bytes.

Por lo tanto, para HMAC-SHA1, tenemos que truncar en 4 bloques y modificar 2 bytes.
Estos 2 bytes serán nuestro terreno de juego para recuperar texto sin formato.

Para descifrar el mensaje, el atacante debe enviar lo siguiente:


Envío de Paquete Malicioso

  • HDR es el encabezado TLS.
  • C₀ es el vector de inicialización.
  • C₁ -C₄ son los bloques de cifrado truncado.
Para TLS, SQN no se envía, pero el emisor y el receptor sin embargo lo agregan.

C₄ es el bloque objetivo con texto plano que el atacante desea explotar. El atacante modificará el bloque anterior, es decir, C₃ con un valor de 16 bytes denotado como Δ (delta).

Analicemos el siguiente diagrama de codificación de cifrado de bloque:

Descifrado AES-CBC (referencia)


En circunstancias normales, es decir, sin ninguna modificación del atacante, la fórmula para descifrar el bloque 4 con la información que contiene es:

                                                            P₄ = (C₄) ⊕ (C₃)

La misma se altera cuando comienza el ataque, debido a que C₃ se modifica con Δ:

                                                            P* = (C₄) ⊕ (C₃⊕ Δ)

De las dos ecuaciones anteriores podemos deducir entonces:

                                                            P* = (P₄) ⊕ (Δ)

Esta es una relación importante entre la información modificada y los datos que el atacante desea obtener en texto plano. Entonces, el receptor primero descifra el paquete transmitido, elimina los bytes de relleno y el MAC, y nuevamente calcula el MAC del texto descifrado para compararlo con el MAC recibido.

Los siguientes escenarios se pueden dar en el lado del receptor una vez que finaliza el descifrado:
  • La comprobación de relleno falla: Esto significa que los últimos bytes y los bytes de relleno no coinciden. Por ejemplo, el último byte es 0x75 , lo que significa que todos los bytes de número 0x75 anteriores también deben contener un valor numérico de 0x75, sin embargo el proceso falla.
  • La respuesta (que sería un MAC incorrecto) regresó en menos tiempo: Este es un caso interesante, y significa que el cálculo de MAC utilizó menos de 55 bytes. Dicho escenario solo puede ser posible si los últimos 2 bytes son 0x01 0x01 o incluso 0x02 0x02 0x02, en todos estos casos se utilizan 64 bytes de bloque de cifrado debido a 42 + 13 bytes de HDR||SQN = 55 bytes.
    Descifrado del rendimiento del último bloque 0x01 0x01 (referencia)
  • El relleno es correcto, pero toma más tiempo: Significa que el último byte es 0x00, entonces el último byte se calcula como 64–1 (1 byte de 0x00) - 20 (etiqueta SHA-1) = 43 bytes + 13 bytes de HDR || SQN = 56 bytes.
Por lo tanto, solo el segundo caso toma menos tiempo y eso significa que en P* los últimos 2 bytes son 0x01 0x01 y que poseemos una relación entre P₄ y P*. El atacante puede recuperar los últimos 2 bytes de P₄.
                                                                P* = (P₄) ⊕ (Δ)

En la práctica, el atacante debe realizar una gran cantidad de cálculos, más precisamente 2¹⁶ (2⁸ por cada byte). Tenga en cuenta que cuando falla el cálculo de MAC, la sesión se cerrará. Por lo tanto, el atacante debe implementar un modelo que inicie una conexión múltiple inyectando JavaScript.

Mitigación

  • Escriba el código de tal manera que los casos de éxito y error consuman el mismo tiempo para que un atacante no pueda medir la diferencia de tiempo.
  • Utilice cifrados AEAD como AES-GCM, estos cifrados calculan MAC mientras cifran el mensaje en sí.
  • Cifre el texto sin formato primero, luego genere un MAC basado en el texto cifrado resultante.
  • Utilice versiones no vulnerables de las librerías que implemente en sus sistemas, como por ejemplo, la versión 1.1.1.* de OpenSSL.
  • Para evitar el ataque LUCKY13, use la siguiente configuración de TLS en los siguientes servidores:
    • Apache:
      • Con apache, la configuración SSL/TLS se almacena en:
        "/etc/apache2/mods-enabled/ssl.conf" Si usa "Let's Encrypt", la configuración puede residir en: "/etc/letsencrypt/options-ssl-apache.conf"

        Para habilitar solo los cifrados con cifrado alto y protocolos recientes establecidos utilice la siguiente configuración:
        SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
        SSLCipherSuite ECDHE-ECDSA-
        AES256-GCM-
        SHA384:ECDHE-
        RSA-AES256-GCM-SHA384:ECDHE-
        ECDSA-CHACHA20-
        POLY1305:ECDHE-
        RSA-CHACHA20-
        POLY1305:ECDHE-
        ECDSA-AES128-
        GCM-
        SHA256:ECDHE-
        RSA-AES128-GCM-
        SHA256:ECDHE-
        ECDSA-AES256-
        SHA384:ECDHE-
        RSA-AES256-
        SHA384:ECDHE-
        ECDSA-AES128-
        SHA256:ECDHE-
        RSA-AES128-
        SHA256
        SSLHonorCipherOrder On
        SSLCompression Off

        Luego vuelva a cargar la configuración del servidor Apache.

        Tenga en cuenta que esto limita las suites de cifrado y la versión del protocolo a versiones recientes de SSL/TLS que pueden excluir a los usuarios con navegadores más antiguos.
    • Nginx:
      • Para Nginx, actualice el archivo de configuración que generalmente se encuentra en:
        • /etc/nginx/nginx.conf
        • /etc/nginx/sited-enabled/yoursite.com (Ubuntu/Debian)
        • /etc/nginx/conf.d/nginx. conf (RHEL / CentOS)

          Agregue la siguiente directiva a la sección del servidor:
          SSLProtocol TLSv1.2;
          ssl_ciphers 'ECDHE-ECDSA-
          AES256-GCM-
          SHA384:ECDHE-
          RSA-AES256-
          GCM-
          SHA384:ECDHE-
          ECDSA-
          CHACHA20-
          POLY1305:ECDHE-
          RSA-CHACHA20-
          POLY1305:ECDHE-
          ECDSA-AES128-
          GCM-
          SHA256:ECDHE-
          RSA-AES128-
          GCM-
          SHA256:ECDHE-
          ECDSA-AES256-
          SHA384:ECDHE-
          RSA-AES256-
          SHA384:ECDHE-
          ECDSA-AES128-
          SHA256:ECDHE-
          RSA-AES128-
          SHA256';
          ssl_prefer_server_ciphers On


          Luego reinicie el servidor Nginx.

          Tenga en cuenta que esto limita las suites de cifrado y la versión del protocolo a versiones recientes de SSL/TLS que pueden excluir a los usuarios con navegadores más antiguos.

Referencias


Autor: Pablo Gonzalo Carrasco - CEH
Depto. Auditoría