El comentario de
@ paj28 cubre el punto principal. OpenSSL es una biblioteca compartida, por lo que se ejecuta en el mismo espacio de direcciones en modo usuario que el proceso que lo usa. No puede ver la memoria de otro proceso en absoluto; cualquier cosa que sugiera lo contrario estaba mal.
Sin embargo, la memoria utilizada por OpenSSL, el material probablemente cerca del búfer desde el que Heartbleed lee en exceso, está llena de datos confidenciales. Específicamente, es probable que contenga tanto el texto cifrado como el texto plano de cualquier transmisión reciente o futura. Si ataca un servidor, esto significa que verá mensajes enviados al servidor por otros y respuestas del servidor a esos mensajes. Esa es una buena manera de robar tokens de sesión e información privada, y probablemente también obtendrá las credenciales de inicio de sesión de alguien. Otros datos almacenados por OpenSSL incluyen claves de cifrado simétricas (utilizadas para el cifrado y la integridad de datos masivos a través de TLS) y claves privadas (utilizadas para probar la identidad del servidor). Un atacante que roba esos puede espiar (e incluso modificar) la comunicación TLS comprometida en tiempo real, o suplantar con éxito el servidor, respectivamente (asumiendo una posición de hombre en el medio en la red).
Ahora, hay algo extraño en Heartbleed que lo hace peor de lo que podrías esperar. Normalmente, existe una gran posibilidad de que, si intenta leer 64k de datos a partir de una dirección de pila arbitraria dentro de un proceso, se encuentre con una dirección de memoria no asignada (memoria virtual no respaldada por nada y, por lo tanto, inutilizable). con rapidez. Estos agujeros en el espacio de direcciones de un proceso son bastante comunes, porque cuando un proceso libera memoria que ya no necesita, el sistema operativo reclama esa memoria para que otros procesos puedan usarla. A menos que su programa pierda memoria como un tamiz, por lo general no hay muchos datos en la memoria que no sean los que se utilizan actualmente. Intentar leer la memoria no asignada (por ejemplo, intentar acceder a la memoria que se ha liberado) provoca una infracción de acceso de lectura (en Windows) / falla de segmentación (en * nix), lo que provocará un bloqueo del programa (y se bloquea antes de que pueda hacerlo) nada como enviar datos de vuelta). Todavía es explotable (como un ataque de denegación de servicio), pero no es tan malo como permitir que el atacante obtenga toda esa información.
Con Heartbleed, el proceso casi nunca se estrelló. Resulta que OpenSSL, aparentemente decidiendo que las bibliotecas de administración de memoria de la plataforma eran demasiado lentas (o algo así, no voy a intentar justificar esta decisión), preasigna una gran cantidad de memoria y luego usa sus propias funciones de administración de memoria. dentro de eso Esto significa algunas cosas:
- Cuando OpenSSL "libera" la memoria, en realidad no se libera en lo que concierne al sistema operativo, por lo que la memoria sigue siendo utilizable por el proceso. El administrador de memoria interna de OpenSSL podría pensar que la memoria no está asignada, pero en lo que respecta al sistema operativo, el proceso de uso de OpenSSL todavía posee esa memoria.
- Cuando OpenSSL "libera" la memoria, a menos que borre explícitamente los datos antes de llamar a su función
free
, esa memoria retiene los valores que tenía antes de ser "liberada". Esto significa que se pueden leer muchos datos que aún no están en uso.
- El montón de memoria utilizado por OpenSSL es contiguo; no hay vacíos dentro de él en lo que se refiere al sistema operativo. Por lo tanto, es muy poco probable que la lectura en exceso del búfer se ejecute en una página no asignada, por lo que no es probable que se bloquee.
- El uso de la memoria de OpenSSL tiene una ubicación muy alta, es decir, se concentra dentro de un rango relativamente pequeño de direcciones (el bloque asignado previamente), en lugar de extenderse por el espacio de direcciones en el capricho del asignador de memoria del sistema operativo. Como tal, la lectura de 64 KB de memoria (que no es mucho, incluso al lado del rango típico de 2 GB de un proceso de 32 bits, y mucho menos del enorme rango de un proceso de 64 bits) es probable que obtenga una gran cantidad de datos actualmente (o estuvo recientemente) en uso, a pesar de que los datos residen en el resultado de un conjunto de asignaciones supuestamente separadas.