O update que fez a CrowdStrike parar o mundo
Entenda e reflita sobre o incidente da empresa, ao atualizar o Falcon, que respingou no mundo todo
Entendendo a Falha da CrowdStrike e suas Consequências
Recentemente, os Estados Unidos enfrentaram os famosos “apagões cibernéticos” que foram bem significativos, trazendo à tona uma certa fragilidade dos sistemas críticos de tecnologia. O incidente envolvendo a CrowdStrike e seu produto Falcon ilustra bem as problemáticas e suas consequências, oferecendo uma oportunidade para refletir sobre as práticas e responsabilidades em cibersegurança. Este episódio não só destacou a importância das boas práticas, mas também as consequências severas quando erros críticos ocorrem. Errar é humano, mas até que ponto é tolerável?
Contexto e o que aconteceu
A CrowdStrike é uma empresa de cibersegurança conhecida por seu software de Endpoint Detection and Response (EDR) chamado Falcon. EDR é uma tecnologia usada para monitorar e responder a ameaças nos endpoints, como computadores e dispositivos móveis. Em uma atualização recente, uma falha crítica ocorreu, causando interrupções significativas.
Detalhes Técnicos do Incidente
A Atualização Problemática
- Update Automático: A atualização foi distribuída automaticamente para os usuários do Falcon. Atualizações automáticas são comuns e úteis para garantir que todos os sistemas estejam protegidos contra as ameaças mais recentes. No entanto, nesse caso, a atualização continha um bug crítico.
- Falha no Processo de Teste: A falha parece estar relacionada a uma insuficiência nos testes. Isso indica que a atualização não passou por testes rigorosos ou que algum aspecto crítico não foi adequadamente avaliado antes da liberação.
Como Funciona um Sistema Operacional
Para compreender o impacto da falha, é fundamental entender o funcionamento de um sistema operacional (SO). O SO atua como um intermediário entre o hardware e os aplicativos, gerenciando recursos como CPU, memória e dispositivos de entrada/saída. O nível de kernel, onde ocorrem as operações mais críticas, gerencia:
- Gerenciamento de Processos: Controla a execução e alocação de tempo da CPU.
- Gerenciamento de Memória: Aloca e libera memória, evitando interferências entre processos.
- Gerenciamento de Dispositivos: Facilita a comunicação entre aplicativos e hardware.
Interações com o Kernel
O Falcon, como uma solução de EDR, opera em um nível muito baixo do sistema operacional, interagindo diretamente com o kernel. Alterações ou falhas nessas interações podem ter consequências graves, incluindo a falha completa do sistema.
Causas do Incidente
A falha foi causada por um erro crítico na atualização do módulo Sensor do Falcon, que envolveu a tentativa de acesso a um ponteiro nulo. Em termos técnicos, um ponteiro nulo aponta para um endereço de memória inválido, o que pode causar falhas graves, especialmente quando o erro ocorre no nível de kernel do sistema operacional.
Endereços de Memória e Ponteiros
Em programação, um ponteiro é como um endereço que você guarda para saber onde algo está localizado. Vamos dar uma passada, com exemplo, sobre ponteiros:
Imagine que um ponteiro é como um atalho que você guarda para saber onde uma variável está localizada na memória do computador. Esse atalho permite que você acesse e modifique o valor da variável diretamente, sem precisar se preocupar com onde exatamente ela está armazenada.
Por exemplo, suponha que temos uma estrutura chamada Data
que contém dois números inteiros, x
e y
. Quando criamos um ponteiro para essa estrutura, como Data* data_ptr = new Data();
, estamos dizendo que data_ptr
vai armazenar o endereço de onde a estrutura Data
está guardada na memória do computador.
- Quando usamos
data_ptr->x
, estamos acessando o valor do primeiro número inteiro na estruturaData
, que está localizado exatamente no endereço quedata_ptr
está apontando. - Já
data_ptr->y
está em um endereço um pouco mais adiante na memória, deslocado por 4 bytes em relação aodata_ptr
(considerando que umint
ocupa 4 bytes).
Um erro comum é tentar usar o ponteiro sem verificar se ele está apontando para um local válido. Isso pode causar problemas graves se o ponteiro estiver nulo, ou seja, se ele não estiver realmente apontando para lugar nenhum.
Código de Exemplo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
struct Data {
int x;
int y;
};
int main() {
Data* data_ptr = new Data(); // Criando um ponteiro para Data
data_ptr->x = 10; // Inicializando x
data_ptr->y = 20; // Inicializando y
std::cout << "Valor de x: " << data_ptr->x << std::endl;
std::cout << "Valor de y: " << data_ptr->y << std::endl;
delete data_ptr; // Liberando memória
return 0;
}
Saída Esperada
1
2
Valor de x: 10
Valor de y: 20
Nesse exemplo, criamos uma estrutura chamada Data
e um ponteiro data_ptr
que age como um atalho para uma instância dessa estrutura. Inicializamos os valores dos membros da estrutura e os acessamos através do ponteiro (atalho). Entretanto, não verificamos se o ponteiro é válido antes de usá-lo. Por fim, liberamos a memória alocada.
Devemos entender que o erro ocorreu porque o código da atualização não verificou se o ponteiro estava nulo antes de tentar acessar a memória, resultando em uma falha crítica.
Código completo com verificação de validade
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
struct Data {
int x;
int y;
};
int main() {
Data* data_ptr = new Data();
data_ptr->x = 10;
data_ptr->y = 20;
std::cout << "Valor de x: " << data_ptr->x << std::endl;
std::cout << "Valor de y: " << data_ptr->y << std::endl;
// Verificando se o ponteiro não é nulo antes de acessar
if (data_ptr != nullptr) {
std::cout << "Ponteiro é válido." << std::endl;
} else {
std::cout << "Ponteiro é nulo." << std::endl;
}
delete data_ptr;
data_ptr = nullptr;
return 0;
}
Saída Esperada
1
2
3
Valor de x: 10
Valor de y: 20
Ponteiro é válido.
Entendendo o código por partes - Passo a Passo
Inclusão da Biblioteca
1
#include <iostream>
Importamos a biblioteca
iostream
para permitir o uso destd::cout
estd::endl
para saída de texto.Definição da Estrutura
Data
1 2 3 4
struct Data { int x; int y; };
Definimos uma estrutura
Data
que contém dois membros inteiros,x
ey
.Função
main
1
int main() {
Início da função principal, onde o programa começa a execução.
Criação de um Ponteiro para
Data
1
Data* data_ptr = new Data();
Criamos um ponteiro
data_ptr
que aponta para uma nova instância da estruturaData
alocada dinamicamente na memória.Inicialização dos Membros da Estrutura
1 2
data_ptr->x = 10; data_ptr->y = 20;
Atribuímos os valores
10
e20
aos membrosx
ey
da estruturaData
através do ponteiro.Exibição dos Valores
1 2
std::cout << "Valor de x: " << data_ptr->x << std::endl; std::cout << "Valor de y: " << data_ptr->y << std::endl;
Usamos
std::cout
para exibir os valores dex
ey
acessados através do ponteiro.Verificação do Ponteiro adicionada
1 2 3 4 5
if (data_ptr != nullptr) { std::cout << "Ponteiro (atalho) é válido." << std::endl; } else { std::cout << "Ponteiro (atalho) é nulo." << std::endl; }
Verificamos se o ponteiro
data_ptr
não é nulo antes de usá-lo. Se for válido, imprimimos uma mensagem apropriada.Liberação da Memória
1 2
delete data_ptr; data_ptr = nullptr;
Liberamos a memória alocada para
data_ptr
e definimos o ponteiro comonullptr
para evitar acessos futuros inválidos.Finalizando a função
main
1 2
return 0; }
Impacto nos Sistemas
A falha afetou amplamente sistemas que utilizavam o Falcon, resultando em interrupções significativas, como o cancelamento de voos e a indisponibilidade de serviços essenciais como o 911. No Brasil, o impacto foi menor, possivelmente devido à menor dependência do Falcon ou à aplicação incompleta da atualização.
Análise da Solução e Resolução do Problema
Soluções Implementadas
Após a falha, a CrowdStrike implementou as seguintes soluções:
- Identificação do Erro: O erro foi localizado no código da atualização, que causava a tentativa de acessar um endereço de memória inválido.
- Reversão Remota: Uma reversão remota foi publicada, exigindo que os computadores afetados fossem reiniciados para aplicar a correção.
- Modo de Segurança: Para aqueles que não conseguiram aplicar a correção automaticamente, foi necessário iniciar o sistema no modo de segurança e remover manualmente o arquivo problemático.
Detalhes Técnicos da Resolução
- CSAgent.sys: A análise dos binários revelou que não houve mudanças significativas entre a versão problemática e a corrigida do driver
CSAgent.sys
, utilizando ferramentas como BinDiff. Portanto, a falha não foi causada por uma mudança no código do driver. - Arquivos de Atualização: Verificou-se que o arquivo de atualização “C-00000291-*.sys” não estava zerado como alegado, mas continha informações válidas. A falha ocorreu quando o CSAgent.sys tentou parsear arquivos corrompidos devido a uma falta de gerenciamento de erros, resultando em um acesso de memória inválido.
Políticas de Atualização e Melhoria dos Processos de Teste
- Política de Atualização: A CrowdStrike recomenda a configuração de uma política de atualização que permita manter uma ou mais versões anteriores, evitando que atualizações instantâneas possam causar problemas semelhantes no futuro. Além disso, a adoção de um cronograma de atualizações pode prevenir ocorrências de falhas em massa.
- Testes Exaustivos: Implementar processos de teste mais rigorosos e abrangentes para garantir que todas as atualizações sejam seguras antes da distribuição.
- Testes Automatizados e Manuais: Usar uma combinação de testes automatizados para cobertura rápida e testes manuais para casos específicos que possam ser negligenciados por scripts.
Reflexões e Boas Práticas
A Culpabilidade da Microsoft e Comparações com o Linux
É importante esclarecer que a Microsoft não é responsável pelo incidente, apesar de algumas críticas direcionadas a ela. A falha foi exclusiva da atualização da CrowdStrike, e não uma vulnerabilidade do sistema operacional Windows. Em um cenário ideal, a Microsoft poderia usar a situação para promover seu próprio produto, como o Defender for Endpoint, mas isso não é uma questão de culpabilidade.
As comparações entre Windows e Linux também são simplistas e enganosas. O Linux enfrentou recentemente um incidente envolvendo um backdoor, que foi rapidamente resolvido devido à natureza open-source do código, permitindo que a comunidade detectasse e corrigisse a falha. Isso não significa que Linux ou Windows sejam infalíveis, nem que seja um melhor que o outro e nem que um é mais propício a dar problemas de grande porte que o outro, mas pode destacar a importância da transparência e colaboração do código aberto. O backdoor foi uma engenharia social que quase deu certo e na prática não afetou praticamente ninguém.
Dentro de publicações que tentam descredibilizar o Windows e responsabilizar a Microsoft pelo incidente do Falcon, muito foi usado como carta de ‘ataque’ a linux esta situação do backdoor, como se fosse uma comparação viável. Essa parte do backdoor do linux, na época, furou a bolha e muitos até hoje não sabem direito o que aconteceu e como tudo se desenrolou. Por mais que seja uma severidade crítica de base score 10 (CVE-2024-3094), até por cenários que poderiam surgir a partir daquilo em determinadas situações, a ‘exploitability score’ foi de 3.9 e isso diz muito sobre como baixo foi o risco prático disso, e os usuários finais nem precisaram se preocupar tal qual os usuários de windows com o acontecimento que estamos falando neste ‘artigo’.
Enfim, windows e sistemas que usam kernel linux são excelentes ferramentas e tem seus altos e baixos, essa briguinha de rede social numa situação séria dessas pode trazer muita desinformação, até em relação a cibersegurança.
Críticas e Resposta às Falhas
Criticar práticas e erros após um incidente é fácil quando estamos no conforto de nossas casas, mas é essencial reconhecer que erros são inevitáveis, mesmo para empresas altamente qualificadas. Trabalhar em cibersegurança é como operar em um ambiente de alta precisão; erros podem ter consequências graves, semelhantes aos riscos enfrentados por cirurgiões ou pilotos.
Boas Práticas a Considerar:
- Testes Rigorosos: Realizar testes exaustivos antes da implementação de atualizações.
- Monitoramento e Resposta: Ter sistemas de monitoramento e planos de resposta bem definidos.
- Comunicação e Transparência: Desenvolver uma estratégia de comunicação eficaz para manter os usuários informados durante incidentes e atualizações.
- Resiliência e Recuperação: Estabelecer planos de contingência robustos para mitigar os impactos de falhas e garantir a rápida recuperação dos sistemas afetados.
Mesmo as maiores empresas podem enfrentar erros, e a falha da CrowdStrike serve como um lembrete da importância de manter práticas rigorosas de segurança e resposta a incidentes.
Conclusão reflexiva
O incidente da CrowdStrike não somente destaca a cibersegurança como uma tarefa complexa e desafiadora, mas também é um alerta sobre a necessidade de manter padrões rigorosos nesse respeito. Do mesmo modo que pilotos e cirurgiões não podem permitir certos erros, basicamente porque as consequências podem ser letais, empresários trabalhando em segurança cibernética, também, devem seguir esse modelo. Desde que os seres humanos cometam erros e eles sejam inevitáveis, as consequências de tal “humanidade” em sistemas tão críticos podem ser insuportáveis.
Deste modo, o exemplo ressalva a importância de uma política de segurança sólida, testes abrangentes e abordagem pró-ativa à proteção cibernética. Corporações como a CrowdStrike que desempenha um papel crítico em proteger um sistema crítico precisam assegurar que suas atualizações e modificações de software sejam submetidas a processos de avaliação detalhados a fim de impedir qualquer tipo de falha.
Comparações podem ser feitas com incidentes na aviação, onde falhas em sistemas críticos levaram a grandes avanços na segurança devido a uma análise minuciosa e à implementação de melhorias. A cibersegurança deve seguir o mesmo caminho, aprendendo com os erros para construir sistemas mais robustos e confiáveis.
Por mais que sejamos humanos (e humanos erram), determinados erros de certas profissões não podem ser cometidos, principalmente quando estamos falando de profissões que lidam com a vida, por exemplo. Um piloto não pode escolher pilotar desligando seu “transponder”, pois ficaria mais fácil de ocorrer uma colisão com outra aeronave. Mesmo tendo 30 anos de piloto e nunca tendo errado, isso não justifica que não deve ser criticado depois de cometer um erro desse.
Quando consideramos os riscos envolvidos em cibersegurança — desde a interrupção de sistemas hospitalares e voos até a paralisia de sistemas bancários — fica claro que alguns erros não podem ser tolerados. A falha da CrowdStrike, embora não seja fatal, atrasou a vida de muitas pessoas e resultou em perdas econômicas significativas. É um tipo de erro que não deve ser tolerado porque suas repercussões são amplas e profundas, afetando não apenas o mundo digital, mas também a vida real e a economia.
Por fim, a falha da CrowdStrike é um lembrete poderoso de que, em um mundo digital cada vez mais interconectado, não podemos nos permitir negligenciar as etapas rigorosas de segurança. A prevenção é fundamental, e uma falha em um componente de software pode ter repercussões que se estendem muito além do domínio digital, afetando vidas e economias. É um chamado para que todos na indústria de tecnologia redobrem seus esforços para garantir a segurança e a confiança nos sistemas de que todos dependemos.
Para mais detalhes técnicos com uma análise aprofundada, recomendo uma postagem rápida da hakai security aqui.
Comments powered by Disqus.