Millones de binarios después. Cómo se fortaleció Linux

TL; DR . En este artículo, exploramos esquemas de fortalecimiento que funcionan de manera inmediata en cinco distribuciones populares de Linux. Para cada uno, tomamos la configuración predeterminada del núcleo, descargamos todos los paquetes y analizamos los esquemas de protección en los archivos binarios adjuntos. Consideramos las distribuciones de OpenSUSE 12.4, Debian 9, CentOS, RHEL 6.10 y 7, así como Ubuntu 14.04, 12.04 y 18.04 LTS.

Los resultados confirman que incluso los esquemas básicos, como los canarios de pila y el código independiente de la posición, aún no son utilizados por todos. La situación es aún peor para los compiladores cuando se trata de proteger contra vulnerabilidades como el choque de la pila, que se convirtió en el centro de atención en enero después de publicar información de vulnerabilidad en systemd . Pero no todo es tan desesperado. En una parte importante de los archivos binarios, se implementan métodos de protección básicos y su número crece de una versión a otra.

La verificación mostró que el mayor número de métodos de protección se implementa en Ubuntu 18.04 a nivel de sistema operativo y aplicación, seguido de Debian 9. Por otro lado, en OpenSUSE 12.4, CentOS 7 y RHEL 7, también se implementan esquemas de protección básicos, y la protección contra colisiones de pila se aplica aún más ampliamente. con un conjunto mucho más denso de paquetes por defecto.

Introduccion


Es difícil proporcionar software de alta calidad. A pesar de la gran cantidad de herramientas avanzadas para el análisis de código estático y el análisis dinámico en tiempo de ejecución, así como el progreso significativo en el desarrollo de compiladores y lenguajes de programación, el software moderno todavía sufre vulnerabilidades que los cibercriminales explotan constantemente. La situación es aún peor en los ecosistemas que incluyen código heredado. En tales casos, no solo nos enfrentamos al eterno problema de encontrar posibles errores explotados, sino que también estamos limitados por marcos rígidos de compatibilidad con versiones anteriores, que a menudo requieren mantener un código limitado o aún peor, vulnerable o con errores.

Aquí es donde entran en juego los métodos de endurecimiento. No podemos evitar algunos tipos de errores, pero podemos hacer que la vida de un atacante sea más difícil y resolver parcialmente el problema evitando o previniendo la operación de estos errores. Dicha protección se usa en todos los sistemas operativos modernos, sin embargo, los métodos varían mucho en complejidad, eficiencia y rendimiento: desde los canarios de pila y ASLR hasta las protecciones completas de CFI y ROP . En este artículo, consideraremos qué métodos de protección se usan en las distribuciones de Linux más populares en la configuración predeterminada, y también estudiaremos las propiedades de los archivos binarios que se distribuyen a través de los sistemas de administración de paquetes de cada distribución.

CVE y seguridad


Todos hemos visto artículos con títulos como "Aplicaciones más vulnerables del año" o "Sistemas operativos más vulnerables". Por lo general, proporcionan estadísticas sobre el número total de registros de vulnerabilidad, como CVE (Common Vulnerability and Exposures) obtenidos de la National Vulnerability Database (NVD) de NIST y otras fuentes. Posteriormente, estas aplicaciones o sistemas operativos se clasifican según el número de CVE. Desafortunadamente, aunque los CVE son muy útiles para rastrear problemas e informar a proveedores y usuarios, dicen poco sobre la seguridad real del software.

Como ejemplo, considere el número total de CVE en los últimos cuatro años para el kernel de Linux y las cinco distribuciones de servidor más populares, a saber, Ubuntu, Debian, Red Hat Enterprise Linux y OpenSUSE.


Fig. 1

¿Qué nos dice este cuadro? ¿Más CVE significa que una distribución es más vulnerable que otra? No hay respuesta Por ejemplo, en este artículo verá que Debian implementa mecanismos de seguridad más estrictos en comparación con, por ejemplo, OpenSUSE o RedHat Linux, y aún así Debian tiene más CVE. Sin embargo, no necesariamente significan seguridad debilitada: incluso tener un CVE no dice si la vulnerabilidad es explotable . Los puntajes de gravedad dan una idea de cuán probable es la explotación de la vulnerabilidad, pero al final, la explotabilidad depende en gran medida de la protección presente en los sistemas afectados, así como de los recursos y capacidades de los atacantes. Además, la falta de informes de CVE no dice nada sobre otras vulnerabilidades no registradas o desconocidas . La diferencia en CVE puede explicarse no por la calidad del software, sino por otros factores, incluidos los recursos asignados para las pruebas o el tamaño de la base de usuarios. En nuestro ejemplo, más CVE de Debian pueden simplemente indicar que Debian está entregando más paquetes de software.

