InfraFenceInfraFence

Live Security Operations

Empezar

Cómo encontrar y eliminar un minero de criptomonedas de tu servidor

Última actualización:

Un minero de criptomonedas es lo más habitual que se encuentra en un servidor Linux comprometido. Usa toda la CPU que puede para minar Monero u otra moneda para otra persona, y la primera señal suele ser un sitio lento, un ventilador a tope, una factura por créditos de CPU o un correo de abuso del proveedor.

El minero en sí es la parte fácil. Lo que importa es lo que lo dejó entrar y lo que lo hace volver: una tarea de cron, una unidad de systemd, una clave SSH, una biblioteca precargada en cada proceso. Sigue este orden: encontrar, contener, eliminar, encontrar el punto de entrada, reforzar. Los comandos son para Debian y Ubuntu y para la familia RHEL; PID es el ID del proceso que encuentres en el paso 1.

Detectar el minero

Empieza por lo que consume CPU. Un minero suele ocupar un proceso al 100% por núcleo, en marcha desde hace días.

Cualquier distribución
ps -eo pid,user,%cpu,etime,args --sort=-%cpu | head -n 15
  • Nombres: xmrig y sus variantes, o nombres elegidos para parecer inofensivos: kdevtmpfsi, kinsing, kworkerds, un [kthreadd] escrito a mano, una cadena aleatoria.
  • Un hilo del kernel aparece entre corchetes y no tiene binario: un nombre entre corchetes con una ruta detrás es falso.
  • El usuario: un minero que se ejecuta como www-data, apache, nginx, redis o postgres entró por ese servicio.

Para un PID sospechoso, mira su binario, su directorio de trabajo, su línea de comandos completa y qué unidad de systemd lo arrancó:

Cualquier distribución
sudo ls -l /proc/PID/exe /proc/PID/cwd
sudo tr '\0' ' ' < /proc/PID/cmdline; echo
systemctl status PID

Un binario que muestra (deleted), o que se ejecuta desde /tmp, /var/tmp o /dev/shm, es una señal clara. Esto lista todos esos procesos de una vez:

Cualquier distribución
sudo ls -l /proc/[0-9]*/exe 2>/dev/null | grep -E '\(deleted\)|/tmp/|/var/tmp/|/dev/shm/'

Cuando top no muestra nada: ld.so.preload

Si la carga es alta pero ningún proceso la explica, puede que el minero se esconda tras una biblioteca que se carga en cada programa a través de /etc/ld.so.preload. Ese archivo normalmente no existe. Si existe y nombra una biblioteca que no conoces, ps y top te están mintiendo.

Cualquier distribución
ls -l /etc/ld.so.preload 2>/dev/null && cat /etc/ld.so.preload
sudo grep -l LD_PRELOAD /proc/[0-9]*/environ 2>/dev/null

Conexiones a un pool de minería

Los mineros hablan con un pool mediante el protocolo stratum. Puertos como 3333, 4444, 5555, 7777 y 14444 son típicos, pero los pools también escuchan en el 443 y el 80, así que revisa también las conexiones del propio proceso:

Cualquier distribución
sudo ss -tnp state established '( dport = :3333 or dport = :4444 or dport = :5555 or dport = :7777 or dport = :14444 )'
sudo ss -tnp state established | grep PID

Los archivos de configuración de los mineros suelen contener la URL de un pool. Esto los busca en los sitios habituales:

Cualquier distribución
sudo grep -rIl -E 'stratum\+(tcp|ssl)://|"pools"|donate-level' /tmp /var/tmp /dev/shm /root /home /var/www /etc 2>/dev/null

Lo que lo hace volver

Busca la persistencia antes de matar nada, para saber qué tienes que eliminar. Primero cron: líneas que descargan con curl o wget, decodifican base64 o ejecutan algo desde /tmp.

Cualquier distribución
sudo cat /etc/crontab
sudo ls -la /etc/cron.d /etc/cron.hourly /etc/cron.daily /var/spool/cron 2>/dev/null
for u in $(cut -d: -f1 /etc/passwd); do sudo crontab -l -u "$u" 2>/dev/null | sed "s/^/$u: /"; done
sudo grep -rE 'curl|wget|base64|/tmp/|/dev/shm' /etc/crontab /etc/cron.* /var/spool/cron 2>/dev/null

Después los timers de systemd y los archivos de unidad modificados en los últimos 30 días:

Cualquier distribución
systemctl list-timers --all
sudo sh -c "find /etc/systemd/system /usr/lib/systemd/system /lib/systemd/system /root/.config/systemd /home/*/.config/systemd \
  -type f \( -name '*.service' -o -name '*.timer' \) -mtime -30 2>/dev/null"

