InfraFenceInfraFence

Live Security Operations

Empezar

Cómo detectar y eliminar un rootkit en /etc/ld.so.preload

Última actualización:

/etc/ld.so.preload lista bibliotecas que el enlazador dinámico carga en cada programa antes que cualquier otra cosa. En un servidor normal el archivo no existe. Los atacantes que consiguen root escriben ahí una biblioteca que sustituye funciones de la biblioteca C, como las que listan directorios o abren archivos, para que ps, top, ls, netstat y ss dejen de mostrar los procesos, archivos y conexiones del atacante. Kits de código abierto como libprocesshider, Azazel y Jynx funcionan así, igual que varias familias de mineros de criptomonedas y puertas traseras.

El punto débil del truco es que solo funciona en programas que cargan la biblioteca C. Las herramientas enlazadas estáticamente, la lectura directa de /proc y una mirada desde fuera del sistema en ejecución lo esquivan. A continuación: cómo comprobarlo, cómo limpiarlo y cuándo reconstruir el servidor. Los comandos son para Debian y Ubuntu y para la familia RHEL; /usr/lib/libhide.so representa la biblioteca que encuentres.

Entender cómo se oculta un rootkit de precarga

  • Procesos: ps y top leen el directorio /proc; un readdir() interceptado se salta los ID de proceso del atacante.
  • Archivos: el mismo hook oculta archivos por nombre, a menudo incluidos el propio /etc/ld.so.preload y la biblioteca, así que ls y cat dicen que no existen.
  • Conexiones: netstat y ss pierden las líneas de los sockets del atacante.
  • Todo lo demás funciona con normalidad, y de eso se trata: el servidor parece limpio ante todas las herramientas en las que confiarías normalmente.

De lo que no puede esconderse: de los programas que no usan la biblioteca C del sistema (binarios enlazados estáticamente como busybox-static), del kernel y de un sistema arrancado desde otro medio. Un rootkit cargado como módulo del kernel es otro caso, más difícil: se oculta del propio /proc, y las comprobaciones siguientes pueden no detectarlo.

Comprobar con herramientas que el rootkit no puede engañar

Conseguir un busybox enlazado estáticamente

busybox-static es un único binario con ls, cat, grep, sh y más, enlazado sin la biblioteca C, así que una biblioteca precargada nunca se carga en él. ldd debe responder not a dynamic executable.

Debian / Ubuntu
sudo apt install busybox-static
ldd /bin/busybox

La familia RHEL no tiene un busybox estático en sus repositorios base. Copia uno desde una máquina Debian o Ubuntu limpia (tras instalar allí busybox-static) y llámalo como /root/busybox en lugar de busybox en los comandos siguientes:

En tu máquina limpia
scp /bin/busybox root@SERVER_IP:/root/busybox
ssh root@SERVER_IP 'chmod 700 /root/busybox && ldd /root/busybox'

Nota: Instalar un paquete en un servidor comprometido pasa por su propio gestor de paquetes, enlazado dinámicamente. Una copia desde una máquina limpia es la opción más fiable en cualquier distribución.

Leer el archivo directamente

Compara lo que ve busybox con lo que ven las herramientas del propio sistema. Si busybox muestra el archivo y los ls y cat normales dicen que no existe, hay un rootkit activo en este momento.

Cualquier distribución
sudo busybox ls -la /etc/ld.so.preload
sudo busybox cat /etc/ld.so.preload
ls -la /etc/ld.so.preload
cat /etc/ld.so.preload

Para cada biblioteca que nombra el archivo, comprueba si pertenece a un paquete. Existen usos legítimos poco frecuentes, como el registrador de comandos Snoopy y algunos agentes de monitorización, y vienen de un paquete que tú instalaste:

Debian / Ubuntu
dpkg -S /usr/lib/libhide.so
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, Fedora
rpm -qf /usr/lib/libhide.so

Una biblioteca que no pertenece a ningún paquete es sospechosa. Anota su tamaño y su hash, mira los nombres que contiene (funciones interceptadas como readdir, la palabra /proc) y qué procesos la tienen cargada:

Cualquier distribución
sudo busybox ls -la /usr/lib/libhide.so
sudo busybox sha256sum /usr/lib/libhide.so
sudo busybox strings /usr/lib/libhide.so | busybox grep -iE 'readdir|/proc|preload|hide' | busybox head
Cualquier distribución
sudo busybox sh -c "busybox grep -l '/usr/lib/libhide.so' /proc/[0-9]*/maps"