Por supuesto, el sistema CVE proporciona información útil que le permite crear protecciones apropiadas. Cuanto mejor comprendamos las razones del fracaso del programa, más fácil será identificar los posibles métodos de operación y desarrollar mecanismos de detección y respuesta adecuados. En la fig. La Figura 2 muestra las categorías de vulnerabilidad para todas las distribuciones en los últimos cuatro años ( fuente ). Es obvio de inmediato que la mayoría de los CVE se dividen en las siguientes categorías: denegación de servicio (DoS), ejecución de código, desbordamiento, corrupción de memoria, pérdida de información (exfiltración) y escalada de privilegios. Aunque muchas CVE están cubiertas varias veces en diferentes categorías, en general, los mismos problemas persisten de año en año. En la siguiente parte del artículo, evaluaremos el uso de varios esquemas de protección para evitar la explotación de estas vulnerabilidades.


Fig. 2

Las tareas


En este artículo, tenemos la intención de responder las siguientes preguntas:

  • ¿Cuál es la seguridad de varias distribuciones de Linux? ¿Qué mecanismos de defensa existen en las aplicaciones de kernel y espacio de usuario?
  • ¿Cómo ha cambiado la adopción de mecanismos de protección para diversas distribuciones con el tiempo?
  • ¿Cuáles son las dependencias promedio de paquetes y bibliotecas para cada distribución?
  • ¿Qué protecciones se implementan para cada binario?

Elegir distribuciones


Resulta que es difícil encontrar estadísticas precisas sobre las instalaciones de distribución, ya que en la mayoría de los casos el número de descargas no indica el número de instalaciones reales. Sin embargo, las variantes de Unix constituyen la mayoría de los sistemas de servidor (69,2% en servidores web, según las estadísticas de W3techs y otras fuentes), y su participación está en constante crecimiento. Por lo tanto, para nuestro estudio, nos centramos en las distribuciones disponibles de fábrica en la plataforma Google Cloud . En particular, elegimos el siguiente sistema operativo:

Distribución / versiónEl núcleoConstruir
OpenSUSE 12.44.12.14-95.3-predeterminado# 1 SMP mié 5 dic 06:00:48 UTC 2018 (63a8d29)
Debian 9 (estiramiento)4.9.0-8-amd64# 1 SMP Debian 4.9.130-2 (2018-10-27)
CentOS 6.102.6.32-754.10.1.el6.x86_64# 1 SMP martes 15 de enero 17:07:28 UTC 2019
CentOS 73.10.0-957.5.1.el7.x86_64# 1 SMP vie 1 feb 14:54:57 UTC 2019
Red Hat Enterprise Linux Server 6.10 (Santiago)2.6.32-754.9.1.el6.x86_64# 1 SMP Mié 21 de noviembre 15:08:21 EST 2018
Red Hat Enterprise Linux Server 7.6 (Maipo)3.10.0-957.1.3.el7.x86_64# 1 SMP jue 15 de noviembre 17:36:42 UTC 2018
Ubuntu 14.04 (Trusty Tahr)4.4.0–140-genérico
# 166 ~ 14/04/1-Ubuntu SMP sáb 17 nov 01:52:43 UTC 20 ...
Ubuntu 16.04 (Xenial Xerus)4.15.0-1026-gcp# 27 ~ 16.04.1-Ubuntu SMP vie 7 dic 09:59:47 UTC 2018
Ubuntu 18.04 (Bionic Beaver)4.15.0-1026-gcp# 27-Ubuntu SMP jue 6 dic 18:27:01 UTC 2018
Tabla 1

Análisis


Examinaremos la configuración predeterminada del kernel, así como las propiedades de los paquetes disponibles a través del administrador de paquetes de cada paquete de distribución listo para usar. Por lo tanto, consideramos solo los paquetes de los espejos predeterminados de cada distribución, ignorando los paquetes de repositorios inestables (por ejemplo, probando espejos en Debian) y paquetes de terceros (por ejemplo, paquetes de Nvidia de espejos estándar). Además, no consideramos compilaciones de kernel personalizadas o configuraciones de seguridad avanzadas.

Análisis de configuración del kernel


Utilizamos un script de análisis basado en el verificador gratuito kconfig . Consideramos las opciones de protección listas para usar para las distribuciones nombradas y las comparamos con la lista del Kernel Self-Defense Project (KSPP). Para cada parámetro de configuración, la Tabla 2 describe la configuración deseada: una marca de verificación es para distribuciones que cumplen con las recomendaciones de KSSP (para una explicación de los términos ver aquí ; en futuros artículos describiremos cuántos de estos métodos de protección aparecieron y cómo piratear el sistema en su ausencia).





