Ruben GroenewoudRemco Sprooten

Viciado em Linux: Engenharia de Detecção de Rootkits

Nesta segunda parte de uma série de dois artigos, exploramos a engenharia de detecção de rootkits no Linux, com foco nas limitações da dependência de detecção estática e na importância da detecção comportamental de rootkits.

Viciado em Linux: Engenharia de Detecção de Rootkits

Introdução

Na primeira parte, examinamos como funcionam os rootkits do Linux: sua evolução, taxonomia e técnicas para manipular o espaço do usuário e o espaço do kernel. Nesta segunda parte, abordaremos a engenharia de detecção. Começamos por mostrar por que a detecção estática costuma ser pouco confiável contra rootkits do Linux, mesmo quando os binários são modificados apenas de forma trivial, e depois passamos para os sinais comportamentais e de tempo de execução que os defensores podem usar em vez disso. Desde o abuso de objetos compartilhados e carregamento da LKM até eBPF, io_uring, persistência e evasão de defesas, este artigo se concentra em maneiras práticas de detectar e investigar atividades de rootkits em ambientes reais.

Detecção estática via VirusTotal

Antes de nos concentrarmos nas técnicas de detecção comportamental, é útil examinar a eficácia dos mecanismos tradicionais de detecção estática na identificação de rootkits do Linux. Para isso, realizamos um pequeno experimento usando o VirusTotal como um substituto para a detecção antivírus tradicional baseada em assinaturas. Um conjunto de dados com dez rootkits para Linux foi compilado a partir de artigos de pesquisa disponíveis publicamente e repositórios de código aberto. Cada amostra foi enviada para o VirusTotal ou recuperada de submissões existentes.

Para cada rootkit, registramos o número de mecanismos antivírus que sinalizaram o binário original. Em seguida, realizamos dois testes adicionais:

  1. Binários despojados, criados usando strip --strip-all, removendo tabelas de símbolos e outros metadados não essenciais.
  2. Binários trivialmente modificados, criados adicionando um único byte nulo ao arquivo original: uma alteração intencionalmente pouco sofisticada.

O objetivo não era evitar a detecção por meio de ofuscação avançada, mas avaliar a fragilidade das assinaturas estáticas diante das modificações binárias mais simples.

Tabela 1: Visão geral técnica do conjunto de dados de rootkits analisado

RootkitDetecções básicasDespidoByte nulo adicionado
Azazel36/6619/6621/66
Infernal*32/6632/6621/66
Pacote quebrado7/663/663/66
Diamorfina33/668/6422/66
Covid27/661/6615/66
Mobkit29/666/6617/66
Réptil32/663/6620/66
Snapekit30/663/6619/66
Simbionte42/668/6622/66
TripleCross31/6617/6619/66

* O Bedevil é despojado de recursos por padrão e, portanto, as detecções básicas e despojadas são as mesmas.

Observações

Como esperado, a remoção de elementos binários geralmente resultou em uma queda acentuada nas taxas de detecção. Em vários casos, as detecções caíram para perto de zero, sugerindo que alguns mecanismos antivírus dependem muito de informações de símbolos ou outros metadados facilmente removíveis. Ainda mais revelador é o impacto da adição de um único byte nulo: uma modificação que não altera a lógica do programa, o fluxo de execução ou o comportamento, mas que, mesmo assim, degrada significativamente a detecção em muitas amostras.

Isso evidencia uma fragilidade fundamental da detecção estática baseada em assinaturas. Se uma alteração de um único byte puder afetar significativamente os resultados da detecção, os atacantes não precisam de ofuscação sofisticada para burlar os scanners estáticos.

Técnicas de ofuscação em rootkits

Curiosamente, a maioria dos rootkits neste conjunto de dados utiliza pouca ou nenhuma ofuscação estática avançada. Quando há ofuscação, ela geralmente se limita à codificação XOR simples de strings ou dados de configuração, ou a técnicas de compactação leves que alteram ligeiramente o layout binário. Esses métodos são baratos de implementar e suficientes para derrotar muitas assinaturas estáticas.

É notável a ausência de técnicas de ofuscação mais avançadas nessas amostras. Muitos são rootkits de prova de conceito de código aberto, projetados para demonstrar técnicas em vez de tentar evitar a detecção de forma agressiva. Mesmo com ofuscação mínima ou nenhuma, a detecção estática se mostra pouco confiável.

Por que a detecção estática não é suficiente

Este experimento reforça um ponto fundamental: a detecção estática por si só é insuficiente para uma detecção confiável de rootkits. A fragilidade das assinaturas estáticas (especialmente diante de modificações triviais) significa que os defensores não podem confiar em indicadores baseados em arquivos ou detecção baseada em hash para descobrir ameaças furtivas.

Quando os binários podem ser alterados sem afetar o comportamento, o único sinal consistente restante é o comportamento do rootkit em tempo de execução. Por essa razão, o restante deste blog muda seu foco de artefatos estáticos para análise dinâmica e detecção comportamental, examinando como os rootkits interagem com o sistema operacional, manipulam o fluxo de execução e deixam rastros observáveis durante a execução.

É aí que a engenharia de detecção se torna mais desafiadora e muito mais eficaz.

Engenharia de detecção dinâmica

técnicas de detecção de carregamento de rootkits no espaço do usuário

Os rootkits de espaço do usuário frequentemente sequestram o processo de vinculação dinâmica, injetando objetos compartilhados maliciosos em processos-alvo sem a necessidade de acesso ao nível do kernel. Uma infecção começa com a criação de um arquivo de objeto compartilhado. A detecção de arquivos de objetos compartilhados recém-criados pode ser feita por meio de uma regra de detecção semelhante à exibida abaixo:

file where event.action == "creation" and
(file.extension like~ "so" or file.name like~ "*.so.*")

Esses arquivos são frequentemente gravados em caminhos graváveis ou efêmeros, como /tmp/, /dev/shm/ ou subdiretórios ocultos em diretórios home do usuário. Os atacantes podem baixá-los, compilá-los ou instalá-los diretamente a partir de um carregador. Esse conhecimento pode ser aplicado à regra de detecção acima para reduzir o ruído.

Como exemplo, na telemetria mostrada acima, podemos ver o agente de ameaça usando scp para baixar um arquivo de objeto compartilhado em um subdiretório oculto dentro de /tmp, depois movê-lo para um diretório de biblioteca, tentando se misturar. Detectamos esta e outras ameaças semelhantes através de:

