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

Millones de binarios después. Cómo se fortaleció LinuxTL;DR. En este artículo, exploramos los esquemas de endurecimiento (hardening schemes) que funcionan de fábrica en cinco distribuciones populares de Linux. Para cada una, tomamos la configuración predeterminada del núcleo, cargamos todos los paquetes y analizamos los esquemas de protección en los binarios anidados. Se consideran las distribuciones 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 las canarias en la 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 protegerse contra vulnerabilidades como el choque de pila (stack clash), que llegaron al centro de atención en enero tras la publicación de información sobre vulnerabilidades en systemd. Pero no todo está perdido. En una parte significativa de los binarios se implementan métodos básicos de protección, y su número aumenta de versión en versión.

La verificación mostró que la mayor cantidad de métodos de protección se implementó en Ubuntu 18.04 a nivel de sistema operativo y aplicaciones, seguido de Debian 9. Por otro lado, OpenSUSE 12.4, CentOS 7 y RHEL 7 también implementaron esquemas básicos de protección, y la protección contra el choque de pila se aplica de manera aún más extensa con un conjunto de paquetes predeterminados mucho más denso.

Introducción

Es difícil asegurar la alta calidad del software. A pesar de la gran cantidad de herramientas avanzadas para el análisis estático del código y el análisis dinámico en tiempo de ejecución, así como del significativo progreso en el desarrollo de compiladores y lenguajes de programación, el software moderno sigue sufriendo de vulnerabilidades que son constantemente explotadas por delincuentes. La situación es aún peor en los ecosistemas que incluyen código obsoleto. En tales casos, no solo enfrentamos el eterno problema de encontrar posibles errores explotables, sino que también estamos limitados por estrictos marcos de compatibilidad hacia atrás que a menudo requieren conservar código limitado, y aún peor, vulnerable o defectuoso.

Aquí es donde entran en juego los métodos de protección o endurecimiento de programas (hardening). Algunos tipos de errores no podemos prevenir, pero podemos dificultar la vida de los delincuentes y resolver parcialmente el problema, previniendo o interrumpiendo. la operación estos errores. Esta protección se utiliza en todos los sistemas operativos modernos, aunque los métodos difieren en gran medida en complejidad, eficacia y rendimiento: desde canarias de pila (stack canaries) y ASLR hasta protecciones completas CFI y ROP. En este artículo, examinaremos qué métodos de protección se aplican en las distribuciones de Linux más populares en su configuración predeterminada, así como también estudiaremos las propiedades de los binarios que se distribuyen a través de los sistemas de gestión de paquetes de cada distribución.

CVE y seguridad

Todos hemos visto artículos con títulos como «Las aplicaciones más vulnerables del año» o «Los sistemas operativos más vulnerables». Normalmente, ahí se presenta estadísticas sobre el número total de registros de vulnerabilidades del tipo CVE (Common Vulnerability and Exposures), obtenidas de la Base Nacional de Vulnerabilidades (NVD) desde NIST y otras fuentes. Posteriormente, estas aplicaciones o sistemas operativos se clasifican según la cantidad de CVE. Desafortunadamente, aunque los CVE son muy útiles para rastrear problemas e informar a proveedores y usuarios, dicen poco sobre la verdadera seguridad del software.

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

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

¿Qué nos dice este gráfico? ¿Significa que una mayor cantidad de CVE indica que una distribución es más vulnerable que otra? La respuesta es no. Por ejemplo, en este artículo verás que Debian implementa mecanismos de protección más estrictos en comparación con, digamos, OpenSUSE o RedHat Linux, y aun así, Debian tiene más CVE. Sin embargo, esto no necesariamente significa que la seguridad esté debilitada: incluso la presencia de CVE no indica si la vulnerabilidad es explotable. Los puntajes de gravedad dan una idea de cuán probable es la explotación de la vulnerabilidad, pero en última instancia, 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 ausencia de informes de CVE no dice nada sobre otras vulnerabilidades no registradas o desconocidas Las vulnerabilidades. La diferencia en CVE puede explicarse no por la calidad del software, sino por otros factores, incluidos los recursos asignados a las pruebas o el tamaño de la base de usuarios. En nuestro ejemplo, un mayor número de CVE en Debian puede simplemente indicar que Debian ofrece más paquetes de software.

