1

O que é eBPF e por que ele é o melhor caminho pra detectar ataques pelo comportamento

Se você tá começando em TI, provavelmente já ouviu que antivírus serve pra pegar vírus. Só que boa parte das ferramentas de segurança funciona comparando um arquivo com uma lista de coisas já conhecidas. Se o atacante mudar o arquivo um pouquinho, a comparação falha. Existe um jeito de detectar ataque que não depende do arquivo, e sim do que o programa faz. O eBPF é a tecnologia que torna isso possível no Linux.
Pra entender como, primeiro precisa saber o que acontece quando um programa roda.
Programa não mexe em nada sozinho
Num computador, quem controla o hardware (disco, rede, memória) é o kernel, o núcleo do sistema operacional. Um programa comum não tem permissão pra ler um arquivo direto no disco nem pra abrir uma conexão de rede. Ele precisa pedir pro kernel, e esse pedido se chama syscall (chamada de sistema).
Por exemplo, quando um programa quer abrir um arquivo, ele faz a syscall openat. Pra iniciar outro programa, faz execve. Pra conectar num servidor, faz connect. Tudo que um programa faz de relevante passa por uma dessas chamadas, sem exceção.
Por que isso importa pra segurança
Imagina que um atacante invadiu um site e colocou um script malicioso lá. Ele pode escrever esse script de mil jeitos diferentes, mudar nomes, embaralhar o código, apagar rastro. Mas o que o script quer fazer no fim das contas é executar comandos, ler arquivos de senha e mandar dados pra fora. Isso exige as mesmas syscalls, de qualquer forma que o código esteja escrito.
Então, em vez de perguntar "esse arquivo é conhecido?", dá pra perguntar "esse programa tá pedindo coisas que não combinam com o trabalho dele?". Um servidor web que de repente executa um terminal e lê o arquivo .env não precisa estar numa lista de vírus pra levantar suspeita. A isso se chama detecção por comportamento.
Pra fazer isso, alguém precisa enxergar as syscalls. E é aí que entra o eBPF.
O que é eBPF
eBPF é um recurso do kernel do Linux que permite rodar pequenos programas dentro do próprio kernel, ligados a eventos específicos. Dá pra pedir, por exemplo: "toda vez que alguma syscall execve acontecer, rode o meu programa e me conte quem pediu e qual arquivo foi executado."
Antes do eBPF, as opções eram piores. O strace consegue mostrar syscalls, mas desacelera muito o processo observado e acompanha um de cada vez, então não serve pra monitorar um servidor inteiro. O auditd é mais amplo, mas com muitas regras gera um volume grande de log e pesa. E escrever um módulo de kernel dá acesso total, só que qualquer erro seu pode travar a máquina inteira.
O eBPF resolve boa parte disso porque o kernel tem um verificador. Antes de aceitar o seu programa, ele checa se o código é seguro: se não tem laço infinito, se não acessa memória que não deveria. Se reprovar, o programa não carrega. Não é perfeito, já apareceram falhas no próprio verificador, mas o modelo é bem mais seguro que um módulo de kernel.
Pra ver funcionando, numa máquina de teste e com o bpftrace instalado:
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_execve { printf("%s executou %s\n", comm, str(args->filename)); }'
Deixa rodando e abre outro terminal pra digitar comandos. Cada programa iniciado aparece ali, com o nome de quem pediu. Num servidor, vale deixar uns minutos e ler o que sai. Quase sempre aparece coisa que você não sabia que rodava.
Do evento solto à detecção de ataque
Um evento isolado quase nunca diz muita coisa. Um servidor web executando sh pode ser suspeito, mas pode ser um script legítimo de manutenção. O que diferencia é o contexto: quem iniciou esse processo, e quem iniciou o processo que o iniciou.
Por isso os sistemas de defesa com eBPF guardam a árvore de processos, atualizando a cada vez que um processo cria outro. Quando o php-fpm cria um sh, que cria um curl conectando num IP que nunca apareceu antes, essa sequência é suspeita no conjunto, mesmo que cada passo sozinho pareça normal. E como a árvore está registrada, dá pra subir até a origem do ataque e achar tudo que veio dali, em vez de remover só a ponta.
Isso exige saber o que é normal na máquina que se está protegendo. Uma ferramenta que não aprende o comportamento normal gera alarme falso o dia todo, e a equipe acaba desligando. O comportamento precisa ser medido no servidor real, não copiado de uma lista genérica.
Detectar e bloquear não são a mesma coisa
Pra só observar, ligar o programa na entrada da syscall funciona bem. Pra bloquear, tem um problema. O caminho do arquivo que o programa quer abrir fica na memória do próprio programa, e outra thread dele pode trocar esse texto depois que você checou e antes de o kernel usar. Você aprova um caminho e o kernel abre outro. Esse erro tem nome: TOCTOU (verifica num momento, usa em outro).
Pra bloquear com segurança, o ideal é decidir num ponto em que o kernel já resolveu o caminho e trabalha com a própria cópia. O BPF LSM faz isso, pois liga o programa eBPF nos mesmos ganchos de segurança que SELinux e AppArmor usam. No SyscallCage, meu projeto open source, usei esse caminho por esse motivo. O custo é exigir um kernel recente, com CONFIG_BPF_LSM ativado e bpf na lista de módulos LSM no boot, o que nem toda distribuição traz de fábrica.
Limites
O eBPF vê o que passa pelo kernel. Não vê o que acontece só dentro da memória de um programa nem lê tráfego criptografado. Quem tem acesso root pode descarregar o seu programa, então proteger o próprio agente faz parte do projeto. Kernel antigo pode não ter os recursos necessários. E o custo de desempenho varia conforme o que você observa, então meça no seu caso em vez de confiar em número de artigo.
Se quiser conhecer ferramentas prontas que usam essa ideia, procure por Falco, Tetragon e Tracee. Mas se o objetivo é aprender, rode o comando acima primeiro e olhe a saída. É a forma mais rápida de entender o que o seu computador faz o tempo todo sem você ver.

Carregando publicação patrocinada...