Después las claves SSH que no añadiste tú, rc.local, los archivos de arranque de la shell y las cuentas que no creaste:

Cualquier distribución
sudo sh -c 'cat /root/.ssh/authorized_keys /home/*/.ssh/authorized_keys 2>/dev/null'
ls -l /etc/rc.local 2>/dev/null
sudo sh -c "grep -lE 'curl|wget|/tmp/|/dev/shm' /etc/profile.d/* /etc/bash.bashrc /etc/bashrc /root/.bashrc /root/.profile /home/*/.bashrc 2>/dev/null"
awk -F: '$3 == 0 || $3 >= 1000 {print $1, $3, $7}' /etc/passwd

Por último, comprueba que los binarios del propio sistema no se han sustituido. La salida lista los archivos de los paquetes cuyo contenido ha cambiado; los archivos de configuración quedan fuera.

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 /'

Contenerlo

Si tu proveedor puede hacer una instantánea del disco, hazla ahora: conserva las pruebas y una vía de vuelta atrás. Después corta la conexión del minero con su pool. Sustituye 198.51.100.23 por la dirección del pool del paso 1. Esta tabla de nftables funciona en Debian, Ubuntu y la familia RHEL junto a ufw o firewalld, y desaparece al reiniciar.

Cualquier distribución con nftables
sudo nft add table inet quarantine
sudo nft 'add chain inet quarantine out { type filter hook output priority 0; policy accept; }'
sudo nft add rule inet quarantine out ip daddr 198.51.100.23 drop

Guarda una copia del binario y de su línea de comandos antes de que se borre. /proc/PID/exe funciona aunque el archivo ya se haya eliminado del disco. El SHA-256 se puede buscar en bases de datos públicas de malware.

Cualquier distribución
sudo mkdir -p /root/evidence
sudo cp /proc/PID/exe /root/evidence/miner.bin
sudo tr '\0' ' ' < /proc/PID/cmdline | sudo tee /root/evidence/cmdline.txt
sudo sha256sum /root/evidence/miner.bin

Congela primero el proceso, para que un watchdog no lo vea morir y lo vuelva a arrancar al instante, mira su proceso padre y después mátalo. Si el padre es un script o un segundo proceso del minero, ocúpate también de él.

Cualquier distribución
sudo kill -STOP PID
ps -o pid,ppid,user,args -p PID
sudo kill -9 PID

Atención: Da por hecho que todos los secretos del servidor son conocidos: claves SSH, contraseñas, las contraseñas de las bases de datos y las claves de API de .env y de los archivos de configuración. Cámbialos desde una máquina limpia, empezando por las cuentas que dan acceso a otros servidores.

Eliminarlo junto con todo lo que lo hace volver

Elimina cada elemento de persistencia que encontraste en el paso 1 y después los binarios. Para una unidad de systemd (sustituye NAME):

Cualquier distribución
sudo systemctl disable --now NAME.service
sudo rm /etc/systemd/system/NAME.service
sudo systemctl daemon-reload
  • Cron: borra las líneas con sudo crontab -e -u USER, y los archivos de /etc/cron.d que no hayas creado tú.
  • SSH: borra de cada authorized_keys las claves que no reconozcas.
  • Cuentas: bloquea o borra los usuarios que no creaste (sudo usermod -L NAME), y revisa /etc/sudoers y /etc/sudoers.d/.
  • Los binarios y archivos de configuración del minero, allí donde los encontró el paso 1.

Los mineros suelen hacer inmutables sus archivos para que rm falle con Operation not permitted incluso como root. Comprueba y quita primero los atributos:

Cualquier distribución
sudo lsattr /path/to/file
sudo chattr -i -a /path/to/file
sudo rm /path/to/file

Si /etc/ld.so.preload nombra una biblioteca que no conoces, apártalo (es raro que el software legítimo lo use) y borra la biblioteca que nombraba:

Cualquier distribución
sudo mv /etc/ld.so.preload /root/evidence/ld.so.preload
sudo ldconfig

Reinicia y vuelve a comprobar la CPU al cabo de una hora y al día siguiente: si el minero vuelve, todavía queda algún elemento de persistencia o el punto de entrada sigue abierto.

Atención: Si el minero se ejecutaba como root, si cambiaron binarios del sistema o si se usó ld.so.preload, no puedes estar seguro de que el servidor esté limpio. Reconstrúyelo a partir de una imagen nueva y restaura los datos desde una copia de seguridad anterior a la infección, después de revisarla. Limpiar sobre el propio servidor solo es razonable cuando el minero se ejecutaba como un usuario sin privilegios y no cambió nada fuera de los archivos de ese usuario.

Averiguar cómo entró

