Español | English
rss facebook linkedin Twitter

Drown a fondo: Un nuevo ataque al SSL. (PARTE III)



En los anteriores posts [parte1] [parte2] hemos ido viendo algunos conceptos necesarios para entender DROWN en su totalidad. Recordemos que el artículo original en el que se describe el ataque en profundidad puede encontrarse en la siguiente dirección https://drownattack.com/drown-attack-paper.pdf

La situación partía de que existe un mensaje “m0” conocido como pre-master-secret que contiene información sobre la clave simétrica utilizada en una conexión SSLv3/TLS, del que sólo conocemos “c0”, que es el mensaje cifrado con la clave pública RSA del servidor. También hemos visto que es posible derivar a partir de “c0” un mensaje “c1”, que es la versión cifrada de un mensaje “m1”, y que conociendo la relación entre “c0” y “c1” (que es un valor escogido por el atacante y al que llamamos “s”), conocemos también la relación entre “m0” y “m1”, por lo que si conseguimos descubrir el valor de “m1”, seremos capaces de calcular “m0”, a partir de él las claves simétricas de la conexión  SSLv3/TLS y por tanto podríamos descifrar la comunicación. El objetivo ahora mismo es encontrar un “m1” que sea aceptado como master-key por un servidor SSLv2 que comparta la clave RSA con el servidor SSLv3/TLS original.

El problema es que escogiendo un valor “s” al azar la posibilidad de conseguir que el mensaje “m1” sea aceptado como master-key por el servidor SSLv2 es inferior a 1 entre 33 millones, y que necesitamos aplicar 240 operaciones de descifrado simplemente para saber si m1 es un master-key o no, lo que hace que esta aproximación sea inviable.

Es necesario aumentar las posibilidades de éxito en lugar de elegir valores de s al azar. Para ello, hay que analizar cómo se cifran tanto pre-master-secret (SSLv3/TLS) como master-key (SSLv2). Ambos datos no se cifran directamente con RSA sino que para aumentar la seguridad del cifrado, se formatean de tal manera que se les añade información aleatoria antes de cifrarlos. El formato se conoce como PKCS#1 v1.5 y tiene la siguiente estructura:



Los bytes marcados en rojo son fijos, mientras que los bytes marcados en azul son los datos que estamos cifrando. Los bytes marcados en verde actúan de relleno. El número de bytes de relleno depende del tamaño de la clave RSA utilizada pero será como mínimo 8. Para el caso de una clave RSA 2048, el tamaño total será de 256 bytes. Estos bytes tomarán un valor aleatorio pero siempre distinto de 0, ya que en caso contrario se podría confundir con el separador entre el relleno y los datos que se están cifrando.

Teniendo en cuenta la estructura anterior, los paquetes pre-master-secret (SSLv3/TLS) y master-key (SSLv2) quedan:


El objetivo del atacante en este caso es conseguir un valor “s” que convierta el mensaje superior en el inferior, para que sea aceptado por el servidor en un algoritmo de cifrado EXPORT de 40 bits (de ahí que en el caso de SSLv2 M sólo tenga 5 bytes frente a los 48 del caso SSLv3/TLS). En este caso puede verse claramente que haga lo que haga el atacante, el resultado tras la multiplicación por  “s” debe empezar por 0x00, 0x02. Al tratarse de aritmética modular, es posible encontrar valores muy diferentes entre sí que den como resultado un número que empiece por 0x00, 0x02. Sin embargo, está claro que muchos valores válidos serán muy cercanos a 1.

Aunque no es posible realizar aritmética con valores en punto flotante (por ejemplo, no podemos tomar s=0.9), lo que sí puede hacerse es dividir el mensaje por un número dado “t”, y luego multiplicar el resultado por otro denominado “u”. Por tanto, sería equivalente a considerar que s = u/t.

Esta forma de actuar permite obtener muchos mejores resultados que simplemente dar valores a “s” aleatoriamente y probar (hay que recordar que cada valor de “s” probado implica hasta 240 operaciones de descifrado para comprobar si es correcto). En concreto si se toman los valores u=7 y t=8, la probabilidad de que “m1” sea un master-key válido es superior a 1 entre 8000. Sin duda, una mejora muy importante al caso de escoger s  aleatoriamente.

Sin embargo, como contrapartida no todos los mensajes SSLv3/TLS sirven para todas las fracciones, ya que cuando se hace la división, el resultado debe ser exacto, no debe tener resto  (en caso contrario y debido a que estamos en aritmética modular, los dos primeros bytes ya no serían 0x00, 0x02). Por tanto, la forma sugerida por los autores del ataque consiste en tomar un número concreto de valores de “s”, o más bien pares u/t (en el artículo sugieren entre 1 y 10) y tomar una cantidad importante de negociaciones SSLv3/TLS (en el artículo sugieren entre 900 y 12000), de tal modo que alguno de los mensajes, con alguna de las fracciones devolverá un mensaje modificado válido como master-key de la negociación SSLv2.

Recordemos que el simple hecho de haber encontrado un valor válido ha implicado ejecutar fuerza bruta y descubrir el master-key de la conexión SSLv2. Por tanto, ahora conocemos todos los valores en azul del mensaje modificado SSLv2.
Por ejemplo (ponemos los valores en rojo para indicar que ya son valores conocidos):