Comparar /proc con ps

busybox lee /proc sin el hook; ps lo usa. Cada ID de proceso que busybox encuentra y ps no está oculto, y la línea muestra su binario. Los procesos que terminaron durante el bucle pueden aparecer una vez: ejecútalo dos veces y fíjate en los ID que aparecen en ambas.

Cualquier distribución
sudo busybox sh -c 'for d in /proc/[0-9]*; do p=${d#/proc/}; /bin/ps -p "$p" > /dev/null 2>&1 || echo "$p $(busybox readlink "$d/exe")"; done'

Lo mismo con las conexiones de red: el netstat de busybox lee /proc/net directamente. Una conexión que está en la primera lista y falta en la segunda está oculta.

Cualquier distribución
sudo busybox netstat -tan
sudo ss -tanp

LD_PRELOAD en entornos y servicios

El mismo truco funciona por proceso, mediante la variable LD_PRELOAD en un archivo de unidad, un perfil de shell o /etc/environment. Búscala en los procesos en ejecución y en los archivos habituales:

Cualquier distribución
sudo busybox sh -c "busybox grep -l LD_PRELOAD /proc/[0-9]*/environ"
sudo busybox grep -rs LD_PRELOAD /etc/environment /etc/profile /etc/profile.d /etc/bash.bashrc /etc/bashrc \
  /etc/systemd /lib/systemd/system /usr/lib/systemd/system /root/.bashrc /root/.profile

Binarios del sistema modificados

Algunos kits sustituyen además ps, ls o sshd. La base de datos de paquetes lista los archivos empaquetados cuyo contenido cambió (sin los archivos de configuración):

Debian / Ubuntu
sudo dpkg --verify | grep -v ' c /'
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, Fedora
sudo rpm -Va 2>/dev/null | grep -E '^..5' | grep -v ' c /'

La forma segura: desde un sistema de rescate

dpkg y rpm también están enlazados dinámicamente. Para un resultado fiable, arranca el sistema de rescate del proveedor, monta el disco del servidor y lee allí el archivo, donde no se está ejecutando nada del servidor. Busca antes la partición raíz con lsblk: /dev/sda1 es un ejemplo.

Sistema de rescate
lsblk -f
mount /dev/sda1 /mnt
ls -la /mnt/etc/ld.so.preload && cat /mnt/etc/ld.so.preload

Eliminar el rootkit de precarga

Si el proveedor puede hacer una instantánea del disco, hazla primero. Después guarda una copia del archivo y de la biblioteca como prueba:

Cualquier distribución
sudo busybox mkdir -p /root/evidence
sudo busybox cp -a /etc/ld.so.preload /usr/lib/libhide.so /root/evidence/
sudo busybox sha256sum /root/evidence/*

Los rootkits suelen hacer inmutables sus archivos, de modo que incluso root recibe Operation not permitted. El busybox-static de Debian no tiene chattr; los lsattr y chattr del propio sistema sirven aquí, porque los kits de precarga ocultan archivos por nombre y no suelen tocar los atributos:

Cualquier distribución
sudo lsattr /etc/ld.so.preload /usr/lib/libhide.so
sudo chattr -i -a /etc/ld.so.preload /usr/lib/libhide.so

Elimina el archivo de precarga con busybox. Desde el siguiente programa que se inicie, ya no se precarga nada, y el ls normal confirma que el archivo ha desaparecido:

Cualquier distribución
sudo busybox rm /etc/ld.so.preload
ls -la /etc/ld.so.preload

Los procesos que ya estaban en marcha siguen teniendo la biblioteca cargada, pero los nuevos ps y ss que ejecutes ya no, así que lo que estaba oculto ahora se ve. Búscalo, y congela lo que no deba estar ahí antes de matarlo:

Cualquier distribución
ps -ef --forest | less
sudo ss -tanp
sudo kill -STOP PID

Elimina lo que lo hace volver: tareas de cron, unidades de systemd, claves SSH y cuentas, como en Cómo encontrar y eliminar un minero de criptomonedas, que repasa cada lugar. Después borra la biblioteca y reinicia, para que ningún proceso en ejecución la conserve:

Cualquier distribución
sudo busybox rm /usr/lib/libhide.so
sudo ldconfig
sudo reboot

Atención: Da por hecho que todos los secretos del servidor son conocidos: claves SSH, contraseñas, contraseñas de bases de datos y claves de API en los archivos de configuración. El atacante tuvo root. Cámbialos desde una máquina limpia.

Decidir cuándo reconstruir el servidor

Escribir /etc/ld.so.preload requiere root. Una vez que un atacante ha tenido root, la limpieza elimina lo que encontraste, no necesariamente todo lo que había. Reconstruye desde una imagen nueva cuando se cumpla cualquiera de estas condiciones:

  • Han cambiado binarios del sistema (la comprobación de paquetes de arriba).
  • El kernel está marcado (tainted) por un módulo desconocido, o lsmod lista un módulo que no sabes explicar.
  • No has averiguado cómo entró el atacante.
  • El servidor guarda datos de clientes, datos de pago o credenciales de otros sistemas.
Cualquier distribución
cat /proc/sys/kernel/tainted
lsmod | sort | head -50
sudo dmesg | grep -iE 'taint|module verification|unsigned'

Un 0 en tainted indica un kernel limpio; otros valores tienen motivos, como los drivers propietarios, así que búscalos antes de sacar conclusiones. Para reconstruir: crea un servidor nuevo desde la imagen del proveedor, actualízalo, restaura los datos (no programas ni configuraciones que no puedas comprobar) desde una copia de seguridad anterior a la infección, cambia todos los secretos y después traslada el tráfico. La checklist para un VPS nuevo cubre la primera hora.

Cómo detecta InfraFence los rootkits de ld.so.preload

El agente de InfraFence es un programa enlazado estáticamente: no carga la biblioteca C del sistema, así que una biblioteca precargada no se ejecuta dentro de él y no puede ocultar archivos ni procesos a lo que el propio agente lee.

  • Integridad de archivos: /etc/ld.so.preload está entre los archivos vigilados, con una huella SHA-256 que se compara cada 30 minutos. Un cambio en él se notifica como un evento integrity_change crítico con el hash anterior y el nuevo. Consulta Integridad de archivos y persistencia.
  • Escaneo de malware, integridad del sistema: un /etc/ld.so.preload con entradas es un hallazgo crítico que muestra su contenido; los procesos presentes en /proc pero ausentes de ps se notifican como ocultos; también se notifican los ejecutables en /tmp y /dev/shm y los binarios del sistema modificados desde que se instaló su paquete (dpkg -V, rpm -Va). Consulta Malware.
  • La misma vigilancia cubre la persistencia que suele acompañarlo: crontabs, unidades de systemd, authorized_keys y sudoers.

Límites: las huellas se toman cuando arranca el agente, así que la vigilancia de integridad notifica cambios en un archivo que ya existía entonces; un /etc/ld.so.preload que aparece después, en un servidor que no lo tenía, lo encuentra el escaneo de malware. Los escaneos se ejecutan según la programación que fijes (los escaneos automáticos están desactivados por defecto) o cuando pulsas **Escanear ahora**. Un rootkit cargado como módulo del kernel también puede ocultarse de /proc, e InfraFence no tiene una detección específica para él. InfraFence nunca borra /etc/ld.so.preload ni la biblioteca: la limpieza y la decisión de reconstruir siguen siendo cosa tuya.

Preguntas

¿/etc/ld.so.preload es siempre malicioso?
No, pero es raro. Un servidor normal no lo tiene. Unas pocas herramientas legítimas lo usan, como el registrador de comandos Snoopy, y vienen de un paquete que instalaste: dpkg -S o rpm -qf sobre la biblioteca te lo dice.
¿Basta con borrar el archivo?
Detiene la ocultación para todos los programas nuevos, y por eso es el primer paso. No elimina lo que el atacante hizo con root: persistencia, otras puertas traseras, secretos robados. Para eso está el resto de la limpieza, o la reconstrucción.
¿Lo detectan rkhunter y chkrootkit?
Buscan bibliotecas precargadas y kits conocidos, y vale la pena ejecutarlos. Son scripts que llaman a las herramientas del propio sistema, así que en un sistema infectado pueden recibir la misma vista oculta. Ejecútalos desde un sistema de rescate para un resultado fiable.

Pruébalo gratis en 1 servidor

Starter es gratuito para un servidor, con protección completa y bloqueo automático. Sin tarjeta de crédito.

Instala el agente como root, con tu token en lugar de <TOKEN>:

curl -fsSL https://github.com/infrafence/infrafence-agent/releases/latest/download/install.sh | sudo bash -s -- --token <TOKEN>

El token se crea en el panel, en Servidores › Añadir servidor.