Windigo no se ha ido: una actualización de Linux/Ebury

Share this…

En febrero de 2014, los investigadores de ESET escribieron sobre un backdoor de OpenSSH y ladrón de credenciales llamado Linux/Ebury. La investigación adicional mostró que este componente era el núcleo de una operación que involucraba múltiples familias de malware, que llamamos “Operación Windigo“. Esto condujo a la publicación de un white paper que analizó la operación completa.

En febrero de 2017 encontramos una nueva muestra de Ebury, que presenta una cantidad significativa de nuevas características. El número de versión subió a 1.6.2a. En el momento de ese descubrimiento, las últimas versiones que habíamos visto eran 1.5.x, meses antes. Después de una investigación más profunda, nos dimos cuenta de que su infraestructura para filtrar credenciales todavía estaba operativa y que Ebury todavía estaba siendo utilizado activamente por la pandilla de Windigo.

Los IoC originales que proporcionamos en 2014 son para la versión 1.4 de Ebury. En su sitio web, CERT-Bund actualizó los IoC para la versión 1.5. En la presente publicación proporcionamos detalles técnicos sobre la versión 1.6, que descubrimos en febrero de 2017. También compartimos IoC actualizados para las versiones 1.5 y 1.6.

Un algoritmo de generación de dominio para extraer credenciales

Ebury v1.4 usa un algoritmo de generación de dominio (domain generation algorithm o DGA) cuando el atacante no se conecta al sistema infectado a través del backdoor de OpenSSH durante tres días. Bajo estas condiciones, Ebury filtrará la información recolectada usando el dominio generado.

Ebury v1.6 tiene el mismo mecanismo, pero hay un cambio menor en el DGA; solo las constantes cambiaron entre estas dos versiones, como muestra la figura 2.

Figura 1: El nuevo DGA de Ebury v1.6 nimplementado en Python

Figura 2: Diferencias entre el DGA en v1.4 y v1.6 implementado en Python

Los primeros diez dominios generados por el DGA son:

  • larfj7g1vaz3y.net
  • idkff7m1lac3g.biz
  • u2s0k8d1ial3r.info
  • h9g0q8a1hat3s.net
  • f2y1j8v1saa3t.biz
  • xdc1h8n1baw3m.info
  • raj2p8z1aae3b.net
  • o9f3v8r1oaj3p.biz
  • tav4h8n1baw3r.info
  • hdm5o8e1tas3n.net

Ebury intenta secuencialmente los nombres de dominio generados hasta que encuentra uno que tiene un registro TXT establecido por el operador. Para verificar la propiedad del dominio, Ebury verifica si el registro TXT se puede descifrar usando una clave pública RSA incrustada en su código:

Figura 3: Registros de DNS para larfj7g1vaz3y[.]net.

El registro A en el dominio es ignorado por Ebury.

Los datos descifrados tienen tres campos separados por comas. Aquí hay un ejemplo de los datos almacenados en la entrada de DNS para larfj7g1vaz3y[.]net en agosto de 2017:

El primer campo contiene el nombre de dominio para que los datos firmados no se puedan reutilizar para otro dominio. El segundo campo es la dirección IP del servidor C&C y el tercero contiene una marca de tiempo UNIX utilizada como fecha de vencimiento de los datos firmados.

La fecha de vencimiento es un nuevo campo agregado como mecanismo anti-sinkhole en v1.6. Si alguien tratara de apoderarse del dominio y la dirección IP del servidor de filtración, solo sería posible reutilizar los datos firmados por un tiempo limitado, reduciendo el impacto de un intento exitoso de sinkhole: algo que sucedió para casi todas las versiones anteriores del DGA.

Tabla 1: Información decodificada almacenada en el registro TXT

Nombre de dominio Dirección IP Fecha de expiración
larfj7g1vaz3y[.]net 0xc6697959 ⇒ 198[.]105.121.89 30/08/2017 @ 9:00pm (UTC)

No creemos que los operadores de Ebury estén pensando usar este mecanismo realmente. En las muestras que analizamos, se encontraron múltiples bugs que evitaban que se ejecutara la rutina, lo que indica que el código no atravesó una fase de pruebas completa.