En este punto se dispone de un mensaje SSLv2 del que se conoce mayor cantidad de información que sobre el mensaje SSLv3/TLS original y a partir del que  (como hemos visto antes) en caso de conocer todos sus bytes podemos recuperar el mensaje SSLv3/TLS. El problema en este punto son los bytes de relleno, ya que si se quiere recuperar el mensaje original es necesario conocer exactamente todos los valores del mensaje modificado. En este último paso hemos visto que la operación de buscar un master-key adecuado y obtenerlo por fuerza bruta nos devuelve los bytes menos significativos del mensaje. El siguiente paso debería ser intentar acumular todos los bytes conocidos que podamos en la zona más significativa del mensaje, de modo que la siguiente iteración calcule bytes desconocidos. Para ello, aplicaremos una rotación hacia la derecha al mensaje modificado SSLv2. Es decir, lo multiplicaremos por 2-48 de tal modo que desplazamos los 6 bytes que conocemos hacia la derecha, dejando en su lugar 6 bytes de relleno (y acumulando bytes conocidos en la zona alta del mensaje. Ahora bien, teniendo en cuenta que estamos trabajando siempre con operaciones en aritmética modular, el desplazamiento no es tan sencillo. Desplazar hacia la derecha un byte distinto de 0 modifica los bytes más significativos de una forma que depende del resto de valores del mensaje.

Para calcular esta rotación nos basaremos en la propiedad distributiva de la multiplicación sobre la suma, incluso en aritmética modular. Si queremos multiplicar un mensaje m1 por un desplazamiento 2-48 podemos descomponer m en la suma de dos submensajes m11 y m12 de tal modo que:

m1 = m11 + m12

m1*2-48 = (m11 + m12)*2-48 = m11*2-48+m12*2-48


Es decir, la rotación del mensaje original será equivalente a la suma de las rotaciones de los dos submensajes. Para facilitar el rotado, el atacante deja los bytes desconocidos en un submensaje para el que todos los bytes rotados serán 0x00, evitando de esta forma que modifiquen los bytes más significativos del resultado final, quedando:






Se puede ver que, tras la rotación, se tiene un mensaje del que se conocen los bytes más significativos, y se desconocen los menos significativos. Puede verse que hay un byte desconocido más de lo que parecería a priori. Esto es debido a que en función del valor de P1 podría haber acarreo con lo que el valor del siguiente byte depende de si existe ese acarreo (por ejemplo, si P1 es 0xFF) o no (por ejemplo, si P1 es 0x01). En este caso el acarreo no va más allá, aunque se debe tener en cuenta que si los bytes sucesivos fuesen 0xFF también podría irse propagando el acarreo y por tanto la incertidumbre sobre los bytes (aunque las probabilidades de que esto  ocurra son muy bajas).

Desgraciadamente para el atacante, el resultado no es un master-key válido (no comienza por 0x00 0x02) por lo que no puede usarlo directamente, sino que vuelve a tener que calcular una transformación que le permita obtener un mensaje que sea aceptado por el servidor SSLv2 para poder romper de nuevo por fuerza bruta los 5 bytes menos significativos. Sin embargo, al conocer mayor cantidad de bytes más significativos, el cálculo del valor s es más sencillo. De hecho, tras dos o tres iteraciones conoce tanta información que, aunque podría continuarse con este proceso hasta encontrar un mensaje que se descifre completamente, los propios autores del artículo recomiendan cambiar la estrategia a una modificación al oráculo de Bleichenbacher descrita en el artículo. Una vez que consigue encontrar un mensaje para el que conozca  todos los bytes, el atacante no tiene más que volver atrás (ya que conoce todas las relaciones entre los mensajes) para acabar descubriendo el valor del mensaje original, que era el pre-master-secret de la comunicación SSLv3/TLS. Con ese valor ya sí es capaz de calcular las claves simétricas necesarias para desencriptar la comunicación segura, que era el objetivo inicial.

Puede verse que este ataque ha sido posible por las siguientes razones:
  • Todavía existen servidores que permiten usar protocolos inseguros (en este ejemplo SSLv2).
  • Por dejadez, reducción de gastos o sencillez de gestión, se están reutilizando claves o incluso certificados completos en servidores diferentes
  • Las implementaciones de SSLv2 no esperan a autenticar al cliente mediante el paquete ClientFinished antes de enviar el ServerVerify. Esto habría impedido el ataque ya que el cliente tendría que demostrar que conocer la clave simétrica antes de recibir la información que le permite obtenerla por fuerza bruta. Esto es algo que ya se prohíbe explícitamente en SSLv3/TLS.
  • El problema de diseño que implica tener criptografía voluntariamente debilitada (los cifrados EXPORT) en un sistema de cifrado. Incluso aunque las restricciones de exportación de criptografía se levantaron en su mayoría en el año 2000, todavía siguen trayendo problemas.
La forma de defender nuestra infraestructura frente a este ataque es sencilla: no usar nunca SSLv2. Se trata de un protocolo con más de 20 años de vida y que poco más de un año después de aparecer ya tenía un sustituto (SSLv3) que además representaba una rediseño desde cero. Sin embargo, esto no debe hacernos caer en la complacencia de usar SSLv3 o incluso TLSv1.0. También tienen sus propios problemas y es necesario que realicemos la migración a TLSv1.1 ó TLSv1.2 cuanto antes. Además, habrá que estar atentos al diseño que se está realizando actualmente de TLSv1.3.

En otro orden de cosas, reutilizar las claves asimétricas también es una mala idea que debería evitarse siempre que sea posible.


Ion Larrañaga 
Software Innovation S21sec

(+34 902 222 521)


24 horas / 7 días a la semana



© Copyright S21sec 2013 - Todos los derechos reservados


login