Por supuesto, el sistema CVE proporciona información útil que permite crear defensas adecuadas. Cuanto mejor comprendamos las causas del fallo de un programa, más fácil será identificar posibles métodos de explotación y desarrollar mecanismos correspondientes. de detección y respuesta.En la Fig. 2 se muestran las categorías de vulnerabilidades para todas las distribuciones en los últimos cuatro años (fuente). Es evidente que la mayoría de los CVE caen en las siguientes categorías: denegación de servicio (DoS), ejecución de código, desbordamiento, corrupción de memoria, fuga (exfiltración) de información y escalamiento de privilegios. Aunque muchos CVE se registran varias veces en diferentes categorías, en general, los mismos problemas persisten año tras año. En la siguiente parte del artículo, evaluaremos el uso de varios esquemas de defensa para prevenir la explotación de estas vulnerabilidades.

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

Tareas

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

  • ¿Cuál es la seguridad de las diferentes distribuciones de Linux? ¿Qué mecanismos de defensa existen en el núcleo y en las aplicaciones del espacio de usuario?
  • ¿Cómo ha cambiado la adopción de los mecanismos de defensa a lo largo del tiempo para las diferentes distribuciones?
  • ¿Cuáles son las dependencias promedio de los paquetes y bibliotecas de cada distribución?
  • ¿Qué defensas se implementan para cada binario?

Selección de distribuciones

Resulta complicado encontrar estadísticas precisas sobre instalaciones de distribuciones, ya que en la mayoría de los casos el número de descargas no indica cuántas instalaciones reales se han realizado. No obstante, las variantes de Unix constituyen la mayoría de los sistemas de servidor (69.2% en los servidores web, según estadísticas W3techs y otras fuentes), y su cuota sigue creciendo. Así, para nuestra investigación, nos centramos en las distribuciones que están disponibles de forma predeterminada en la plataforma Google Cloud. En particular, elegimos los siguientes sistemas operativos:

Distribución/version
Núcleo
Construcción

OpenSUSE 12.4
4.12.14-95.3-default
#1 SMP Wed Dec 5 06:00:48 UTC 2018 (63a8d29)

Debian 9 (stretch)
4.9.0-8-amd64
#1 SMP Debian 4.9.130-2 (2018-10-27)

CentOS 6.10
2.6.32-754.10.1.el6.x86_64
#1 SMP Tue Jan 15 17:07:28 UTC 2019

CentOS 7
3.10.0-957.5.1.el7.x86_64
#1 SMP Fri Feb 1 14:54:57 UTC 2019

Red Hat Enterprise Linux Server 6.10 (Santiago)
2.6.32-754.9.1.el6.x86_64
#1 SMP Wed Nov 21 15:08:21 EST 2018

Red Hat Enterprise Linux Server 7.6 (Maipo)
3.10.0-957.1.3.el7.x86_64
#1 SMP Thu Nov 15 17:36:42 UTC 2018

Ubuntu 14.04 (Trusty Tahr)
4.4.0–140-generic

#166~14.04.1-Ubuntu SMP Sat Nov 17 01:52:43 UTC 20…

Ubuntu 16.04 (Xenial Xerus)
4.15.0–1026-gcp
#27~16.04.1-Ubuntu SMP Fri Dec 7 09:59:47 UTC 2018

Ubuntu 18.04 (Bionic Beaver)
4.15.0–1026-gcp
#27-Ubuntu SMP Thu Dec 6 18:27:01 UTC 2018

Tabla 1

Análisis

Examinaremos la configuración del kernel por defecto, así como las características de los paquetes disponibles a través del gestor de paquetes de cada distribución desde el principio. De este modo, solo consideramos los paquetes de los espejos por defecto de cada distribución, ignorando los paquetes de repositorios inestables (por ejemplo, los espejos 'testing' en Debian) y los paquetes de terceros (como los paquetes de Nvidia desde los espejos estándar). Además, no consideramos las compilaciones personalizadas del kernel ni las configuraciones con mayor seguridad.

Análisis de la configuración del kernel

Aplicamos un script de análisis basado en el verificador de configuración kconfig gratuito. Consideramos los parámetros de seguridad por defecto en las distribuciones mencionadas y los comparamos con la lista de Proyecto de Autoprotección del Kernel (KSPP). Para cada parámetro de configuración, la tabla 2 describe la configuración deseada: se marca con una palomita para las distribuciones que cumplen con las recomendaciones del KSSP (la explicación de los términos se encuentra en aquí; en futuros artículos hablaremos sobre cómo se desarrollaron muchos de estos métodos de seguridad y cómo vulnerar el sistema en su ausencia).

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

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

