Inicio / Blog / Malware en Linux: Rootkits, introducción y clasificación

Malware en Linux: Rootkits, introducción y clasificación

Publicado el 05/03/2015, por Antonio López (INCIBE)
Malware en Linux

El malware en general, y los rootkits en particular, pueden funcionar igual de bien en un sistema operativo Linux como en uno Windows. Desde Windows XP la seguridad de los sistemas de Microsoft ha mejorado sensiblemente y no podemos atribuir a esta razón la existencia de más cantidad de malware para estas plataformas.

Sin embargo, desde el punto de vista del creador de malware, siempre resultará mucho más atractivo un sistema Windows frente a Linux por ser mucho más común y compatible entre sí, contar con más usuarios y estar casi omnipresente en cualquier lugar. El uso de Linux es creciente y en los últimos años el fenómeno IoT ó Internet de las cosas , el número de dispositivos con conectividad a Internet que implementan software libre y Linux ha crecido exponencialmente. Este crecimiento significa mayores oportunidades y un gran terreno por explotar para los creadores de malware.

Como ilustración, en 2014 la operación Windigo orquestada por ESET sacó a la luz un informe sobre código malicioso con más de 25000 servidores afectados en el mundo, gran parte de ellos Linux. El año pasado fue especialmente interesante al descubrirse graves vulnerabilidades como Heartbleed o Shellshock que también afectaban a sistemas Linux/Unix y que sin duda fueron aprovechadas para comprometer servidores. Es patente que no solo de Windows vive el malware.

Especialmente, por sus capacidades vamos a hablar de rootkits en Linux de sus tipos, sus características y mostrar algún ejemplo ilustrativo.

 

Comprometiendo un sistema: Rootkits

 ¿Qué es un rootkit, y cómo funciona?

Un rootkit debe considerarse como una "herramienta" que puede actuar independientemente, o bien acompañar a cualquier variante de código malicioso con el objetivo principal de ocultar su actividad a usuarios y administradores del sistema. Comprender el funcionamiento de un rootkit aportará un conocimiento de gran utilidad para detectar la presencia de estos elementos no deseados.

Básicamente la misión principal de un rootkit es la de ocultar información: procesos, conexiones de red, ficheros, directorios, elevación de privilegios, etc. Adicionalmente puede incorporar otras funcionalidades como las de backdoor o puerta trasera para proporcionar acceso permanente al sistema o las de keylogger para interceptar las pulsaciones del teclado.

 

Tipos de rootkits. Espacio de usuario y espacio de kernel

 

En general un sistema operativo cuenta con dos áreas de memoria bien diferenciada: el espacio de usuario y el espacio de kernel. En una arquitectura típica, estos espacios se ubican en "anillos de seguridad" con nivel de privilegios distintos.

 

En el espacio de usuario correspondiente al anillo menos privilegiado (anillo3) se ejecutan las aplicaciones en un entorno controlado, que no tiene acceso directo a los recursos (memoria, disco, dispositivos, etc.) si no que debe solicitarlo a través de llamadas al sistema. En el espacio de kernel (anillo 0, de máximo privilegio) se gestiona y se tiene acceso total a cualquier recurso, siendo donde se ejecuta el núcleo del sistema operativo. Los anillos intermedios no son de implementación frecuente y en la mayoría de sistemas solo tendremos que contar con el espacio de usuario y el espacio de kernel.

Teniendo en cuenta esta segmentación podemos clasificar dos variantes principales de rootkits: rootkits en espacio de usuario y rootkits en espacio de kernel. Lógicamente dados los distintos niveles de privilegios de los dos espacios, un rootkit de kernel será mucho más avanzado, potente y difícil de detectar que un rootkit en espacio de usuario.

 

Rootkit en espacio de usuario

 

 Este tipo de rootkit se ejecuta en el espacio de usuario al mismo nivel que otras aplicaciones y otros binarios. Este tipo de rootkit habitualmente sustituye ejecutables legítimos del sistema por otros modificados, de modo que la información que proporcionan esté manipulada según interese. Entre los principales binarios objetivo de un rootkit para conseguir su ocultación y operación se encuentran los siguientes:

  • Ficheros: ls, df, stat, du, find, lsof, lsattr, chattr, sync
  • Conexiones: ip, route, neststat, lsof, nc, iptables, arp…
  • Procesos: ps, top, pidof, kill, lsof…
  • Tareas: crontab, at…
  • Logs: syslogd, rsyslogd…
  • Accesos: sshd, login, telnetd, inetd, passwd, last, lastlog,su, sudo, who, w, runlevel…

La opción de cambiar binarios es bastante tosca y de fácil detección y con frecuencia se complementa con otras técnicas que tratan modificar al vuelo la ejecución, interceptando las llamadas a librerías dinámicas. Lógicamente, esto solo es posible si el binario a intervenir no está compilado estáticamente, en cuyo caso no llamará a librerías externas.