Uma vez que o arquivo de objeto compartilhado esteja presente no sistema, o atacante tem diversas opções para ativá-lo. Os mecanismos mais comumente abusados são a variável de ambiente LD_PRELOAD , o arquivo /etc/ld.so.preload e caminhos de configuração do vinculador dinâmico, como /etc/ld.so.conf.

A variável de ambiente LD_PRELOAD permite que um atacante especifique um objeto compartilhado que será carregado antes de quaisquer outras bibliotecas durante a execução de um binário vinculado dinamicamente. Isso permite uma substituição completa das funções libc , como execve(), open() ou readdir(). Este método funciona por processo e não requer acesso root.

Para detectar essa técnica, é necessário obter telemetria da variável de ambiente LD_PRELOAD . Uma vez que isso esteja disponível, qualquer lógica de detecção para detectar valores LD_PRELOAD incomuns pode ser escrita. Por exemplo:

process where event.type == "start" and event.action == "exec" and
process.env_vars != null

Conforme ilustrado na Figura 1, este foi também o próximo passo dos atacantes. Os atacantes moveram libz.so.1 de /tmp/.X12-unix/libz.so.1 para /usr/local/lib/libz.so.1.

Para maior fidelidade, implementamos essa lógica usando o tipo de regra new_terms, sinalizando apenas entradas de objetos compartilhados não vistas anteriormente dentro da variável LD_PRELOAD por meio de:

É claro que, se mais do que apenas as variáveis de ambiente LD_PRELOAD e LD_LIBRARY_PATH forem coletadas, a regra acima deverá ser alterada para incluir especificamente esses dois itens. Para reduzir o ruído, devem ser realizadas análises estatísticas e/ou definição de linhas de base.

Outro método de ativação é utilizar o arquivo /etc/ld.so.preload . Se presente, este arquivo força o vinculador dinâmico a injetar o objeto compartilhado listado em todos os binários vinculados dinamicamente no sistema, resultando em injeção global.

Um método semelhante envolve alterar a configuração do vinculador dinâmico para priorizar caminhos de biblioteca maliciosos. Isso pode ser conseguido modificando /etc/ld.so.conf ou adicionando entradas a /etc/ld.so.conf.d/, seguido da execução de ldconfig para atualizar o cache. Isso altera o caminho de resolução de bibliotecas críticas, como libc.so.6.

Esses cenários podem ser detectados monitorando os arquivos /etc/ld.so.preload e /etc/ld.so.conf , bem como o diretório /etc/ld.so.conf.d/ para eventos de criação/modificação. Utilizando esses dados de telemetria brutos, é possível implementar uma regra de detecção para sinalizar esses eventos:

file where event.action in ("creation", "rename") and
file.path like ("/etc/ld.so.preload", "/etc/ld.so.conf", "/etc/ld.so.conf.d/*")

Vemos frequentemente essa cadeia, onde um objeto compartilhado é criado e, em seguida, o vinculador dinâmico é modificado.

Que detectamos através das seguintes regras de detecção:

O encadeamento desses dois alertas em um único host justifica uma investigação.

Técnicas de detecção de carregamento de rootkits no espaço do kernel

Carregar um LKM manualmente normalmente requer o uso de utilitários de linha de comando integrados, como modprobe, insmod e kmod. A detecção da execução desses utilitários permitirá identificar a fase de carregamento (quando realizada manualmente).

process where event.type == "start" and event.action == "exec" and (
  (process.name == "kmod" and process.args == "insmod" and
   process.args like~ "*.ko*") or
  (process.name == "kmod" and process.args == "modprobe" and
   not process.args in ("-r", "--remove")) or
  (process.name == "insmod" and process.args like~ "*.ko*") or
  (process.name == "modprobe" and not process.args in ("-r", "--remove"))
)

Muitos rootkits de código aberto são publicados sem um carregador e dependem de utilitários de carregamento de LKM pré-instalados. Um exemplo é o Singularity, que fornece um script load_and_persistence.sh , que executa várias ações, após as quais ele eventualmente chama insmod "$MODULE_DIR/$MODULE_NAME.ko". Embora insmod seja chamado no comando, insmod é na verdade kmod internamente, com insmod como argumento do processo. Um exemplo de carga de singularidade:

O que pode ser facilmente detectado através das seguintes regras de detecção:

Essa abordagem de detecção, no entanto, está longe de ser infalível, já que muitos rootkits dependem de um carregador para carregar o LKM, evitando assim a execução desses utilitários do espaço do usuário.

Por exemplo, o carregador do Reptile invoca diretamente a chamada de sistema init_module com um blob do kernel descriptografado na memória:

#define init_module(module_image, len, param_values) syscall(__NR_init_module, module_image, len, param_values)

int main(void) {
    [...]
    do_decrypt(reptile_blob, len, DECRYPT_KEY);
    module_image = malloc(len);
    memcpy(module_image, reptile_blob, len);
    init_module(module_image, len, "");
    [...]
}

Além disso, o módulo kmatryoshka do Reptile atua como um carregador de cadeia no kernel que descriptografa e carrega outro LKM oculto usando um ponteiro de função direto para sys_init_module, localizado via kallsyms_on_each_symbol(). Isso obscurece ainda mais o mecanismo de carregamento da visibilidade do usuário.

Por isso, é essencial entender o que esses utilitários fazem internamente; eles são meramente wrappers em torno das chamadas de sistema init_module() e finit_module() . Uma detecção eficaz deve, portanto, concentrar-se no rastreamento direto dessas chamadas de sistema, em vez das ferramentas que as invocam.

Para garantir a disponibilidade das fontes de dados necessárias para carregar os LKMs, podem ser utilizadas diversas ferramentas de segurança. Auditd ou Auditd Manager são opções adequadas. Para facilitar a coleta de chamadas de sistema init_module() e finit_module , a seguinte configuração pode ser implementada.

-a always,exit -F arch=b64 -S finit_module -S init_module
-a always,exit -F arch=b32 -S finit_module -S init_module

A combinação desses dados de telemetria brutos com uma regra de detecção que emite alertas quando esse evento ocorre permite uma defesa robusta.

driver where event.action == "loaded-kernel-module" and
auditd.data.syscall in ("init_module", "finit_module")

Essa estratégia permitirá a detecção do carregamento do módulo do kernel, independentemente do utilitário utilizado para o evento de carregamento. No exemplo abaixo, vemos uma detecção verdadeiramente positiva do rootkit Diamorphine .

Esta regra pré-configurada está disponível aqui:

Orientações adicionais sobre engenharia de detecção no Linux por meio do Auditd são apresentadas na pesquisa "Engenharia de detecção no Linux com Auditd".