En general, los nuevos kernels tienen configuraciones más estrictas por defecto. Por ejemplo, CentOS 6.10 y RHEL 6.10 en el kernel 2.6.32 carecen de la mayoría de las funciones críticas implementadas en los nuevos kernels, tales como SMAP, permisos RWX estrictos, aleatorización de direcciones o protección copy2usr. Cabe destacar que muchas de las opciones de configuración de la tabla no están presentes en versiones anteriores del kernel y no son aplicables en la práctica; en la tabla se indica esto como una falta de protección adecuada. De igual manera, si un parámetro de configuración está ausente en esta versión y es necesario deshabilitar este parámetro por razones de seguridad, se considera una configuración razonable.

Otro aspecto a tener en cuenta al interpretar los resultados es que algunas configuraciones del núcleo que aumentan la superficie de ataque también pueden utilizarse para la seguridad. Ejemplos de esto incluyen uprobes y kprobes, módulos del núcleo y BPF/eBPF. Nuestra recomendación es utilizar los mecanismos mencionados para garantizar una protección real, ya que no son triviales de usar y su explotación supone que los actores malintencionados ya están anclados en el sistema. Sin embargo, si estas opciones están habilitadas, el administrador del sistema debe supervisar activamente posibles abusos.

Al analizar más a fondo las entradas de la tabla 2, vemos que los núcleos modernos ofrecen varias opciones para proteger contra la explotación de vulnerabilidades como las fugas de información y el desbordamiento de pila/montón. Sin embargo, notamos que incluso las distribuciones más recientes y populares aún no han implementado protecciones más complejas (por ejemplo, con parches grsecurity), o protecciones modernas contra ataques de reutilización de código (por ejemplo, una combinación de aleatorización con esquemas de tipo R^X para el código). Lo que es aún peor, incluso estas herramientas de protección más avanzadas no protegen contra todo el espectro de ataques. Por lo tanto, es de suma importancia que los administradores de sistemas complementen configuraciones razonables con soluciones que ofrezcan detección y prevención de exploits en tiempo de ejecución.

Análisis de aplicaciones

No es sorprendente que diferentes distribuciones tengan diferentes características de paquetes, opciones de compilación, dependencias de bibliotecas, etc. Existen diferencias incluso para distribuciones relacionadas y paquetes con pocas dependencias (por ejemplo, coreutils en Ubuntu o Debian). Para evaluar las diferencias, descargamos todos los paquetes disponibles, extraímos su contenido y analizamos los archivos binarios y sus dependencias. Para cada paquete, rastreamos otros paquetes de los que depende, y para cada binario, rastreamos sus dependencias. En esta sección, resumiremos nuestras conclusiones.

Distribuciones

En total, hemos descargado 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 de la filtración, quedaron 129,569 paquetes que contienen un total de 584,457 archivos binarios. La distribución de paquetes y archivos por distribuciones se muestra en la Fig. 3.

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

Se 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 de Ubuntu y Debian incluyen muchos más archivos binarios (tanto ejecutables como módulos dinámicos y bibliotecas) que CentOS, SUSE y RHEL, lo que potencialmente afecta la superficie de ataque de Ubuntu y Debian (hay que notar que las cifras reflejan todos los binarios de todas las versiones del paquete, es decir, algunos archivos se analizan varias veces). Esto es especialmente importante si consideramos las dependencias entre paquetes. Por lo tanto, una vulnerabilidad en el binario de un paquete puede afectar a muchas partes del ecosistema, así como una biblioteca vulnerable puede afectar a todos los archivos binarios que la importan. Tomemos como referencia la distribución del número de dependencias por paquetes en diferentes sistemas operativos:

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

Casi en todas las distribuciones, el 60% de los paquetes tienen al menos 10 dependencias. Además, algunos paquetes tienen un número significativamente mayor de dependencias (más de 100). Lo mismo se aplica a las dependencias inversas de los paquetes: como era de esperar, varios paquetes son utilizados por muchos otros paquetes en la distribución, por lo que las vulnerabilidades en esos pocos elegidos tienen un alto riesgo. Como ejemplo, en la siguiente tabla se enumeran 20 paquetes con la máxima cantidad de dependencias inversas en SLES, CentOS 7, Debian 9 y Ubuntu 18.04 (en cada celda se indica el paquete y el número de dependencias inversas).

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