Si no cierras la vía de entrada, el minero vuelve en pocos días. El usuario con el que se ejecutaba el minero y la hora en que se crearon sus archivos apuntan hacia ella:

Cualquier distribución
ps -o user,pid,lstart,args -p PID
sudo stat /path/to/miner
  • Se ejecuta como el usuario del servidor web: un plugin, un tema o una aplicación vulnerables, o un formulario de subida. Mira los logs web alrededor de la hora en que apareció el archivo.
  • Se ejecuta como redis, o los archivos los creó ese usuario: Redis abierto a internet sin contraseña.
  • Lo arrancó un contenedor o dockerd: la API de Docker expuesta en el 2375 o el 2376.
  • Se ejecuta como root o como un usuario normal con un inicio de sesión justo antes: una contraseña débil o una clave SSH robada.
Inicios de sesión SSH
last -i -n 50
sudo journalctl --since "14 days ago" | grep -E "Accepted (password|publickey)"
Logs del servidor web
sudo grep -hE 'wget|curl|base64|%2Fbin%2Fsh|/bin/sh' \
  /var/log/nginx/access.log* /var/log/apache2/access.log* /var/log/httpd/access_log* 2>/dev/null | tail -n 50

Y los servicios que suelen ser una vía de entrada cuando escuchan en todas las interfaces: la API de Docker, Redis, consolas web en el 8080, Elasticsearch, MongoDB, Memcached.

Cualquier distribución
sudo ss -tlnp | grep -E ':(2375|2376|6379|8080|9200|27017|11211)\b'

Reforzar el servidor después

  • Cierra el punto de entrada que encontraste: actualiza o elimina la aplicación, haz que Redis y las bases de datos escuchen solo en localhost y con contraseña, y no expongas nunca la API de Docker.
  • SSH solo con claves y sin acceso de root: consulta Cómo frenar los ataques de fuerza bruta SSH.
  • Instala las actualizaciones y activa las actualizaciones de seguridad automáticas y el firewall: consulta Proteger un VPS nuevo: la checklist.
  • Limita el tráfico saliente donde puedas: un servidor web rara vez necesita abrir conexiones a puertos arbitrarios.
  • A partir de ahora, vigila el uso de CPU, las conexiones salientes y los cambios en cron, systemd y las claves SSH, para que el próximo se detecte en minutos y no en semanas.

Cómo detecta InfraFence un minero de criptomonedas

Varios detectores de InfraFence cubren los pasos anteriores, cada uno desde un ángulo distinto:

  • Detección de procesos: un proceso en ejecución cuyo nombre o línea de comandos coincide con un minero conocido (xmrig, minerd, cpuminer y otros), con una URL stratum o con un pool conocido se notifica como crítico, con su PID y su línea de comandos. También se notifican las reverse shells y los scripts que se ejecutan desde /tmp.
  • Escaneo de malware: firmas para mineros de criptomonedas, web shells y puertas traseras en tus sitios, reglas YARA actualizadas a diario, y los binarios del sistema comprobados contra la base de datos de paquetes (dpkg -V / rpm -Va).
  • Tráfico saliente y DNS: conexiones a direcciones que figuran en listas públicas de inteligencia de amenazas, y cada consulta DNS asociada al programa que la hizo.
  • Integridad de archivos: /etc/ld.so.preload, los crontabs, las unidades de systemd y cada authorized_keys se registran con su hash y se vigilan, y cualquier cambio genera una alerta al instante.
  • Comprobaciones de hardening que señalan las vías de entrada habituales: bases de datos abiertas a internet, software desactualizado, SSH con contraseñas.

La comprobación de procesos se basa en nombres y líneas de comandos: un minero renombrado que lee su pool de un archivo de configuración no coincide, y queda en manos de los demás detectores. La limpieza que describe esta guía sigue siendo cosa tuya.

Preguntas

¿Basta con matar el proceso?
Volverá. Los mineros instalan una tarea de cron, una unidad de systemd o una clave SSH para arrancar de nuevo, y el agujero por el que entraron sigue abierto. Elimina la persistencia y cierra el punto de entrada.
¿Tengo que reinstalar el servidor?
Si el minero se ejecutaba como root, cambiaron binarios del sistema o se usó /etc/ld.so.preload, sí: no puedes demostrar que el servidor esté limpio. Si se ejecutaba como un usuario sin privilegios y no cambió nada más, una limpieza cuidadosa puede ser suficiente.
Mi proveedor dice que el servidor está minando, pero no veo nada. ¿Por qué?
Puede que el minero esté oculto con /etc/ld.so.preload, que se ejecute en un contenedor o que solo arranque a ciertas horas desde cron. Revisa el archivo de preload, docker ps y las conexiones que abre el servidor a lo largo del tiempo.

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.