Módulos fora da árvore e não assinados

Outro sinal de um LKM malicioso é a presença do sinalizador de "contaminação" do kernel. Quando o kernel detecta que um módulo carregado não faz parte da árvore oficial do kernel, não possui uma assinatura válida ou usa uma licença não permissiva, ele marca o kernel como "contaminado". Este é um mecanismo de integridade integrado que indica que o kernel está em um estado potencialmente não confiável. Um exemplo disso é mostrado abaixo, onde o módulo reveng_rtkit é carregado:

[ 2853.023215] reveng_rtkit: loading out-of-tree module taints kernel.
[ 2853.023219] reveng_rtkit: module license 'unspecified' taints kernel.
[ 2853.023220] Disabling lock debugging due to kernel taint
[ 2853.023297] reveng_rtkit: module verification failed: signature and/or required key missing - tainting kernel

O kernel identifica o módulo como externo à árvore de código, com uma licença não especificada e sem verificação criptográfica. Isso resulta na marcação do kernel como contaminado.

Para detectar esse comportamento, os registros do sistema e do kernel devem ser analisados e utilizados. Assim que a telemetria do log do kernel estiver disponível, uma simples correspondência de padrões ou detecção baseada em regras pode sinalizar esses eventos. O carregamento de módulos fora da árvore pode ser detectado através de:

event.dataset:"system.syslog" and process.name:"kernel" and
message:"loading out-of-tree module taints kernel."

Uma lógica de detecção semelhante pode ser implementada para detectar o carregamento de módulos não assinados:

event.dataset:"system.syslog" and process.name:"kernel" and
message:"module verification failed: signature and/or required key missing - tainting kernel"

Utilizando a lógica de detecção acima, observamos verdadeiros positivos na telemetria, ao tentar carregar o Singularity:

Essas regras estão disponíveis por padrão em:

O registro sempre mostrará o nome do módulo que desencadeou o evento, facilitando a triagem. Quando o LKM não está presente no sistema durante uma verificação manual acionada por este alerta, isso pode indicar que o LKM está se ocultando.

sinais de morte

Muitos rootkits (de código aberto) exploram sinais kill , especificamente aqueles nos intervalos mais altos e não atribuídos (32+), como canais de comunicação secretos ou gatilhos para ações maliciosas. Por exemplo, um rootkit pode interceptar um sinal kill específico de número alto (por exemplo, kill -64 <pid>). Ao receber esse sinal, o payload do rootkit poderia ser configurado para elevar privilégios, executar comandos, ativar/desativar recursos de ocultação ou estabelecer uma porta dos fundos.

Para detectar isso, podemos usar o Auditd e criar uma regra que colete todos os sinais de encerramento:

-a exit,always -F arch=b64 -S kill -k kill_rule

Os argumentos passados para kill() são kill(pid, sig). Podemos consultar a1 (o sinal) para sinalizar qualquer sinal de morte acima de 32.

process where event.action == "killed-pid" and
auditd.data.syscall == "kill" and auditd.data.a1 in (
"21", "22", "23", "24", "25", "26", "27", "28", "29", "2a",
"2b", "2c", "2d", "2e", "2f", "30", "31", "32", "33", "34",
"35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e",
"3f", "40", "41", "42", "43", "44", "45", "46", "47"
)

A análise da chamada de sistema kill() em busca de valores de sinal incomuns por meio do Auditd apresenta uma forte oportunidade de detecção contra rootkits que utilizam esses sinais, como visto em técnicas como as empregadas pelo Diamorphine. As regras pré-definidas relacionadas a eliminações estão disponíveis em:

Falhas de segmentação

Por fim, é essencial reconhecer que os rootkits de espaço do kernel são inerentemente frágeis. Os LKMs são normalmente compilados para uma versão e configuração específicas do kernel. Um símbolo mal resolvido ou uma escrita de memória desalinhada pode desencadear uma falha de segmentação. Embora essas falhas possam não expor imediatamente a funcionalidade do rootkit, elas fornecem fortes indícios forenses.

Para detectar isso, a coleta de logs brutos do sistema (syslog) deve estar habilitada. A partir daí, escrever uma regra de detecção para sinalizar mensagens de falha de segmentação pode ajudar a identificar comportamentos maliciosos ou instabilidade do kernel, ambos merecedores de investigação:

event.dataset:"system.syslog" and process.name:"kernel" and message:"segfault"

Essa regra de detecção está disponível pronta para uso como um bloco de construção:

A combinação da visibilidade do carregamento de módulos em nível de chamada de sistema com a detecção de contaminação do kernel, mensagens fora da árvore, detecção de sinais de interrupção e alertas de falha de segmentação estabelece a base para uma estratégia em camadas para detectar rootkits baseados em LKM.

Rootkits eBPF

Os rootkits eBPF exploram a funcionalidade legítima do subsistema BPF do kernel Linux. Os programas podem ser carregados e anexados dinamicamente usando utilitários como bpftool ou por meio de carregadores personalizados que abusam das chamadas de sistema bpf() .

A detecção de rootkits baseados em eBPF requer visibilidade tanto das chamadas de sistema bpf() quanto do uso de auxiliares eBPF sensíveis. Os principais indicadores envolvidos incluem:

  • bpf(BPF_MAP_CREATE, ...)
  • bpf(BPF_MAP_LOOKUP_ELEM, ...)
  • bpf(BPF_MAP_UPDATE_ELEM, ...)
  • bpf(BPF_PROG_LOAD, ...)
  • bpf(BPF_PROG_ATTACH, ...)

Utilizando o Auditd, é possível criar uma regra de auditoria onde a0 é usado para especificar as chamadas de sistema BPF de interesse:

-a always,exit -F arch=b64 -S bpf -F a0=0 -k bpf_map_create
-a always,exit -F arch=b64 -S bpf -F a0=1 -k bpf_map_lookup_elem
-a always,exit -F arch=b64 -S bpf -F a0=2 -k bpf_map_update_elem
-a always,exit -F arch=b64 -S bpf -F a0=5 -k bpf_prog_load
-a always,exit -F arch=b64 -S bpf -F a0=8 -k bpf_prog_attach

Esses parâmetros devem ser ajustados para cada ambiente específico, a fim de garantir que programas benignos (como EDRs ou outras ferramentas de observabilidade) que utilizam eBPF não gerem ruído. Outro sinal importante é o uso de funções auxiliares eBPF.

A função auxiliar bpf_probe_write_user