En general, los núcleos más nuevos tienen configuraciones más estrictas fuera de la caja. Por ejemplo, CentOS 6.10 y RHEL 6.10 en el núcleo 2.6.32 no tienen la mayoría de las funciones críticas implementadas en los nuevos núcleos, como SMAP , permisos RWX fuertes, aleatorización de direcciones o protección contra copy2usr. Cabe señalar que muchas de las opciones de configuración de la tabla no están disponibles en versiones anteriores del núcleo y no son aplicables en la realidad; esto todavía se indica en la tabla como la falta de protección adecuada. Del mismo modo, si el parámetro de configuración no está disponible en esta versión, y por seguridad, este parámetro debe estar deshabilitado, esto se considera una configuración razonable.

Otro punto a la hora de interpretar los resultados: algunas configuraciones de kernel que aumentan la superficie de ataque se pueden usar simultáneamente por seguridad. Tales ejemplos incluyen uprobes y kprobes, módulos de kernel y BPF / eBPF. Nuestra recomendación es utilizar los mecanismos anteriores para proporcionar una protección real, ya que no son triviales de usar, y su funcionamiento supone que los actores maliciosos ya están arraigados en el sistema. Pero si estas opciones están habilitadas, el administrador del sistema debe monitorear activamente el abuso.

Al estudiar más a fondo las entradas en la Tabla 2, vemos que los núcleos modernos ofrecen varias opciones para proteger contra la explotación de vulnerabilidades como la fuga de información y el desbordamiento de pila / montón. Sin embargo, notamos que incluso las distribuciones populares más recientes aún no han implementado una protección más sofisticada (por ejemplo, con parches de seguridad) o protección moderna contra ataques de reutilización de código (por ejemplo, combinando aleatorización con esquemas como R ^ X para código ). Peor aún, incluso estas defensas más avanzadas no protegen contra una gama completa de ataques. Por lo tanto, es crucial que los administradores de sistemas complementen las configuraciones inteligentes con soluciones que ofrezcan detección y prevención de exploits en tiempo de ejecución.

Análisis de la aplicación


No es sorprendente que diferentes distribuciones tengan diferentes características de paquetes, opciones de compilación, dependencias de biblioteca, etc. Existen diferencias incluso para distribuciones relacionadas y paquetes con un pequeño número de dependencias (por ejemplo, coreutils en Ubuntu o Debian). Para evaluar las diferencias, descargamos todos los paquetes disponibles, extrajimos sus contenidos y analizamos los archivos binarios y las dependencias. Para cada paquete, rastreamos los otros paquetes de los que depende, y para cada binario rastreamos sus dependencias. Esta sección resume los hallazgos.

Distribuciones


En total, descargamos 361,556 paquetes para todas las distribuciones, extrayendo solo paquetes de los espejos predeterminados. Ignoramos los paquetes sin archivos ejecutables ELF, como códigos fuente, fuentes, etc. Después del filtrado, quedaron 129 569 paquetes que contenían un total de 584 457 archivos binarios. La distribución de paquetes y archivos entre distribuciones se muestra en la fig. 3)


Fig. 3

Puede notar que cuanto más moderna es la distribución, más paquetes y archivos binarios contiene, lo cual es lógico. Al mismo tiempo, los paquetes Ubuntu y Debian incluyen muchos más archivos binarios (módulos y bibliotecas tanto ejecutables como dinámicas) que CentOS, SUSE y RHEL, lo que potencialmente afecta la superficie de ataque de Ubuntu y Debian (debe tenerse en cuenta que los números reflejan todos los archivos binarios de todas las versiones paquete, es decir, algunos archivos se analizan varias veces). Esto es especialmente importante cuando se consideran las dependencias entre paquetes. Por lo tanto, una vulnerabilidad en el binario de un solo paquete puede afectar muchas partes del ecosistema, así como una biblioteca vulnerable puede afectar a todos los archivos binarios que lo importan. Como punto de referencia, veamos la distribución del número de dependencias entre paquetes en varios sistemas operativos:


Fig. 4 4

