InfraFenceInfraFence

Live Security Operations

Começar

Como detectar e remover um rootkit no /etc/ld.so.preload

Última atualização:

O /etc/ld.so.preload lista bibliotecas que o linker dinâmico carrega em todo programa antes de qualquer outra coisa. Num servidor normal, o arquivo não existe. Invasores que conseguem root gravam ali uma biblioteca que substitui funções da biblioteca C, como as que listam diretórios ou abrem arquivos, para que ps, top, ls, netstat e ss deixem de mostrar os processos, arquivos e conexões do invasor. Kits de código aberto como libprocesshider, Azazel e Jynx funcionam assim, e também várias famílias de mineradores de criptomoedas e backdoors.

O ponto fraco do truque é que ele só funciona em programas que carregam a biblioteca C. Ferramentas com link estático, a leitura direta do /proc e uma olhada de fora do sistema em execução passam por cima dele. Abaixo: como verificar, como limpar e quando reconstruir o servidor. Os comandos são para Debian e Ubuntu e para a família RHEL; /usr/lib/libhide.so representa a biblioteca que você encontrar.

Entenda como um rootkit de preload se esconde

  • Processos: ps e top leem o diretório /proc; um readdir() interceptado pula os IDs de processo do invasor.
  • Arquivos: o mesmo hook esconde arquivos pelo nome, muitas vezes incluindo o próprio /etc/ld.so.preload e a biblioteca, então ls e cat dizem que eles não existem.
  • Conexões: netstat e ss perdem as linhas dos sockets do invasor.
  • Todo o resto funciona normalmente, e essa é a ideia: o servidor parece limpo para todas as ferramentas em que você normalmente confiaria.

Do que ele não consegue se esconder: programas que não usam a biblioteca C do sistema (binários com link estático, como o busybox-static), o kernel e um sistema iniciado a partir de outra mídia. Um rootkit carregado como módulo do kernel é outro caso, mais difícil: ele se esconde do próprio /proc, e as verificações abaixo podem não pegá-lo.

Verifique com ferramentas que o rootkit não engana

Consiga um busybox com link estático

O busybox-static é um único binário com ls, cat, grep, sh e mais, linkado sem a biblioteca C, então uma biblioteca pré-carregada nunca entra nele. O ldd precisa responder not a dynamic executable.

Debian / Ubuntu
sudo apt install busybox-static
ldd /bin/busybox

A família RHEL não tem busybox estático nos repositórios base. Copie um de uma máquina Debian ou Ubuntu limpa (depois de instalar o busybox-static nela) e chame-o como /root/busybox em vez de busybox nos comandos abaixo:

Na sua máquina limpa
scp /bin/busybox root@SERVER_IP:/root/busybox
ssh root@SERVER_IP 'chmod 700 /root/busybox && ldd /root/busybox'

Nota: Instalar um pacote num servidor comprometido passa pelo gerenciador de pacotes dele, que tem link dinâmico. Uma cópia vinda de uma máquina limpa é a opção mais confiável em qualquer distribuição.

Leia o arquivo diretamente

Compare o que o busybox vê com o que as ferramentas do próprio sistema veem. Se o busybox mostra o arquivo e o ls e o cat normais dizem que ele não existe, há um rootkit ativo neste momento.

Qualquer distribuição
sudo busybox ls -la /etc/ld.so.preload
sudo busybox cat /etc/ld.so.preload
ls -la /etc/ld.so.preload
cat /etc/ld.so.preload

Para cada biblioteca citada no arquivo, verifique se algum pacote é dono dela. Existem usos legítimos raros, como o registrador de comandos Snoopy e alguns agentes de monitoramento, e eles vêm de um pacote que você instalou:

Debian / Ubuntu
dpkg -S /usr/lib/libhide.so
RHEL, Rocky Linux, AlmaLinux, Oracle Linux, Fedora
rpm -qf /usr/lib/libhide.so

Uma biblioteca que nenhum pacote possui é suspeita. Anote o tamanho e o hash dela, veja os nomes que ela contém (funções interceptadas como readdir, a palavra /proc) e quais processos a têm carregada:

Qualquer distribuição
sudo busybox ls -la /usr/lib/libhide.so
sudo busybox sha256sum /usr/lib/libhide.so
sudo busybox strings /usr/lib/libhide.so | busybox grep -iE 'readdir|/proc|preload|hide' | busybox head
Qualquer distribuição
sudo busybox sh -c "busybox grep -l '/usr/lib/libhide.so' /proc/[0-9]*/maps"