O auxiliar bpf_probe_write_user permite que programas eBPF do espaço do kernel escrevam diretamente na memória do espaço do usuário. Embora destinada à depuração, essa função pode ser explorada indevidamente por rootkits.

A detecção continua sendo um desafio, mas os kernels do Linux geralmente registram o uso de auxiliares sensíveis, como bpf_probe_write_user. O monitoramento dessas entradas oferece uma oportunidade de detecção, exigindo a coleta de syslog bruto e regras de detecção específicas, como as seguintes:

event.dataset:"system.syslog" and process.name:"kernel" and
message:"bpf_probe_write_user"

Esta regra irá alertar sobre qualquer entrada de log do kernel que indique o uso de bpf_probe_write_user. Embora ferramentas legítimas possam ocasionalmente invocá-lo, o uso inesperado ou frequente, especialmente em conjunto com comportamento suspeito do processo, justifica uma investigação. O contexto, como o ponto de integração do programa eBPF e o processo envolvido no espaço do usuário, auxilia na triagem. Essa regra de detecção está disponível aqui:

Abaixo estão alguns exemplos óbvios de verdadeiros positivos detectados por essa lógica:

A regra é acionada pelo nysm (um contêiner furtivo de pós-exploração) e pelo boopkit (um backdoor eBPF para Linux).

io_uring rootkits

A pesquisa ARMO (2025) introduziu uma nova técnica de evasão de defesa que aproveita io_uring, um projeto para E/S assíncrona, para reduzir a atividade de chamada de sistema observável e contornar a telemetria padrão. Essa técnica é limitada às versões do kernel 5.1 e superiores e evita o uso de hooks. Embora o método tenha sido descoberto recentemente por pesquisadores de rootkits, ele ainda está em desenvolvimento ativo e permanece relativamente imaturo em seu conjunto de recursos. Um exemplo de ferramenta que utiliza essa técnica é o RingReaper. Os rootkits podem processar em lote arquivos, redes e outras operações de E/S por meio de io_uring_enter(). Um exemplo de código é mostrado abaixo.

struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, fd, buf, size, offset);
io_uring_submit(&ring);

Essas chamadas enfileiram e enviam uma solicitação de leitura usando io_uring, ignorando os caminhos típicos de telemetria de chamadas de sistema.

Ao contrário do syscall table hooking ou da injeção baseada em LD_PRELOAD , io_uring não é um mecanismo de entrega de rootkit em si, mas fornece um meio mais furtivo de interagir com o sistema de arquivos e dispositivos após a invasão. Embora io_uring não possa executar binários diretamente (devido à falta de capacidades semelhantes execve ), permite ações maliciosas como criação de arquivos, enumeração e exfiltração de dados, minimizando a observabilidade.

A detecção de rootkits baseados em io_uringrequer visibilidade das chamadas de sistema que sustentam sua operação, como io_uring_setup(), io_uring_enter() e io_uring_register().

Embora as soluções EDR possam ter dificuldades em capturar os efeitos indiretos de io_uring, o Auditd pode rastrear essas chamadas de sistema diretamente. A seguinte regra de auditoria captura eventos relevantes para análise:

-a always,exit -F arch=b64 -k io_uring
-S io_uring_setup -S io_uring_enter -S io_uring_register

No entanto, isso expõe apenas o uso da chamada de sistema em si, não o arquivo ou objeto específico que está sendo acessado. A verdadeira "mágica" de io_uring ocorre dentro das bibliotecas do espaço do usuário (por exemplo, liburing), tornando a análise dos argumentos da chamada de sistema essencial.

Por exemplo, monitorar io_uring_enter() com to_submit > 0 indica que uma operação de E/S está sendo agrupada, enquanto alternar chamadas com min_complete > 0 sinaliza a sondagem de conclusão. A correlação com atributos de processo (por exemplo, UID=0, caminhos incomuns como locais com suporte em /dev/shm, /tmp ou tmpfs ) aumenta a eficácia da detecção.

Um método prático para rastrear a atividade io_uring é através do eBPF com ferramentas como BCC, visando pontos de rastreamento como sys_enter_io_uring_enter. Isso permite que os analistas monitorem o comportamento do processo e os descritores de arquivo ativos durante as operações io_uring :

tracepoint:syscalls:sys_enter_io_uring_enter
{
    printf("\nPID %d (%s) called io_uring_enter with fd=%d, to_submit=%d, min_complete=%d, flags=%d\n",
        pid, comm, args->fd, args->to_submit, args->min_complete, args->flags);

    printf("Manually inspect with: ls -l /proc/%d/fd\n", pid);
}

Para ilustrar isso, diversas técnicas introduzidas pelo RingReaper foram testadas. O rastreamento em tempo real revela os descritores de arquivo em uso, ajudando a identificar atividades suspeitas, como a leitura de /run/utmp para detectar quais usuários estão conectados:

A atividade de escrever em um arquivo, neste exemplo /root/test:

Ou listando informações do processo via ps lendo o conteúdo de comm para cada PID ativo:

Embora o monitoramento de chamadas de sistema exponha o uso de io_uring , ele não revela diretamente a natureza da E/S sem correlação adicional. io_uring é uma técnica relativamente nova e, portanto, ainda furtiva; no entanto, também tem várias limitações. io_uring não pode executar código diretamente; no entanto, os atacantes podem abusar de gravações de arquivos (por exemplo, tarefas cron, regras udev) para obter execução atrasada ou indireta, como demonstrado pelas técnicas de persistência usadas pelas famílias de malware Reptile e Sedexp .

técnicas de persistência de rootkit

Os rootkits, sejam eles executados no espaço do usuário ou no espaço do kernel, exigem alguma forma de persistência para permanecerem funcionais após reinicializações ou sessões de usuário. Os métodos variam dependendo do tipo e dos privilégios do rootkit, mas geralmente envolvem o abuso de arquivos de configuração, gerenciamento de serviços ou scripts de inicialização do sistema.

Rootkits de espaço do usuário – persistência de variáveis de ambiente

Ao usar LD_PRELOAD para ativar um rootkit de espaço do usuário, o comportamento não é persistente por padrão. Para alcançar a persistência, os atacantes podem modificar os arquivos de inicialização do shell (por exemplo, ~/.bashrc, ~/.zshrc ou /etc/profile) para exportar variáveis de ambiente como LD_PRELOAD ou LD_LIBRARY_PATH. Essas modificações garantem que cada nova sessão do shell herde automaticamente o ambiente necessário para ativar o rootkit. É importante destacar que esses arquivos existem tanto para o contexto do usuário quanto para o contexto do usuário root. Portanto, mesmo usuários sem privilégios podem introduzir persistência que sequestra o fluxo de execução em seu nível de privilégio.