Por ese motivo, sospechamos que sería bastante extraño que los operadores perdieran acceso a sus máquinas infectadas. También es posible que no les importe perder acceso a una pocas máquinas de vez en cuando, siendo que controlan tantos sistemas comprometidos. Por qué se dedican esfuerzos a un mecanismo que ya no funciona no está claro para nosotros.

Resumen de cambios

  • DGA ligeramente modificado (constantes cambiadas)
  • Se añadió una fecha de expiración para la validez de la entrada DNS del servidor de filtración
  • Nuevo dominio registrado: larfj7g1vaz3y[.]net
  • Nueva dirección IP del servidor de filtración: 198[.]105.121.89

Nuevas funcionalidades

Se añadieron nuevas funcionalidades a la versión 1.6. Por motivos desconocidos, no estaban disponibles en todas las muestras de la v1.6 que analizamos.

Ebury ahora implementa técnicas para ocultarse que generalmente se describen como “userland rootkit“. Para ello, hace un hook a la función readdir o readdir64, cada una de las cuales se usa para enumerar entradas de directorio. Si la siguiente estructura de directorio para devolver es el archivo de biblioteca compartida de Ebury, el hook la saltea y devuelve la entrada siguiente.

Figura 4: Salida Hex-Rays del hook readdir de Ebury

La activación de estos hooks es hecha por Ebury inyectando su biblioteca dinámica en cada proceso descendente de sshd. Para inyectarse en subprocesos, Ebury hace hook a execve y usa la variable LD_PRELOAD del enlazador dinámico. Cada vez que se crea un nuevo proceso, Ebury agrega LD_PRELOAD = <Ebury_filename> a su entorno. Una vez que se ejecuta el nuevo proceso, se carga la biblioteca dinámica de Ebury y se llama a su constructor, ejecutando las rutinas de hook.

Como se menciona en un artículo en srvfail.com, hay un hilo en StackExchange de un usuario que afirma que Ebury ha comprometido su máquina. El comportamiento que describe corresponde a las técnicas de auto-ocultación de las que hemos sido testigos en Ebury v1.6.2a.

Las versiones anteriores de Ebury solían funcionar solo en versiones muy específicas de OpenSSH y eran específicas para distribuciones de Linux. Normalmente, las muestras anteriores de Ebury funcionarían para entre tres y cinco compilaciones de OpenSSH para una determinada distribución de Linux. Este ya no es el caso. La mayoría de las rutinas de parcheo de OpenSSH fueron reemplazadas por el hooking de funciones. Ya no hay compensaciones hardcodeadas. Intentamos instalar Ebury en máquinas que ejecutan Debian Jessie, CentOS 7 y Ubuntu Artful con la misma muestra y funcionó en todos los casos.

Para inyectar la configuración del servidor OpenSSH directamente en la memoria, Ebury analiza la sección del código del binario sshd mapeada en el mismo proceso buscando dos funciones diferentes. Intenta encontrar la dirección de parse_server_config o process_server_config_line.

Si falla, degrada las características de seguridad al deshabilitar el control de acceso basado en roles SELinux y al desactivar los módulos PAM. Cuando una de las funciones se resuelve con éxito, Ebury lo aprovechará cuando el backdoor se use para alterar la configuración de sshd.

Figura 5: Configuración usada por el backdoor de Ebury.

Los autores de Ebury también endurecieron su mecanismo de backdoor. En lugar de confiar solo en una contraseña codificada en la string de la versión del cliente SSH, la activación ahora requiere una clave privada para autenticarse. Es posible que esta verificación adicional se haya agregado para evitar que otras personas que hayan encontrado la contraseña del backdoor puedan usarla para obtener acceso al servidor comprometido de Ebury.

Figura 6: Clave pública de RSA de los operadores de Ebury.

Cuando hay un intento de conexión al backdoor, Ebury modifica la opción AuthorizedKeysFilepara que apunte a /proc/self/ environ. Hace hook a open o open64 y comprueba si hay un intento de abrir /proc/self/environ o una ruta que contenga .ssh/authorized_keys. La segunda verificación se puede usar como una alternativa en caso de que Ebury no haya podido resolver parse_server_config y process_server_config_line para enviar su propia configuración.