En casi todas las distribuciones, el 60% de los paquetes tienen al menos 10 dependencias. Además, algunos paquetes tienen más dependencias (más de 100). Lo mismo se aplica a las dependencias de paquetes inversos: como se esperaba, muchos paquetes son utilizados por muchos otros paquetes en la distribución, por lo que las vulnerabilidades en estos pocos favoritos tienen un alto riesgo. Como ejemplo, la siguiente tabla enumera 20 paquetes con el número máximo de dependencias inversas en SLES, Centos 7, Debian 9 y Ubuntu 18.04 (cada cuadro indica el paquete y el número de dependencias inversas).


Tabla 3

Un hecho interesante Aunque todos los sistemas operativos analizados están construidos para la arquitectura x86_64, mientras que la mayoría de los paquetes tienen la arquitectura definida como x86_64 y x86, los paquetes a menudo contienen binarios para otras arquitecturas, como se muestra en la Fig. 5)


Fig. 5 5

En la siguiente sección, profundizaremos en las características de los binarios analizados.

Estadísticas de protección binaria


Como mínimo absoluto, debe estudiar el conjunto básico de opciones de protección para los archivos binarios existentes. Varias distribuciones de Linux vienen con scripts que realizan tales comprobaciones. Por ejemplo, en Debian / Ubuntu existe tal script. Aquí hay un ejemplo de su trabajo:

$ hardening-check $(which docker) /usr/bin/docker: Position Independent Executable: yes Stack protected: yes Fortify Source functions: no, only unprotected functions found! Read-only relocations: yes Immediate binding: yes 

El script verifica cinco funciones de protección :

  • Position Independent Executable (PIE): indica si la sección de texto del programa se puede mover en la memoria para lograr la aleatorización si ASLR está habilitado en el núcleo.
  • Pila protegida: si los canarios de pila están incluidos para proteger contra los ataques de colisión de pila.
  • Fortificar fuente: si las funciones inseguras (por ejemplo, strcpy) se reemplazan por sus contrapartes más seguras, y las llamadas verificadas en tiempo de ejecución se reemplazan por sus contrapartes no verificadas (por ejemplo, memcpy en lugar de __memcpy_chk).
  • Reubicaciones de solo lectura (RELRO): si las entradas en la tabla de movimiento están marcadas como de solo lectura si funcionaron antes de que comenzara la ejecución.
  • Enlace inmediato: si el enlazador de tiempo de ejecución permite todos los movimientos antes de iniciar el programa (esto es equivalente a RELRO completo).

¿Son suficientes los mecanismos anteriores? Lamentablemente no. Hay formas conocidas de eludir todas las defensas anteriores, pero cuanto más estricta sea la defensa, más alta será la barra para el atacante. Por ejemplo, las soluciones alternativas de RELRO son más difíciles de aplicar si PIE y la vinculación inmediata están vigentes. Del mismo modo, un ASLR completo requiere trabajo adicional para crear un exploit de trabajo. Sin embargo, los atacantes sofisticados están listos para enfrentar tales defensas: su ausencia esencialmente acelerará la piratería. Por lo tanto, es imperativo que estas medidas se consideren el mínimo necesario.

Queríamos estudiar cuántos archivos binarios en las distribuciones en cuestión están protegidos por estos, así como tres métodos más:

  • Un bit no ejecutable ( NX ) impide la ejecución en cualquier región que no debería ser ejecutable, como un montón de pila, etc.
  • RPATH / RUNPATH indica la ruta de ejecución utilizada por el cargador dinámico para encontrar las bibliotecas apropiadas. El primero es obligatorio para cualquier sistema moderno: su ausencia permite a los atacantes escribir arbitrariamente la carga útil en la memoria y ejecutarla tal como está. Para el segundo, las configuraciones incorrectas de la ruta de ejecución ayudan a introducir código no confiable, lo que puede provocar una serie de problemas (por ejemplo, escalada de privilegios , así como otros problemas ).
  • La protección de colisión de la pila proporciona protección contra ataques que hacen que la pila se superponga con otras áreas de la memoria (como un montón). Dadas las recientes vulnerabilidades que abusan de las vulnerabilidades de colisión del montón en systemd , nos pareció apropiado incluir este mecanismo en nuestro conjunto de datos.

Entonces, sin más preámbulos, pasemos a los números. Las tablas 4 y 5 contienen una muestra de análisis de archivos ejecutables y bibliotecas de varias distribuciones, respectivamente.

  • Como puede ver, la protección NX se implementa en todas partes, con raras excepciones. En particular, su menor uso en las distribuciones de Ubuntu y Debian se puede observar en comparación con CentOS, RHEL y OpenSUSE.
  • Los canarios de pila no están disponibles en muchos lugares, especialmente en distribuciones con núcleos antiguos. Se ha visto algún progreso en las distribuciones recientes de Centos, RHEL, Debian y Ubuntu.
  • Con la excepción de Debian y Ubuntu 18.04, la mayoría de las distribuciones tienen poca compatibilidad con PIE.
  • La protección contra colisiones de la pila está mal implementada en OpenSUSE, Centos 7 y RHEL 7 y está prácticamente ausente del resto.
  • Todas las distribuciones con núcleos modernos tienen algún soporte RELRO, con Ubuntu 18.04 a la cabeza, con Debian ocupando el segundo lugar.