Para detectar isso, pode-se usar uma regra semelhante à exibida abaixo:

file where event.action in ("rename", "creation") and file.path like (
  // system-wide configurations
  "/etc/profile", "/etc/profile.d/*", "/etc/bash.bashrc",
  "/etc/bash.bash_logout", "/etc/zsh/*", "/etc/csh.cshrc",
  "/etc/csh.login", "/etc/fish/config.fish", "/etc/ksh.kshrc",

  // root and user configurations
  "/home/*/.profile", "/home/*/.bashrc", "/home/*/.bash_login",
  "/home/*/.bash_logout", "/home/*/.bash_profile", "/root/.profile",
  "/root/.bashrc", "/root/.bash_login", "/root/.bash_logout",
  "/root/.bash_profile", "/root/.bash_aliases", "/home/*/.bash_aliases",
  "/home/*/.zprofile", "/home/*/.zshrc", "/root/.zprofile", "/root/.zshrc",
  "/home/*/.cshrc", "/home/*/.login", "/home/*/.logout", "/root/.cshrc",
  "/root/.login", "/root/.logout", "/home/*/.config/fish/config.fish",
  "/root/.config/fish/config.fish", "/home/*/.kshrc", "/root/.kshrc"
)

Dependendo do ambiente, vários desses shells podem não estar em uso e uma regra de detecção mais personalizada pode ser criada, focando apenas em bash ou zsh, por exemplo. A lógica completa de detecção, utilizando a integração do Elastic Defend e do Monitoramento de Integridade de Arquivos da Elastic, pode ser encontrada aqui:

Para obter mais informações, uma análise completa dessa técnica de persistência, incluindo várias outras maneiras de detectar seu abuso, é apresentada em Linux Detection Engineering - A primer on persistence mechanisms.

Rootkits de espaço do usuário – persistência baseada em configuração

A modificação dos arquivos de configuração /etc/ld.so.preload, /etc/ld.so.conf ou /etc/ld.so.conf.d/ permite que os rootkits persistam globalmente entre usuários e sessões (mais informações sobre esse vetor de persistência estão disponíveis em Linux Detection Engineering - A Continuation on Persistence Mechanisms). Uma vez gravado, o vinculador dinâmico continuará injetando o objeto compartilhado malicioso, a menos que essas configurações sejam revertidas explicitamente. Esses métodos são persistentes por natureza. As estratégias de detecção são semelhantes às descritas na seção anterior e baseiam-se no monitoramento de eventos de criação ou modificação de arquivos nesses caminhos.

Rootkits em espaço de kernel – persistência do LKM

Assim como os rootkits de espaço do usuário, os LKMs não são persistentes por padrão. O atacante precisa configurar explicitamente o sistema para recarregar o módulo malicioso na inicialização. Isso geralmente é conseguido aproveitando mecanismos legítimos de carregamento de módulos do kernel:

Arquivo de módulos: modules

Este arquivo lista os módulos do kernel que devem ser carregados automaticamente durante a inicialização do sistema. Adicionar um nome de arquivo .ko malicioso aqui garante que modprobe o carregará na inicialização. Este arquivo está localizado em /etc/modules.

Diretório de configuração para modprobe

Este diretório contém arquivos de configuração para o utilitário modprobe . Os atacantes podem usar aliases para disfarçar seu rootkit ou carregá-lo automaticamente quando um evento específico do kernel ocorre (por exemplo, quando um dispositivo é sondado). Esses arquivos de configuração do modprobe estão localizados em /etc/modprobe.d/, /run/modprobe.d/, /usr/local/lib/modprobe.d/, /usr/lib/modprobe.d/, e /lib/modprobe.d/.

Configure os módulos do kernel para serem carregados na inicialização: modules-load.d

Esses arquivos de configuração especificam quais módulos carregar no início do processo de inicialização e estão localizados em /etc/modules-load.d/, /run/modules-load.d/, /usr/local/lib/modules-load.d/ e /usr/lib/modules-load.d/.

Para detectar todas as técnicas de persistência listadas acima, pode-se criar uma regra de detecção semelhante à seguinte:

file where event.action in ("rename", "creation") and file.path like (
  "/etc/modules",
  "/etc/modprobe.d/*",
  "/run/modprobe.d/*",
  "/usr/local/lib/modprobe.d/*",
  "/usr/lib/modprobe.d/*",
  "/lib/modprobe.d/*",
  "/etc/modules-load.d/*",
  "/run/modules-load.d/*",
  "/usr/local/lib/modules-load.d/*",
  "/usr/lib/modules-load.d/*"
)

Esta regra pré-configurada, que combina todos os caminhos listados acima em uma única regra de detecção, está disponível aqui:

Um exemplo de rootkit que implanta persistência automaticamente usando esse método é o Singularity. Durante a sua implementação, os seguintes comandos são executados:

read -p "Enter the module name (without .ko): " MODULE_NAME
CONF_DIR="/etc/modules-load.d"
mkdir -p "$CONF_DIR"
echo "[*] Setting up persistence..."
echo "$MODULE_NAME" > "$CONF_DIR/$MODULE_NAME.conf"

Por padrão, isso significa que singularity.conf será criado como uma nova entrada em /etc/modules-load.d/. Ao analisar a telemetria, detectamos essa técnica simplesmente monitorando a criação de novos arquivos:

Esses diretórios também são usados para LKMs benignos e, portanto, estarão sujeitos a falsos positivos. Outro método de persistência envolve o uso de uma técnica baseada em gatilhos ou agendamentos para carregar o módulo do kernel executando o carregador.

Persistência baseada em Udev – Exemplo Reptile

Um método de persistência menos comum, porém poderoso, envolve o uso indevido do udev, o gerenciador de dispositivos do Linux que lida com eventos dinâmicos de dispositivos. O Udev executa scripts baseados em regras quando condições específicas são atendidas. Uma descrição completa dessa técnica é apresentada em Linux Detection Engineering - A Sequel on Persistence Mechanisms. O rootkit Reptile demonstra essa técnica instalando uma regra udev maliciosa em /etc/udev/rules.d/:

ACTION=="add", ENV{MAJOR}=="1", ENV{MINOR}=="8", RUN+="/lib/udev/reptile"