Ebury también hace hook a fgets que es llamada por sshd para leer el contenido del archivo authorized_keys. Se utiliza una variable global para asegurarse de que se invoca a fgetsdespués de que se abrió el archivo authorized_keys. Luego, el hook llena el buffer de fgets con la clave pública de los operadores de Ebury, por lo que la clave del atacante se usa para la autenticación.

Figura 7: Salida Hex-Rays del hook fgets

Algo que sigue siendo un misterio para nosotros es el propósito de este hook memcpy:

Figura 8. Salida Hex-Rays del hook memcpy.

Si bien sabemos que el hook es usado para eliminar el algoritmo chacha20-poly1305 durante el intercambio de clave SSH, no comprendemos por qué los autores de Ebury no quieren que se use este algoritmo.

Nuevos métodos de instalación

Anteriormente, Ebury agregó su payload dentro de la biblioteca libkeyutils.so. El archivo contendría las funciones legítimas de libkeyutils y el código malicioso Ebury, que se inicia al cargarse. Cuando se viera comprometido, el archivo era más grande de lo normal, una señal de compromiso que compartimos en 2014.

Si bien hemos visto esta técnica utilizada por la versión 1.6, los autores de Ebury han ideado nuevos trucos para engañar a nuestros IoC. Todavía usan el archivo libkeyutils.so, pero de manera diferente.

Según lo que hemos visto, las secuencias de comandos y las técnicas de implementación parecen diferir en función de la distribución de Linux del sistema de destino.

Debian/Ubuntu

En sistemas Debian/Ubuntu, Ebury se implementa actualmente utilizando un nuevo método. Dado que libkeyutils.so es cargado por el cliente OpenSSH y los ejecutables del servidor OpenSSH, sigue siendo un objetivo interesante para los atacantes.

Hemos visto previamente a Ebury instalado cambiando el enlace simbólico libkeyutils.so.1 para que apunte a la versión maliciosa de la biblioteca. La biblioteca alterada tendría un constructor donde se almacena el código de inicialización de Ebury. Cada vez que se carga libkeyutils.so, se llama al constructor. Por lo tanto, cada vez que se lanza el cliente o servidor OpenSSH, Ebury se inyecta en el proceso.

El último método de implementación en Debian/Ubuntu ahora se basa en el parcheo de libkeyutils.so para forzarlo a cargar Ebury, que se almacena en un archivo .so separado. Comparando una versión original y una parcheada, notamos que hay una entrada adicional en la sección .dynamic del encabezado ELF. Esta entrada es de tipo NEEDED (0x01), lo que significa que es una dependencia de este ejecutable y que se cargará en tiempo de ejecución. En el script de implementación que hemos analizado, la biblioteca que se va a cargar se llama libsbr.so y contiene el código malicioso de Ebury.

Figura 9: Diferencia entre sección dinámica de una versión original y una parcheada de libkeyutils.so.

El proceso de parcheo tiene dos pasos. Primero, la cadena “libsbr.so” debe almacenarse en la tabla de strings del binario. En segundo lugar, debe agregarse una nueva entrada de tipo 0x1 (DT_NEEDED) a la sección dinámica de los encabezados ELF. Esta entrada debe apuntar a la string de la biblioteca con un desplazamiento en la tabla de strings. Los autores de Ebury reemplazan la cadena “__bss_start” por “_\ x00libsbr.so“. Como __bss_start no es utilizado por el enlazador dinámico, la modificación de este símbolo no tiene ningún impacto en la ejecución de la biblioteca. La Figura 10 muestra la diferencia entre el original y la tabla de strings alteradas delibkeyutils.so.

Figura 10: Diferencias entre una tabla de strings original y una parcheada

Ahora que la cadena “libsbr.so” se almacena en la tabla de strings, se debe agregar una nueva entrada en la sección .dynamic. La Figura 11 muestra la diferencia entre la sección .dynamic del original y del parcheado libkeyutils.so.

Figura 11: Diferencias entre sección .dynamic original y parcheada