Esto posibilita al rootkit interferir en tiempo de ejecución con binarios que hagan uso de librerías dinámicas. Es habitual que estas librerías se intercepten a través de variables del sistema como LD_PRELOAD, LD_LIBRARY_PATH, o mediante ficheros de caché (/etc/ld.so.cache) y configuración (/etc/ld.so.preload). De este modo, se pretende precargar o desviar llamadas a librerías para dirigirlas a otras manipuladas puesto que, en la ejecución se comprobarán estas variables y ficheros.

- Ejecución de /bin/ls, obsérvese comprobación de ficheros -

Ejemplo de interceptación de librerías con LD_PRELOAD.

El ejecutable ls está dinámicamente compilado y en su ejecución se llaman varias librerías externas:

- Librerías dinámicas utilizadas por /bin/ls -

A su vez, estas librerías ejecutan funciones que pueden estar autocontenidas o en otras librerías. Entre las funciones que se invocan se encuentra entre otras la función srtlen, la cual encuentra en la librería string.h. Esta función quizás no es la mejor elección pues puede ser llamada por muchos otros binarios, pero para mostrar un ejemplo sencillo, servirá:

- Llamada a librerías al ejecutar el comando "ls". (fragmento de la salida) -

La idea es interponerse en alguna llamada a la librería (hooking) que contiene la función y modificar el comportamiento de esa función. Una de las posibilidades de entre las descritas para realizar la interceptación, es utilizar la variable de entorno LD_PRELOAD. Para ello, creamos una librería propia que nos defina la función a interceptar, en este caso strlen, adaptar su comportamiento según objetivo y hacer que el ejecutable la encuentre antes que la original, aprovechando la variable LD_PRELOAD:

- Programa para definir una función strlen falsa. Gracias a LD_PRELOAD, el binario ejecutará esta función en lugar de la original -

Compilando el código con los flags apropiados, generamos una librería dinámica:

gcc -shared -fPIC -Wall -o mi_ls.so mi_ls.c

A continuación, fijamos la variable de entorno LD_PRELOAD y  comprobamos la efectividad del "hook" al ejecutar el comando ls . Con ello, el sistema carga previamente la librería creada con la función strlen manipulada :

- Efecto de interceptar una librería dinámica y sustituir la función strlen -

De forma muy sencilla, hemos aprovechado una llamada  a la librería por parte de un ejecutable dinámico para interceptar la ejecución del comando ls y modificar su salida.

Como se ha mostrado estos rootkits son de muy fácil implementación, pero en contrapartida son relativamente sencillos de detectar mediante comprobaciones básicas (hash) de la integridad de los binarios, verificación de variables de entorno (que modifiquen el path), seguimiento de enlaces simbólicos, rutas y configuración de librerías dinámicas, etc.

Por otra parte, el número de binarios a modificar y su compilación específica para cada versión de kernel, presenta una gran dificultad a superar de cara a la programación de este tipo de rootkits. Además el uso de precarga de librerías dinámicas está limitado por medidas de seguridad del kernel que impiden que estas librerías se carguen si suponen un problema de seguridad como, por ejemplo, la elevación de privilegios.

Todas estas razones hacen que los rootkits en espacio de usuario hayan quedado obsoletos frente a variedades más avanzadas que sacan partido del espacio de kernel.

 

Rootkit en espacio de kernel

 

Sin lugar a dudas, el objetivo más interesante para un atacante tras acceder a un sistema y conseguir privilegios de superusuario es instalar un rootkit en modo kernel y, de este modo asegurarse un control total del sistema a la par que una mejor ocultación. Una vez integrado en el sistema, su detección es mucho más complicada pues se mueven en un nivel de privilegio superior que les brinda permisos para poder modificar, ya no solo los binarios en sí, sino las propias funciones y llamadas del sistema operativo.

En este caso el diseño del rootkit debe ser mucho más elaborado, puesto que al trabajar en espacio de kernel e interaccionar con funciones y llamadas del sistema básicas, cualquier defecto en su funcionamiento puede provocar un fallo en el kernel con consecuencias fatales.

 

Bootkits

 

Finalmente, podemos hablar de otra variedad de rootkits, los bootkits. Los bootkits dan un paso más al incorporar funcionalidades de arranque a los rootkits y afectando al firmware de sistemas y sectores de arranque de discos. Con ello, a la dificultad intrínseca de su detección se añade persistencia y resistencia a ser eliminado.

Un ejemplo muy reciente es Thunderstrike, un bootkit para MacBooks que modifica el firmware de la EFI de arranque haciéndolo persistente a reinstalación de SO e incluso a sustitución del disco. Fue presentado por el investigador Trammell Hudson en la Chaos Computer Congress celebrada en Alemania en diciembre de 2014.

En próximos artículos seguiremos hablando de este interesante asunto y se describirán los rootkits en espacio de kernel y los mecanismos de ocultación que se suelen emplear.