Essa regra provavelmente serviu de inspiração para o malware Sedexp descoberto pela Levelblue. Eis como a regra funciona:

  • ACTION=="add": É acionado quando um novo dispositivo é adicionado ao sistema.
  • ENV{MAJOR}=="1": Corresponde a dispositivos com número principal “1”, normalmente dispositivos relacionados à memória, como /dev/mem, /dev/null, /dev/zero e /dev/random.
  • ENV{MINOR}=="8": Restringe ainda mais a condição a /dev/random.
  • RUN+="/lib/udev/reptile"Executa o binário do carregador Reptile quando o dispositivo acima é detectado.

Esta regra estabelece persistência ao acionar a execução de um binário de carregamento sempre que o dispositivo /dev/random é carregado. Sendo um gerador de números aleatórios amplamente utilizado e essencial para inúmeras aplicações de sistema e para o processo de inicialização, este método é eficaz. A ativação ocorre apenas mediante eventos específicos do dispositivo e a execução acontece com privilégios de root através do udev daemon. Para detectar essa técnica, pode-se criar uma regra de detecção semelhante à seguinte:

file where event.action in ("rename", "creation") and file.extension == "rules" and file.path like (
  "/lib/udev/*",
  "/etc/udev/rules.d/*",
  "/usr/lib/udev/rules.d/*",
  "/run/udev/rules.d/*",
  "/usr/local/lib/udev/rules.d/*"
)

Abordamos a criação e a modificação desses arquivos por meio das seguintes regras predefinidas:

Mecanismos gerais de persistência

Além dos caminhos de carregamento de módulos do kernel, os atacantes podem se valer de métodos de persistência do Linux mais genéricos para recarregar rootkits do espaço do usuário ou do espaço do kernel por meio do carregador:

Systemd: Crie ou adicione a um serviço/temporizador em qualquer diretório (por exemplo, /etc/systemd/system/) que suporte o carregador na inicialização.

file where event.action in ("rename", "creation") and file.path like (
  "/etc/systemd/system/*", "/etc/systemd/user/*",
  "/usr/local/lib/systemd/system/*", "/lib/systemd/system/*",
  "/usr/lib/systemd/system/*", "/usr/lib/systemd/user/*",
  "/home/*.config/systemd/user/*", "/home/*.local/share/systemd/user/*",
  "/root/.config/systemd/user/*", "/root/.local/share/systemd/user/*"
) and file.extension in ("service", "timer")

Scripts de inicialização: Criar ou anexar a um script malicioso de controle de execução (/etc/rc.local), SysVinit (/etc/init.d/) ou Upstart (/etc/init/).

file where event.action in ("creation", "rename") and
file.path like (
  "/etc/init.d/*", "/etc/init/*", "/etc/rc.local", "/etc/rc.common"
)

Tarefas cron: Crie ou adicione itens a uma tarefa cron que permita a execução repetida de um carregador.

file where event.action in ("rename", "creation") and
file.path like (
  "/etc/cron.allow", "/etc/cron.deny", "/etc/cron.d/*",
  "/etc/cron.hourly/*", "/etc/cron.daily/*", "/etc/cron.weekly/*",
  "/etc/cron.monthly/*", "/etc/crontab", "/var/spool/cron/crontabs/*",
  "/var/spool/anacron/*"
)

Sudoers: Crie ou adicione elementos a uma configuração maliciosa do sudoers como uma porta dos fundos.

file where event.type in ("creation", "change") and
file.path like "/etc/sudoers*"

Esses métodos são amplamente utilizados, flexíveis e, muitas vezes, mais fáceis de detectar usando a linhagem de processos ou a telemetria de modificação de arquivos.

A lista de regras de detecção pré-construídas para detectar essas técnicas de persistência está listada abaixo:

técnicas de evasão de defesa contra rootkits

Embora os rootkits sejam, por definição, ferramentas para evasão de defesas, muitos implementam técnicas adicionais para permanecerem indetectáveis durante e após a implantação. Esses métodos são projetados para evitar a visibilidade nos registros, burlar os agentes de detecção de endpoints e interferir nos fluxos de trabalho comuns de investigação. A seção a seguir descreve as principais técnicas de evasão empregadas pelos rootkits modernos do Linux, categorizadas por seus alvos operacionais.

Tentativas de manter o sigilo durante o destacamento

Do ponto de vista forense, os agentes maliciosos geralmente se concentram em táticas de execução furtivas. Por exemplo, um agente de ameaça pode armazenar e executar seus payloads a partir do diretório de memória compartilhada /dev/shm , já que este é um sistema de arquivos totalmente virtual e, portanto, os payloads nunca tocarão o disco. Isso é ótimo do ponto de vista forense, mas, como engenheiros de detecção comportamental, consideramos esse comportamento muito suspeito e incomum.

Como exemplo, embora não seja um agente de ameaça real, o autor do Singularity sugere o seguinte método de implantação:

cd /dev/shm
git clone https://github.com/MatheuZSecurity/Singularity
cd Singularity
sudo bash setup.sh
sudo bash scripts/x.sh

Existem vários mecanismos de detecção a serem instalados para detectar esse comportamento com uma taxa de falsos positivos próxima de zero, começando com a clonagem de um repositório do GitHub no diretório /dev/shm .

sequence by process.entity_id, host.id with maxspan=10s
  [process where event.type == "start" and event.action == "exec" and (
     (process.name == "git" and process.args == "clone") or
     (
       process.name in ("wget", "curl") and
       process.command_line like~ "*github*"
     )
  )]
  [file where event.type == "creation" and
   file.path like ("/tmp/*", "/var/tmp/*", "/dev/shm/*")]

A clonagem de diretórios em /tmp e /var/tmp é comum, portanto, estes poderiam ser removidos desta regra em ambientes onde a clonagem de repositórios é comum. A mesma atividade em /dev/shm, no entanto, é muito incomum.

O script setup.sh , chamado pelo carregador, continua compilando o LKM em um subdiretório /dev/shm/ . Em geral, os agentes de ameaças reais não compilam o malware no próprio host; no entanto, não é incomum que isso aconteça de qualquer maneira.

sequence with maxspan=10s
  [process where event.type == "start" and event.action == "exec" and
   process.name like (
     "*gcc*", "*g++*", "c++", "cc", "c99", "c89", "cc1*", "clang*",
     "musl-clang", "tcc", "zig", "ccache", "distcc"
   )] as event0
  [file where event.action == "creation" and file.path like "/dev/shm/*" and
   process.name like (
     "ld", "ld.*", "lld", "ld.lld", "mold", "collect2", "*-linux-gnu-ld*", 
     "*-pc-linux-gnu-ld*"
   ) and
   stringcontains~(event0.process.command_line, file.name)]