Como ya se mencionó, las métricas en esta tabla son promedio en todas las versiones del archivo binario. Si solo mira las últimas versiones de los archivos, los números serán diferentes (por ejemplo, vea el progreso de Debian con la implementación de PIE ). Además, la mayoría de las distribuciones generalmente al calcular estadísticas verifican la protección de solo unas pocas funciones en código binario, y en nuestro análisis se indica el porcentaje real de funciones fortificadas. Por lo tanto, si 5 de 50 funciones están protegidas en el binario, le daremos una calificación de 0.1, que corresponde al 10% de las funciones fortalecidas.


Tabla 4. Características de protección para archivos ejecutables que se muestran en la fig. 3 (implementación de las funciones correspondientes como un porcentaje del número total de archivos ejecutables)


Tabla 5. Características de protección para las bibliotecas que se muestran en la Fig. 3 (implementación de las funciones correspondientes como un porcentaje del número total de bibliotecas)

Entonces, ¿hay progreso? Definitivamente existe: puede verse en las estadísticas de distribuciones individuales (por ejemplo, Debian ), así como en las tablas anteriores. Como ejemplo en la fig. La Figura 6 muestra la implementación de mecanismos de defensa en tres distribuciones consecutivas de Ubuntu LTS 5 (hemos omitido las estadísticas de protección de colisión de la pila). Notamos que de una versión a otra, más y más archivos admiten canarios apilados, y también secuencialmente, cada vez más archivos binarios vienen con protección RELRO completa.


Fig. 6 6

Desafortunadamente, varios archivos ejecutables en diferentes distribuciones todavía no tienen ninguna de las protecciones anteriores. Por ejemplo, mirando Ubuntu 18.04, puede ver el binario ngetty (reemplazo de getty), así como los shells mksh y lksh, el intérprete picolisp, los paquetes nvidia-cuda-toolkit (un paquete popular para aplicaciones aceleradas por GPU como marcos de aprendizaje automático) y klibc -utils. Del mismo modo, el binario mandos-client (una herramienta administrativa que le permite reiniciar automáticamente máquinas con sistemas de archivos encriptados), así como rsh-redone-client (re-implementando rsh y rlogin) se entregan sin protección NX, aunque tienen derechos SUID :(. Además, Varios binarios suid no tienen protección básica, como los canarios de pila (por ejemplo, el binario Xorg.wrap del paquete Xorg).

Resumen y observaciones finales


En este artículo, destacamos varias características de seguridad de las distribuciones modernas de Linux. El análisis mostró que la última distribución Ubuntu LTS (18.04) implementó en promedio la protección más fuerte del sistema operativo y del nivel de aplicación entre las distribuciones con núcleos relativamente nuevos, como Ubuntu 14.04, 12.04 y Debian 9. Sin embargo, las distribuciones CentOS, RHEL y OpenSUSE discutidas en nuestro kit de forma predeterminada, se emite un conjunto más denso de paquetes, y en versiones recientes (CentOS y RHEL) tienen un mayor porcentaje de protección contra colisiones de la pila en comparación con los competidores basados ​​en Debian (Debian y Ubuntu). Al comparar las versiones CentOS y RedHat, notamos grandes mejoras en la implementación de los canarios de pila y RELRO de las versiones 6 a 7, pero en promedio CentOS tiene más características que RHEL. En general, todas las distribuciones deben prestar especial atención a la protección PIE, que, con la excepción de Debian 9 y Ubuntu 18.04, se implementa en menos del 10% de los archivos binarios de nuestro conjunto de datos.

Finalmente, debe tenerse en cuenta: aunque hicimos la investigación manualmente, hay muchas herramientas de seguridad (por ejemplo, Lynis , Tiger , Hubble ) que realizan análisis y ayudan a evitar configuraciones inseguras. Desafortunadamente, incluso una protección fuerte en configuraciones razonables no garantiza la ausencia de exploits. Es por eso que estamos firmemente convencidos de que es vital garantizar un monitoreo confiable y la prevención de ataques en tiempo real , enfocándonos en modelos operativos y previniéndolos.

Source: https://habr.com/ru/post/444418/


All Articles