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:
psytopleen el directorio/proc; unreaddir()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.preloady la biblioteca, así quelsycatdicen que no existen. - Conexiones:
netstatysspierden 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.
sudo apt install busybox-static
ldd /bin/busyboxLa 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:
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.
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.preloadPara 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:
dpkg -S /usr/lib/libhide.sorpm -qf /usr/lib/libhide.soUna 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:
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 headsudo 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.
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.
sudo busybox netstat -tan
sudo ss -tanpLD_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:
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/.profileBinarios 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):
sudo dpkg --verify | grep -v ' c /'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.
lsblk -f
mount /dev/sda1 /mnt
ls -la /mnt/etc/ld.so.preload && cat /mnt/etc/ld.so.preloadEliminar 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:
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:
sudo lsattr /etc/ld.so.preload /usr/lib/libhide.so
sudo chattr -i -a /etc/ld.so.preload /usr/lib/libhide.soElimina 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:
sudo busybox rm /etc/ld.so.preload
ls -la /etc/ld.so.preloadLos 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:
ps -ef --forest | less
sudo ss -tanp
sudo kill -STOP PIDElimina 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:
sudo busybox rm /usr/lib/libhide.so
sudo ldconfig
sudo rebootAtenció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
lsmodlista 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.
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.preloadestá entre los archivos vigilados, con una huella SHA-256 que se compara cada 30 minutos. Un cambio en él se notifica como un eventointegrity_changecrítico con el hash anterior y el nuevo. Consulta Integridad de archivos y persistencia. - Escaneo de malware, integridad del sistema: un
/etc/ld.so.preloadcon entradas es un hallazgo crítico que muestra su contenido; los procesos presentes en/procpero ausentes depsse notifican como ocultos; también se notifican los ejecutables en/tmpy/dev/shmy 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_keysy 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 -Sorpm -qfsobre 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.