Essa lógica de ponto final detecta a execução de um compilador, seguida pela criação de um arquivo pelo linker em /dev/shm (ou um subdiretório).

E, finalmente, como clonou todo o repositório em /dev/shm e executou setup.sh e x.sh, observaremos a execução do processo a partir do diretório de memória compartilhada, o que é incomum na maioria dos ambientes:

process where event.type == "start" and event.action == "exec" and
process.executable like ("/dev/shm/*", "/run/shm/*")

Essas regras estão disponíveis nos repositórios detection-rules e protections-artifacts:

Disfarçando-se de processos legítimos

Para evitar serem detectados durante a enumeração de processos ou o monitoramento do sistema, os rootkits frequentemente renomeiam seus processos e threads para que correspondam a componentes benignos do sistema. Disfarces comuns incluem:

  • kworker, migration ou rcu_sched (threads do kernel)
  • sshd, systemd, dbus-daemon, ou bash (daemons do espaço do usuário)

Esses nomes são escolhidos para se misturarem com a saída de ferramentas como ps, top ou htop, tornando a detecção manual mais difícil. Exemplos de rootkits que utilizam essa técnica incluem Reptile e PUMAKIT. Reptile gera eventos de rede incomuns através de kworker na inicialização:

network where event.type == "start" and event.action == "connection_attempted" 
and process.name like~ ("kworker*", "kthreadd") and not (
  destination.ip == null or
  destination.ip == "0.0.0.0" or
  cidrmatch(
    destination.ip,
    "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12",
    "192.0.0.0/24", "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32",
    "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24", 
    "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24",
    "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24","198.18.0.0/15", 
    "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1",
    "FE80::/10", "FF00::/8"
  )
)

O exemplo abaixo mostra a funcionalidade de "port knocking" do Reptile, onde a thread do kernel cria um novo processo, altera seu ID de sessão para 0 e estabelece a conexão de rede:

Também foi observado que o Reptile utiliza o mesmo processo kworker para criar arquivos:

file where event.type == "creation" and
process.name like~ ("kworker*", "kthreadd")

O PUMAKIT gera threads do kernel para executar comandos do espaço do usuário por meio de kthreadd, mas atividade semelhante foi observada por meio de um processo kworker em outros rootkits:

process where event.type == "start" and event.action == "exec" and
process.parent.name like~ ("kworker*", "kthreadd") and
process.name in ("bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish") and
process.args == "-c"

Essas regras kworker e kthreadd podem gerar falsos positivos devido às operações internas do kernel do Linux. Esses itens podem ser facilmente excluídos para cada ambiente individualmente, ou argumentos adicionais da linha de comando podem ser adicionados à lógica.

Essas regras estão disponíveis nos repositórios detection-rules e protections-artifacts:

Além disso, processos maliciosos, como um dropper inicial ou um mecanismo de persistência, podem se disfarçar de threads do kernel e usar uma função interna do shell para isso. Utilizando o comando exec -a , qualquer processo pode ser iniciado com um nome escolhido pelo atacante. A falsificação de processos do kernel pode ser detectada através da seguinte consulta de detecção:

process where event.type == "start" and event.action == "exec" and 
process.command_line like "[*]" and process.args_count == 1

Esse comportamento é mostrado abaixo, onde vários malwares tentaram se passar por um processo de kernel ou por um processo de serviço web.

Essa técnica também é comumente usada indevidamente por agentes maliciosos que utilizam o conjunto de ferramentas The Hacker's Choice (THC), especificamente ao implantar o gsocket.

As regras relacionadas ao mascaramento do kernel e ao mascaramento via exec -a em geral estão disponíveis no repositório protections-artifacts:

Outra técnica vista na natureza, e também em Horse Pill, é o uso de prctl para sobrescrever o nome do processo. Para garantir que essa telemetria esteja disponível, uma regra Auditd personalizada pode ser criada:

-a exit,always -F arch=b64 -S prctl -k prctl_detection

E acompanhado da seguinte lógica de detecção:

process where host.os.type == "linux" and auditd.data.syscall == "prctl" and
auditd.data.a0 == "f"

Permitirá a detecção dessa técnica. Na captura de tela abaixo, podemos ver exemplos de telemetria dessa técnica sendo usada, onde process.executable é um caractere sem sentido e prctl será usado para se passar por um processo legítimo no sistema.

Esta regra, incluindo as instruções de configuração, está disponível aqui:

Embora existam muitas maneiras de se disfarçar, estas são as mais comuns observadas.

Limpeza de logs e auditorias

Muitos rootkits incluem rotinas que apagam vestígios de sua instalação ou atividade dos registros. Uma dessas técnicas consiste em limpar o histórico de disparos da vítima. Isso pode ser detectado de duas maneiras. Um método consiste em detectar a exclusão do arquivo de histórico do shell:

file where event.type == "deletion" and file.name in (
  ".bash_history", ".zsh_history", ".sh_history", ".ksh_history",
  ".history", ".csh_history", ".tcsh_history", "fish_history"
)

O segundo método consiste em detectar execuções de processos com argumentos de linha de comando relacionados à limpeza do histórico do shell:

process where event.type == "start" and event.action == "exec" and (
  (
    process.args in ("rm", "echo") or
    (
      process.args == "ln" and process.args == "-sf" and
      process.args == "/dev/null"
    ) or
    (process.args == "truncate" and process.args == "-s0")
  )
  and process.command_line like~ (
    "*.bash_history*", "*.zsh_history*", "*.sh_history*", "*.ksh_history*",
    "*.history*", "*.csh_history*", "*.tcsh_history*", "*fish_history*"
  )
) or
(process.name == "history" and process.args == "-c") or
(
  process.args == "export" and
  process.args like~ ("HISTFILE=/dev/null", "HISTFILESIZE=0")
) or
(process.args == "unset" and process.args like~ "HISTFILE") or
(process.args == "set" and process.args == "history" and process.args == "+o")

Ter ambas as regras de detecção (processo e arquivo) ativas permitirá uma estratégia de defesa em profundidade mais robusta.

Ao serem carregados, os rootkits podem contaminar o kernel ou gerar mensagens fora da árvore de código, que podem ser identificadas ao analisar os logs do syslog e do kernel. Para apagar seus rastros, os rootkits podem excluir estes arquivos de registro:

file where event.type == "deletion" and file.path in (
  "/var/log/syslog", "/var/log/messages", "/var/log/secure", 
  "/var/log/auth.log", "/var/log/boot.log", "/var/log/kern.log", 
  "/var/log/dmesg"
)