Dato curioso. Aunque todos los sistemas operativos analizados están construidos para la arquitectura x86_64, y la mayoría de los paquetes tienen su arquitectura definida como x86_64 y x86, los paquetes a menudo contienen archivos binarios para otras arquitecturas, como se muestra en la Fig. 5.

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

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

Estadísticas de protección de archivos binarios

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

$ hardening-check $(which docker)
/usr/bin/docker:
 Ejecutable independiente de posición: sí
 Pila protegida: sí
 Funciones de fuente reforzada: no, ¡solo se encontraron funciones no protegidas!
 Relocalizaciones de solo lectura: sí
 Vínculo inmediato: sí

El script verifica cinco funciones de protección:

  • Ejecutable independiente de posición (PIE): indica si se puede mover en memoria la sección de texto del programa para lograr aleatorización, si ASLR está habilitado en el núcleo.
  • Pila protegida: si se han habilitado las canarias de pila para proteger contra ataques de colisión de pila.
  • Fortify Source: si se reemplazan las funciones inseguras (por ejemplo, strcpy) por sus equivalentes más seguros, y si las llamadas verificadas en tiempo de ejecución son sus equivalentes no verificadas (por ejemplo, memcpy en lugar de __memcpy_chk).
  • Relocalizaciones de solo lectura (RELRO): si las entradas de la tabla de relocación están marcadas como ‘solo lectura’, si se activaron antes de comenzar la ejecución.
  • Vínculo inmediato: si el enlazador de tiempo de ejecución resuelve todos los movimientos antes de que comience la ejecución del programa (esto es equivalente a RELRO completo).

¿Son suficientes los mecanismos mencionados anteriormente? Desafortunadamente, no. Se conocen formas de eludir todas las protecciones mencionadas, pero cuanto más dura sea la protección, mayor será la barra para el atacante. Por ejemplo, los métodos para eludir RELRO son más difíciles de aplicar si PIE y el vínculo inmediato están en funcionamiento. De manera similar, ASLR completo requiere trabajo adicional para crear un exploit funcional. Sin embargo, los atacantes sofisticados ya están listos para afrontar tales protecciones: su ausencia, en esencia, acelera el hackeo. Por lo tanto, es extremadamente importante que estas medidas se consideren como imprescindibles. un mínimo de.

Queríamos estudiar cuántos archivos binarios en las distribuciones consideradas están protegidos por estas y otras tres metodologías:

  • El bit no ejecutable (NX) previene la ejecución en cualquier región que no debería ser ejecutable, como en el montón de pila, etc.
  • RPATH/RUNPATH indica la ruta de ejecución utilizada por el cargador dinámico para buscar las bibliotecas correspondientes. El primero es obligatorio Para cualquier sistema moderno: su ausencia permite a los atacantes escribir de forma arbitraria carga útil en la memoria y ejecutarla tal cual. Para el segundo, las configuraciones incorrectas de las rutas de ejecución ayudan a introducir código poco fiable, lo que puede provocar una serie de problemas (por ejemplo, escalada de privilegios, así como otros problemas).
  • La protección contra colisiones de pila proporciona defensa contra ataques que hacen que la pila se superponga a otras áreas de memoria (por ejemplo, a la heap). Dado los recientes exploits que abusan de vulnerabilidades de colisión en la heap en systemd, consideramos apropiado incluir este mecanismo en nuestro conjunto de datos.

Así que, sin más preámbulos, pasemos a los números. Las tablas 4 y 5 contienen un resumen del análisis de archivos ejecutables y bibliotecas de varias distribuciones, respectivamente.

  • Como se puede observar, la protección NX está implementada en todas partes, con algunas excepciones. En particular, se puede señalar un uso algo más bajo en las distribuciones Ubuntu y Debian en comparación con CentOS, RHEL y OpenSUSE.
  • Las canarios de pila faltan en muchas partes, especialmente en distribuciones con kernels antiguos. Se ha observado cierto progreso en las últimas distribuciones de CentOS, RHEL, Debian y Ubuntu.
  • Con la excepción de Debian y Ubuntu 18.04, la mayoría de las distribuciones tienen un soporte deficiente para PIE.
  • La protección contra colisiones de pila está débilmente implementada en OpenSUSE, CentOS 7 y RHEL 7 y prácticamente no existe en los demás.
  • Todas las distribuciones con kernels modernos tienen algún soporte para RELRO, liderando Ubuntu 18.04, seguida de Debian.