La sección.dynamic contiene un array de Elf64_Dyn para binarios de amd64 y Elf64_Dyn para binarios de i386. Las definiciones de estas estructuras se muestran en la figura 12.

Figura 12: Estructuras relacionadas a la sección .dynamic

En la figura 13, tenemos una versión para 64 bits de libkeyutils.so. Por lo tanto, la nueva entrada en la sección .dynamic podría ser escrita como sigue:

Figura 13: Nueva entrada .dynamic

El primer campo es 0x1, que se traduce a la etiqueta DT_NEEDED. El segundo campo es el desplazamiento para la string libsbr.so en la table de strings: 0x3F8.

Para ser más sigilosos, los operadores de Ebury se ocupan de parchear las sumas MD5 del paquete libkeyutils1. Así que no es posible verificar si un sistema está infectado mirando la integridad del paquete; un comando a tal fin no mostraría errores:

Se usan múltiples nombres de archivo cuando Ebury se implementa como biblioteca independiente. Esta es la lista de nombres de archivo que conocemos:

  • libns2.so
  • libns5.so
  • libpw3.so
  • libpw5.so
  • libsbr.so
  • libslr.so

CentOS

En CentOS se utilizan técnicas similares a la descrita para la implementación de Debian/Ubuntu. Los atacantes parchearían libkeyutils.so para forzarlo a cargar una biblioteca adicional. Además, notamos una nueva técnica utilizada para implementar Ebury en los sistemas CentOS/RedHat.

Todavía no conocemos todos los detalles sobre cómo funciona el proceso de instalación. El análisis de varios informes en línea nos ayudó a hacer algunas conjeturas sobre cómo ocurre la implementación.

Sabemos que Ebury se implementó como un objeto compartido separado cargado por libkeyutilsde una manera similar a la implementación de Debian. Pero también fuimos testigos de otro método de instalación, que creemos que es el método de implementación para v1.6.

Como fue el caso en lanzamientos anteriores de Ebury, los operadores construyen su propia versión de libkeyutils.so a la cual agregan un constructor que contiene el código malicioso. En lugar de alterar libkeyutils.so.1 desde /lib/ o /lib64/ usan la carpeta /lib {, 64}/tls/ para cargar su archivo porque el enlazador dinámico mira primero este directorio cuando se resuelven las dependencias.

Creemos que el proceso de implementación para esta versión es cargar Ebury en /lib/tls/ o /lib64/tls/ dependiendo de la arquitectura del sistema de la víctima. Luego, al ejecutar ldconfig se creará automáticamente un enlace simbólico /lib{,64}/tls/libkeyutils.so.1que apunta al objeto compartido malicioso.

Figura 14: Uso de ldconfig para cargar Ebury en /lib64/tls/

Además, crea un sistema de desinstalación simple que no requiere manipular enlaces simbólicos y mantener algunas copias de seguridad del objeto compartido original de libkeyutils en caso de que algo salga mal durante el proceso de implementación. Lo único que se necesita es borrar el archivo libkeyutils.so malicioso en la carpeta /lib {,64}/tls/, luego ejecutar ldconfignuevamente y el sistema vuelve a su estado original.

Figura 15: Uso de ldconfig para desinstalar Ebury

El subdirectorio tls se usa junto con una funcionalidad del loder de Linux en la que si el CPU soporta un conjunto de instrucciones adicional, el incluido en ese directorio se impone por sobre el “regular”. El directorio tls es en realidad para una pseudo-hwcap de “TLS support” que está siempre presente actualmente.

Conclusión

Incluso después del arresto de Maxim Senakh, el núcleo de Windigo aún está en funcionamiento. Ebury, el componente principal de la botnet de Linux, ha pasado por importantes actualizaciones.

Ahora usa técnicas de auto-ocultación y nuevas formas de inyección en procesos relacionados con OpenSSH. Además, usa un nuevo algoritmo de generación de dominio (DGA) para encontrar qué registro de TXT de dominio buscar. La dirección IP del servidor de filtración está oculta en estos datos, firmada con la clave privada de los atacantes.

Fuente:https://www.welivesecurity.com/la-es/2017/10/30/windigo-actualizacion-linux-ebury/