Ou limpe o buffer de mensagens do kernel através de dmesg:

process where event.type == "start" and event.action == "exec" and
process.name == "dmesg" and process.args in ("-c", "--clear")

Um exemplo de rootkit que limpa automaticamente o dmesg é o rootkit bds, que é carregado executando /opt/bds_elf/bds_start.sh:

Outra forma de limpar esses registros é usando o journalctl:

process where event.type == "start" and event.action == "exec" and
process.name == "journalctl" and
process.args like ("--vacuum-time=*", "--vacuum-size=*", "--vacuum-files=*")

Essa é uma técnica que foi usada pela Singularity:

Outra técnica empregada pelo script de carregamento do Singularity é a exclusão de todos os arquivos associados ao rootkit caso ele não consiga carregar, ou assim que o processo de carregamento for concluído. Para uma eliminação mais completa, o autor optou pelo uso de shred em vez de rm. rm (remover) simplesmente exclui o ponteiro do arquivo, tornando-o rápido, mas permitindo a recuperação de dados. shred sobrescreve os dados do arquivo várias vezes com dados aleatórios, garantindo que não possam ser recuperados. Isso torna a exclusão mais permanente, mas, ao mesmo tempo, mais ruidosa do ponto de vista da detecção de comportamento, já que shred não é comumente usado na maioria dos sistemas Linux.

process where event.type == "start" and event.action == "exec" and
process.name == "shred" and (
// Any short-flag cluster containing at least one of u/z, 
// and containing no extra "-" after the first one
process.args regex~ "-[^-]*[uz][^-]*" or
process.args in ("--remove", "--zero")
) and
not process.parent.name == "logrotate"

A expressão regular acima garante que as tentativas de burlar a detecção combinando ou modificando flags se tornem mais difíceis. Abaixo, um exemplo do Singularity procurando e destruindo arquivos relacionados à sua implantação:

Essas técnicas de remoção de arquivos e logs podem ser detectadas por meio de diversas regras de detecção prontas para uso:

Após um rootkit terminar de apagar seus rastros, ele pode registrar a data e hora dos arquivos que alterou para garantir que nenhum vestígio de modificação seja deixado para trás:

process where event.type == "start" and event.action == "exec" and
process.name == "touch" and
process.args like (
  "-t*", "-d*", "-a*", "-m*", "-r*", "--date=*", "--reference=*", "--time=*"
)

Um exemplo disso é mostrado aqui, onde um agente malicioso usa o carimbo de data/hora do arquivo /etc/ld.so.conf como referência de tempo para os arquivos na unidade /dev/shm em uma tentativa de se camuflar:

Esta é uma técnica para a qual adicionamos cobertura por meio de regras de detecção e artefatos de proteção:

Embora existam sempre mais técnicas que não abordamos nesta pesquisa, estamos confiantes de que ela contribuirá para aprofundar a compreensão do cenário de rootkits no Linux e da engenharia de sua detecção.

técnicas de prevenção de rootkits

Prevenir rootkits no Linux exige uma estratégia de defesa em camadas que combine o fortalecimento do kernel e do espaço do usuário, controle de acesso rigoroso e monitoramento contínuo. Frameworks de controle de acesso obrigatórios, como SELinux e AppArmor, limitam o comportamento dos processos e as oportunidades de persistência no espaço do usuário. Entretanto, técnicas de reforço da segurança do kernel, incluindo o Modo de Bloqueio (Lockdown Mode), KASLR, SMEP/SMAP e ferramentas como o LKRG, mitigam o risco de comprometimento em nível de kernel. Restringir o uso de módulos do kernel, desativando o carregamento dinâmico ou impondo a assinatura de módulos, reduz ainda mais os vetores comuns para a implantação de rootkits.

A visibilidade de comportamentos maliciosos é aprimorada por meio do Auditd e do monitoramento da integridade de arquivos para chamadas de sistema e atividades de arquivos, bem como por meio de soluções EDR que identificam e previnem comportamentos suspeitos em tempo de execução. A segurança é ainda mais reforçada pela minimização dos privilégios do processo através de seccomp-bpf, capacidades do Linux e do landlock LSM, restringindo assim o acesso a chamadas de sistema e interações com o sistema de arquivos.

Atualizações oportunas do kernel e do software, com suporte de correções em tempo real quando necessário, eliminam vulnerabilidades conhecidas antes que sejam exploradas. Além disso, as configurações do sistema de arquivos e do dispositivo devem ser reforçadas remontando sistemas de arquivos sensíveis com sinalizadores restritivos e desativando o acesso às interfaces de memória do kernel, como /dev/mem e /proc/kallsyms.

Nenhum controle isolado consegue impedir completamente os rootkits. Uma defesa em camadas, que combine o fortalecimento da configuração, a detecção estática e dinâmica e a prontidão forense, continua sendo essencial.

Conclusão

Na primeira parte desta série, examinamos como os rootkits do Linux operam internamente, explorando sua evolução, taxonomia e técnicas para manipular o espaço do usuário e o espaço do kernel. Nesta segunda parte, traduzimos esse conhecimento em estratégias práticas de detecção, com foco nos sinais comportamentais e na telemetria de tempo de execução que expõem a atividade do rootkit.

Embora o malware para Windows continue a dominar o foco dos fornecedores de segurança comercial e das comunidades de pesquisa de ameaças, o Linux permanece comparativamente pouco pesquisado, apesar de alimentar a maior parte da infraestrutura de nuvem, ambientes de computação de alto desempenho e serviços de internet do mundo.

Nossa análise destaca que os rootkits do Linux estão evoluindo. A crescente adoção de tecnologias como eBPF, io_uring e cargas de trabalho Linux conteinerizadas introduz novas superfícies de ataque que ainda não são bem compreendidas ou amplamente protegidas.

Encorajamos a comunidade de segurança a:

  • Invista em engenharia de detecção focada em Linux, tanto do ponto de vista estático quanto dinâmico.
  • Compartilhar abertamente resultados de pesquisas, provas de conceito e estratégias de detecção para acelerar o conhecimento coletivo entre os defensores.
  • Colaborar com fornecedores, instituições acadêmicas e a indústria para impulsionar a defesa contra rootkits no Linux rumo ao mesmo nível de maturidade alcançado no Windows.

Somente aprimorando coletivamente as capacidades de visibilidade, detecção e resposta, os defensores poderão se manter à frente desse cenário de ameaças furtivas e em rápida evolução.

Compartilhe este artigo