Compare o /proc com o ps

O busybox lê o /proc sem o hook; o ps passa por ele. Todo ID de processo que o busybox encontra e o ps não encontra está escondido, e a linha mostra o binário dele. Processos que terminaram durante o loop podem aparecer uma vez: rode duas vezes e olhe os IDs que aparecem nas duas.

Qualquer distribuição
sudo busybox sh -c 'for d in /proc/[0-9]*; do p=${d#/proc/}; /bin/ps -p "$p" > /dev/null 2>&1 || echo "$p $(busybox readlink "$d/exe")"; done'

O mesmo vale para as conexões de rede: o netstat do busybox lê o /proc/net diretamente. Uma conexão que está na primeira lista e falta na segunda está escondida.

Qualquer distribuição
sudo busybox netstat -tan
sudo ss -tanp

LD_PRELOAD em ambientes e serviços

O mesmo truque funciona por processo, pela variável LD_PRELOAD num arquivo de unidade, num perfil de shell ou no /etc/environment. Procure por ela nos processos em execução e nos arquivos de sempre:

Qualquer distribuição
sudo busybox sh -c "busybox grep -l LD_PRELOAD /proc/[0-9]*/environ"
sudo busybox grep -rs LD_PRELOAD /etc/environment /etc/profile /etc/profile.d /etc/bash.bashrc /etc/bashrc \
  /etc/systemd /lib/systemd/system /usr/lib/systemd/system /root/.bashrc /root/.profile

Binários do sistema alterados

Alguns kits também substituem ps, ls ou sshd. O banco de dados de pacotes lista os arquivos empacotados cujo conteúdo mudou (sem os arquivos de configuração):

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

O jeito garantido: a partir de um sistema de resgate

O dpkg e o rpm também têm link dinâmico. Para um resultado em que você possa confiar, inicie o sistema de resgate do provedor, monte o disco do servidor e leia o arquivo ali, onde nada do servidor está rodando. Encontre antes a partição raiz com lsblk: /dev/sda1 é um exemplo.

Sistema de resgate
lsblk -f
mount /dev/sda1 /mnt
ls -la /mnt/etc/ld.so.preload && cat /mnt/etc/ld.so.preload

Remova o rootkit de preload

Se o provedor permite um snapshot do disco, faça primeiro. Depois guarde uma cópia do arquivo e da biblioteca como evidência:

Qualquer distribuição
sudo busybox mkdir -p /root/evidence
sudo busybox cp -a /etc/ld.so.preload /usr/lib/libhide.so /root/evidence/
sudo busybox sha256sum /root/evidence/*

Rootkits muitas vezes tornam os seus arquivos imutáveis, para que até o root receba Operation not permitted. O busybox-static do Debian não tem chattr; o lsattr e o chattr do próprio sistema funcionam aqui, porque os kits de preload escondem arquivos pelo nome e normalmente não mexem nos atributos:

Qualquer distribuição
sudo lsattr /etc/ld.so.preload /usr/lib/libhide.so
sudo chattr -i -a /etc/ld.so.preload /usr/lib/libhide.so

Remova o arquivo de preload com o busybox. A partir do próximo programa iniciado, nada mais é pré-carregado, e o ls normal confirma que o arquivo sumiu:

Qualquer distribuição
sudo busybox rm /etc/ld.so.preload
ls -la /etc/ld.so.preload

Os processos que já estavam rodando continuam com a biblioteca carregada, mas os novos ps e ss que você inicia não, então o que estava escondido agora aparece. Procure, e congele o que não pertence ao sistema antes de matá-lo:

Qualquer distribuição
ps -ef --forest | less
sudo ss -tanp
sudo kill -STOP PID

Remova o que o traz de volta: tarefas do cron, unidades systemd, chaves SSH e contas, como em Como encontrar e remover um minerador de criptomoedas, que passa por cada lugar. Depois apague a biblioteca e reinicie, para que nenhum processo em execução continue com ela:

Qualquer distribuição
sudo busybox rm /usr/lib/libhide.so
sudo ldconfig
sudo reboot

Atenção: Considere conhecido todo segredo do servidor: chaves SSH, senhas, senhas de banco de dados e chaves de API em arquivos de configuração. O invasor teve root. Troque tudo a partir de uma máquina limpa.

Decida quando reconstruir o servidor

Gravar o /etc/ld.so.preload exige root. Depois que um invasor teve root, a limpeza remove o que você encontrou, não necessariamente tudo o que havia. Reconstrua a partir de uma imagem nova quando qualquer um destes itens for verdade:

  • Binários do sistema foram alterados (a verificação de pacotes acima).
  • O kernel está marcado (tainted) por um módulo desconhecido, ou o lsmod lista um módulo que você não sabe explicar.
  • Você não descobriu como o invasor entrou.
  • O servidor guarda dados de clientes, dados de pagamento ou credenciais de outros sistemas.
Qualquer distribuição
cat /proc/sys/kernel/tainted
lsmod | sort | head -50
sudo dmesg | grep -iE 'taint|module verification|unsigned'

0 em tainted é um kernel limpo; outros valores têm motivos, como drivers proprietários, então pesquise antes de concluir. Para reconstruir: crie um servidor novo a partir da imagem do provedor, atualize-o, restaure os dados (não programas ou configurações que você não consegue verificar) de um backup anterior à infecção, troque todos os segredos e então migre o tráfego. O checklist de VPS nova cobre a primeira hora.

Como o InfraFence detecta rootkits de ld.so.preload

O agente do InfraFence é um programa com link estático: ele não carrega a biblioteca C do sistema, então uma biblioteca pré-carregada não roda dentro dele e não consegue esconder arquivos ou processos do que o próprio agente lê.

  • Integridade de arquivos: o /etc/ld.so.preload está entre os arquivos monitorados, com uma impressão digital SHA-256 comparada a cada 30 minutos. Uma alteração nele é reportada como evento crítico integrity_change, com o hash antigo e o novo. Veja Integridade de arquivos e persistência.
  • Varredura de malware, integridade do sistema: um /etc/ld.so.preload com entradas é um achado crítico que mostra o conteúdo dele; processos presentes no /proc mas ausentes do ps são reportados como escondidos; executáveis em /tmp e /dev/shm e binários do sistema alterados desde a instalação do pacote (dpkg -V, rpm -Va) também são reportados. Veja Malware.
  • O mesmo monitoramento cobre a persistência que costuma vir junto: crontabs, unidades systemd, authorized_keys e sudoers.

Limites: as impressões digitais são tiradas quando o agente inicia, então o monitoramento de integridade reporta alterações em arquivos que já existiam naquele momento; um /etc/ld.so.preload que aparece depois, num servidor que não tinha um, é encontrado pela varredura de malware. As varreduras rodam na programação que você definir (as varreduras automáticas vêm desligadas por padrão) ou quando você clica em **Varrer agora**. Um rootkit carregado como módulo do kernel também consegue se esconder do /proc, e o InfraFence não tem uma detecção dedicada para ele. O InfraFence nunca apaga o /etc/ld.so.preload nem a biblioteca: a limpeza e a decisão de reconstruir continuam com você.

Perguntas

O /etc/ld.so.preload é sempre malicioso?
Não, mas é raro. Um servidor normal não tem esse arquivo. Algumas ferramentas legítimas o usam, como o registrador de comandos Snoopy, e elas vêm de um pacote que você instalou: dpkg -S ou rpm -qf na biblioteca dizem qual.
Apagar o arquivo é suficiente?
Isso acaba com o esconderijo para todo programa novo, e por isso é o primeiro passo. Não desfaz o que o invasor fez com root: persistência, outros backdoors, segredos roubados. É para isso que serve o resto da limpeza, ou a reconstrução.
O rkhunter e o chkrootkit encontram isso?
Eles procuram bibliotecas pré-carregadas e kits conhecidos, e vale a pena rodá-los. São scripts que chamam as ferramentas do próprio sistema, então num sistema infectado podem receber a mesma visão escondida. Rode-os a partir de um sistema de resgate para ter um resultado confiável.

Teste grátis em 1 servidor

O Starter é gratuito para um servidor, com proteção completa e bloqueio automático. Sem cartão de crédito.

Instale o agente como root, com o seu token no lugar de <TOKEN>:

curl -fsSL https://github.com/infrafence/infrafence-agent/releases/latest/download/install.sh | sudo bash -s -- --token <TOKEN>

O token é criado no painel, em Servidores › Adicionar servidor.