Heartbleed es una vulnerabilidad en un componente de software de código abierto llamado openssl. En 2014, se reveló que contenía un error y muchos sitios y servicios de Internet eran vulnerables a ataques mediante el uso de un componente de software gratuito. Solucionar el problema ha sido un proceso largo y doloroso .

Al igual que con muchos otros componentes de software de código abierto, openssl está disponible para que cualquier persona en el mundo lo use como parte de una aplicación (sujeto a su licencia, por supuesto).

85% of Global 2000 companies may still be vulnerable to Heartbleed
– Thinkstock / Nerthuz

El componente openssl es una implementación del protocolo de red de seguridad de la capa de transporte (TLS), que se utiliza en muchos tipos de aplicaciones. TLS proporciona autenticación, integridad y confidencialidad para la comunicación en red. Por ejemplo, cada vez que visita una URL https: //…, su navegador utiliza TLS para verificar la identidad del servidor, configurar una conexión cifrada y recuperar páginas y otros recursos a través de la conexión cifrada.

La vulnerabilidad en detalle

TLS es complicado y difícil de hacer bien. Para los desarrolladores de aplicaciones, tiene mucho sentido utilizar una implementación de código abierto como openssl. Siempre que los términos de la licencia del componente sean aceptables, el uso de un componente de código abierto brinda a los desarrolladores de aplicaciones una implementación sólida y madura con muy pocos gastos iniciales.

El protocolo TLS dicta cómo ocurren las conversaciones entre dos puntos finales de la red: un cliente y un servidor. Puede pensar en el cliente como un navegador web y el servidor como un servidor web. Básicamente, cualquier conversación TLS tiene dos fases:

  1. El cliente y el servidor se saludan y negocian los algoritmos y parámetros criptográficos para el resto de la conversación. Esta fase de la conversación tiene mensajes que se intercambian en texto plano.
  2. Una vez finalizada la negociación, el cliente y el servidor entran en la segunda fase en la que intercambian datos cifrados. Este es el punto de TLS: una vez que se haya configurado el cifrado, cualquiera que esté fisgoneando en la red no podrá descifrar los datos intercambiados entre el cliente y el servidor.

El protocolo TLS ha pasado por varias versiones importantes y openssl se ha actualizado para mantener el ritmo. Heartbleed se creó cuando openssl se actualizó para TLS 1.2 en 2012.

Específicamente, TLS 1.2 agregó un nuevo tipo de mensaje: el latido. La intención era que cualquiera de los lados pudiera preguntar al otro "¿Estás ahí?" Un mensaje de solicitud de latido de un lado se reconoce con una respuesta de latido del otro lado.

Los mensajes de latido son muy simples y constan de un campo de longitud y una carga útil. La carga útil en la solicitud se repite en la respuesta.

Por ejemplo, lo siguiente podría ser el contenido de una solicitud de latido, que se muestra como hexadecimal:

La respuesta de latido debe contener exactamente la misma longitud y carga útil.

Desafortunadamente, los desarrolladores de openssl cometieron un error crítico al implementar mensajes de latido. Confiaron plenamente en la longitud enviada en la solicitud. Esta es la vulnerabilidad Heartbleed .

Si la solicitud miente sobre la longitud de su carga útil, openssl aún devuelve la longitud solicitada, que incluye la memoria de pila. Este tipo de vulnerabilidad es "fuga de información". Los datos devueltos pueden contener información confidencial como credenciales utilizadas recientemente o incluso la clave criptográfica privada del servidor.

Por ejemplo, una solicitud mal formada podría reclamar fácilmente una longitud mayor que la carga útil dada:

En este caso, openssl podría responder de la siguiente manera:

Los 16 bytes adicionales (10 hexadecimales) en la respuesta de latido provienen directamente de la memoria de pila del servidor.

Peor aún, la implementación inicial de los mensajes de latido permitió solicitudes y respuestas en la parte no cifrada de la conversación TLS, lo que simplificó la explotación.

Debido a que la longitud de la carga útil es de 32 bits, un atacante podría enviar mensajes de solicitud de latido con una longitud de carga útil falsa de 65.535 bytes (64k, FFFF hexadecimal) y una carga útil vacía, lo que básicamente hace que el sistema de la víctima descargue 64k fragmentos de memoria. El atacante puede examinar estos fragmentos de datos en busca de credenciales, la clave privada del servidor y otra información confidencial.

Usar el viaje en el tiempo para crear un banco de pruebas

Para ver cómo funciona Heartbleed en la práctica, solo necesita un servidor vulnerable y un script de explotación. Si desea probar esto por sí mismo, todos los scripts necesarios están aquí: https://github.com/jknudsen-synopsys/heartbleed-box

Los scripts funcionan en un entorno Linux con Docker instalado. Puede obtener el código de la siguiente manera:

Para ejecutar un servidor vulnerable, puede recuperar una versión anterior de openssl y compilarla usted mismo. Estoy usando un contenedor Docker para este propósito; el extracto relevante del Dockerfile es el siguiente. En particular, el comando git checkout recupera la versión 1.0.1f, la última versión vulnerable a Heartbleed.

heartbleed 4.png
– Synopsys

Si lo está siguiendo, no necesita ejecutar nada de esto manualmente. Simplemente construya el contenedor de esta manera:

Esté preparado para esperar uno o dos minutos.

Si inspecciona el Dockerfile, notará que también ejecuta un comando para generar un par de claves y un certificado para un servidor. Finalmente, ENTRYPOINT está configurado para ejecutar openssl s_server, que implementa un servidor web simple habilitado para TLS.

Una vez que haya creado el contenedor, puede ejecutarlo de la siguiente manera:

El contenedor se inicia y ejecuta el servidor, que está listo para aceptar conexiones entrantes en el puerto 4433.

Simular inicio de sesión

En este ejemplo, aprovecharemos Heartbleed para recuperar las credenciales de usuario. Sin embargo, primero debemos simular un usuario que inicia sesión en el servidor. Una forma en que esto podría suceder en una aplicación web es con un formulario de inicio de sesión. Suele ser un formulario HTML cuya entrada se envía a la aplicación web.

Podemos simular el envío de un formulario de inicio de sesión utilizando curl. Nuestro servidor de ejemplo, que en realidad es openssl s_server, en realidad no tiene páginas. Eso no importa porque solo estamos demostrando cómo las credenciales que se envían con un formulario web están disponibles en la memoria del servidor para ser robadas mediante la explotación de Heartbleed.

El siguiente comando, por ejemplo, simula un formulario de inicio de sesión que se envía a / envía con un nombre de usuario y contraseña de ejemplo:

Las opciones son las siguientes:

  • -k ignora la validación del certificado, que es necesaria porque nuestro servidor usa un certificado autofirmado simple
  • -s suprime la salida
  • -m es un tiempo de espera, que es necesario porque estamos enviando el formulario a un punto final imaginario y no queremos esperar una respuesta
  • -d indica que los datos proporcionados serán POSTADOS

He encapsulado este comando en un script, por lo que puede simular un inicio de sesión como este:

Tenga en cuenta que estas credenciales se cifran antes de transmitirse al servidor.

Explotar Heartbleed

Ahora verá cómo se puede aprovechar Heartbleed para extraer las credenciales de usuario de texto sin formato de la memoria del servidor.

Debido a que las versiones vulnerables de openssl responden a los mensajes de latido en la fase de negociación no cifrada de las conversaciones TLS, la explotación es bastante simple.

Primero, nos conectamos al puerto TCP y enviamos un mensaje TLS ClientHello válido, que es suficiente para convencer a openssl de que estamos iniciando una conversación TLS. Después de eso, podemos enviar un mensaje de solicitud de latido con formato incorrecto, como se describió anteriormente.

En Python, los mensajes de solicitud ClientHello y heartbeat se pueden definir de la siguiente manera:

Una vez que se definen los mensajes, tener una conversación TLS es bastante fácil:

La parte más complicada de este exploit (y no es muy complicado) es buscar a través del mensaje de respuesta del latido del corazón para localizar las credenciales. No reproduciré el código aquí, pero en esencia solo necesitamos buscar username = en la respuesta e intentar ubicar el final de esa cadena.

Envolví todo esto en exploit-01.py, que puede ejecutar fácilmente de la siguiente manera:

La moraleja de la historia

Siete años después, Heartbleed todavía tiene lecciones importantes para todos nosotros.

Conoce tu código

En primer lugar, la gestión de los componentes de software de código abierto es de vital importancia para la seguridad de las aplicaciones. Si bien el uso de componentes de código abierto es una estrategia práctica y fructífera para los desarrolladores de aplicaciones, esos componentes deben administrarse correctamente. Debe saber qué componentes ha utilizado en sus aplicaciones y debe conocer las vulnerabilidades conocidas en esos componentes. Cuando se publican nuevas vulnerabilidades sobre los componentes de software que ha utilizado, debe saberlo de inmediato para poder tomar medidas si es necesario. (Del mismo modo, debe conocer las licencias de software de esos componentes para asegurarse de que no está usando algo incorrectamente, pero ese no es el enfoque de este artículo). Una solución de análisis de composición de software (SCA) como Black Duck automatiza gran parte de este trabajo.

La seguridad es responsabilidad de todos

En segundo lugar, no se puede confiar en nadie aguas arriba para la seguridad. Si bien los componentes de código abierto a menudo brindan implementaciones de funcionalidad de alta calidad que su aplicación necesita, ocurren errores y los desarrolladores de código abierto pueden tener una idea diferente a la suya del riesgo aceptable. Para los componentes de software que utiliza en su aplicación, es su responsabilidad comprender qué tipo de pruebas de seguridad se han realizado y decidir si necesita aumentar esas pruebas con sus propias evaluaciones. Para componentes críticos como openssl que son parte de la superficie de ataque de sus aplicaciones, es prudente realizar sus propias pruebas de seguridad. Dependiendo del tipo de componente, las pruebas de seguridad pueden incluir análisis estático (Coverity, por ejemplo), análisis de composición de software (Black Duck),análisis interactivo (Seeker) y fuzzing (Defensics). De hecho, fueron las pruebas de fuzz de Defensics las que descubrieron Heartbleed.

La seguridad de las aplicaciones es fundamental en el desarrollo de aplicaciones

Finalmente, la seguridad de las aplicaciones es inseparable del desarrollo de aplicaciones. Cuando diseña nuevas aplicaciones o nuevas funciones de aplicaciones existentes, debe reforzar su diseño realizando un modelado de amenazas para pensar en las amenazas, las vulnerabilidades y los controles de seguridad. Durante el desarrollo y las pruebas, debe automatizar e integrar las herramientas de prueba de seguridad para que los desarrolladores corrijan los defectos de seguridad a medida que avanzan. Las prácticas de implementación deben seguir el mismo rigor, con especial atención a las configuraciones de la nube, las imágenes de la base de contenedores y la configuración de la aplicación. Finalmente, después del lanzamiento, las vulnerabilidades recién descubiertas, ya sea en la propia aplicación o en su cadena de suministro de componentes de código abierto, deben identificarse, evaluarse y abordarse de inmediato.


Por Jonathan Knudsen, estratega senior de seguridad en Synopsys Software Integrity Group