Obtener el acceso es la mitad del trabajo; la otra mitad consiste en no perderlo. Por eso casi todo el software malicioso automatizado se asegura antes que nada de volver a lanzarse: tras un reinicio, tras el borrado del archivo, tras un cambio de contraseña. De ahí la historia conocida: «limpiamos y dos días después volvió».

Los lugares donde eso se organiza no son tantos, y todos se revisan en unos minutos. A continuación, el recorrido completo por orden.

1. Las claves SSH

La vuelta más sencilla: una línea en authorized_keys sobrevive a un cambio de contraseña, a una actualización del sistema y a un reinicio.

sudo find /home /root -name authorized_keys -exec ls -l {} \; -exec cat {} \;

Cada línea es el acceso permanente de alguien. Si no puede decir de quién, considérelo ajeno. Fíjese también en el comentario del final de la línea: es texto libre, y que coincida con su propio nombre no demuestra nada.

2. Las tareas de cron de todos los usuarios

No hay que revisar solo su propia crontab:

for u in $(cut -f1 -d: /etc/passwd); do echo "== $u"; sudo crontab -u "$u" -l 2>/dev/null; done
sudo ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/
sudo cat /etc/crontab

Qué hay que buscar: líneas con @reboot, comandos largos codificados, llamadas a curl o wget redirigidas a un intérprete, todo lo que se lance desde /tmp, /dev/shm o /var/tmp. De esos directorios no se ejecuta nada regular.

3. Temporizadores y servicios de systemd

El equivalente moderno de cron, y se revisa bastante menos:

systemctl list-timers --all
systemctl list-units --type=service --state=running
sudo ls -la /etc/systemd/system/ /run/systemd/system/

Aparte, los servicios de usuario, que funcionan sin privilegios de root y no aparecen en la lista general:

systemctl --user list-units --type=service
sudo ls -la /home/*/.config/systemd/user/

Un detalle más: si para un usuario está activada la persistencia (loginctl enable-linger), sus servicios funcionan sin sesión activa. Se comprueba con loginctl list-users.

4. Los archivos de arranque del intérprete

El código añadido al final de un archivo de arranque del intérprete se ejecuta en cada acceso:

sudo tail -5 /root/.bashrc /root/.profile /home/*/.bashrc /home/*/.profile
sudo ls -la /etc/profile.d/

Mire precisamente el final del archivo: ahí se añade para que no llame la atención en una ojeada rápida.

5. ld.so.preload

Un archivo que obliga al sistema a cargar una biblioteca dada en cada proceso que se lance. En condiciones normales no se crea nunca:

ls -l /etc/ld.so.preload

Su presencia es prácticamente una señal inequívoca de compromiso grave, y una biblioteca así suele ocultar tanto archivos como procesos y conexiones de red. Nada de lo que vea después en esa máquina merece confianza.

6. Los ganchos del gestor de paquetes

Un método que rara vez se contempla: apt puede ejecutar comandos antes y después de cada operación con paquetes.

sudo ls -la /etc/apt/apt.conf.d/
sudo grep -r 'DPkg::Pre-Invoke\|DPkg::Post-Invoke\|APT::Update' /etc/apt/apt.conf.d/

Un gancho así se dispara en cada instalación de actualizaciones, es decir, con regularidad y como root.

7. El mensaje del día en Ubuntu

El directorio /etc/update-motd.d/ contiene scripts ejecutables que se lanzan en cada acceso por SSH y componen el texto de bienvenida. El lugar es cómodo precisamente porque parece parte del sistema:

sudo ls -la /etc/update-motd.d/

8. Las tareas diferidas de at

sudo atq
sudo ls -la /var/spool/cron/atjobs/ 2>/dev/null

Un mecanismo antiguo y poco usado, y por eso el menos revisado de todos.

Qué hacer si aparece algo

El primer impulso es borrar el hallazgo de inmediato. Es un error: con él desaparece la información sobre cómo llegó ahí, y sin respuesta a esa pregunta todo se repetirá.

  1. Guardar una copia del archivo o de la tarea y su hora de modificación.
  2. Con esa hora, mirar en los registros del servidor web y en auth.log qué pasaba en ese mismo minuto. Ahí suele estar el punto de entrada.
  3. Revisar los ocho lugares de la lista, y no solo aquel donde apareció algo. Una puerta trasera casi nunca se deja en un único ejemplar.
  4. Solo después limpiar y cerrar la vulnerabilidad en sí.

Saber cómo es la normalidad

La principal dificultad de esta revisión no son los comandos, sino que una línea desconocida en una lista de tareas no parece sospechosa si no recuerda cómo era la lista antes. En un servidor configurado por otra persona, o configurado hace un año, distinguir lo suyo de lo ajeno resulta casi imposible.

De ahí la conclusión práctica: tomar hoy una instantánea del estado actual tiene sentido, mientras el servidor está en orden. La lista de tareas de cron, temporizadores, claves y servicios de una máquina sana es la referencia con la que se comparará después. Recogida y conservada con histórico, convierte la búsqueda de una puerta trasera de un ejercicio de varias horas en una comparación de dos listas. Cómo se ve eso lo muestran las páginas de demostración de abajo.