Como ya se mencionó, las métricas en esta tabla son promedios de todas las versiones del archivo binario. Si se observan solo las últimas versiones de los archivos, los números serán diferentes (por ejemplo, ver el progreso de Debian en la implementación de PIE). Además, la mayoría de las distribuciones, al calcular estadísticas, verifican la protección solo de algunas funciones en el código binario, mientras que nuestro análisis indica el verdadero porcentaje de funciones aseguradas. Por lo tanto, si en el binario están protegidas 5 de 50 funciones, le asignaremos una calificación de 0.1, que corresponde al 10% de funciones aseguradas.

Millones de binarios después. Cómo se fortaleció Linux
Tabla 4. Características de protección para archivos ejecutables, mostrados en la figura 3 (implementación de funciones relevantes como porcentaje del total de archivos ejecutables)

Millones de binarios después. Cómo se fortaleció Linux
Tabla 5. Características de seguridad para las bibliotecas mostradas en la fig. 3 (implementación de las funciones correspondientes en porcentaje del total de bibliotecas)

¿Hay progreso? Definitivamente sí: esto se muestra en las estadísticas de distribuciones individuales (por ejemplo, Debian), así como en las tablas anteriores. Como ejemplo, en la fig. 6 se muestra la implementación de mecanismos de seguridad en tres distribuciones sucesivas de Ubuntu LTS 5 (hemos omitido la estadística de protección contra desbordamiento de pila). Observamos que de una versión a otra, cada vez más archivos admiten canarios de pila, y también que cada vez más archivos binarios se entregan con protección completa RELRO.

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

Desafortunadamente, varios archivos ejecutables en diferentes distribuciones aún no cuentan con ninguna de las protecciones mencionadas anteriormente. Por ejemplo, al mirar Ubuntu 18.04, se puede notar el binario ngetty (sustituto de getty), así como las shell mksh y lksh, el intérprete picolisp, los paquetes nvidia-cuda-toolkit (paquete popular para aplicaciones con aceleración por GPU, como los marcos de aprendizaje automático) y klibc-utils. De manera similar, el binario mandos-client (herramienta administrativa que permite reiniciar automáticamente máquinas con sistemas de archivos cifrados), así como rsh-redone-client (reescritura de rsh y rlogin) se entregan sin protección NX, a pesar de que tienen permisos SUID :(. Además, en varios binarios SUID no hay protección básica, como los canarios de pila (por ejemplo, el archivo binario Xorg.wrap del paquete Xorg).

Resumen y observaciones finales

En este artículo, hemos destacado varias características de seguridad de las distribuciones modernas de Linux. El análisis mostró que la última distribución LTS de Ubuntu (18.04) implementa, en promedio, la protección más fuerte a nivel de sistema operativo y aplicaciones entre distribuciones con núcleos relativamente recientes, como Ubuntu 14.04, 12.04 y Debian 9. Sin embargo, las distribuciones consideradas, CentOS, RHEL y OpenSUSE, ofrecen por defecto un conjunto de paquetes más completo, y en las últimas versiones (CentOS y RHEL) tienen un porcentaje más alto de implementación de protección contra colisiones en la pila, en comparación con sus competidores basados en Debian (Debian y Ubuntu). Al comparar las versiones de CentOS y RedHat, notamos grandes mejoras en la implementación de canarias en la pila y RELRO de las versiones 6 a 7, aunque en promedio, CentOS presenta más funciones que RHEL. En general, todas las distribuciones deberían prestar especial atención a la protección PIE, que, a 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, es importante señalar: aunque realizamos la investigación manualmente, existen muchas herramientas de seguridad (por ejemplo, Lynis, Tiger, Hubble), que realizan análisis y ayudan a evitar configuraciones inseguras. Desafortunadamente, incluso una fuerte protección en configuraciones razonables no garantiza la ausencia de exploits. Por eso estamos firmemente convencidos de que es vital asegurar una vigilancia fiable y la prevención de ataques en tiempo real, centrándose en los patrones de explotación y previniéndolos.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster