Os ataques cibernéticos são motivados principalmente pelo ganho financeiro, o que leva os invasores a desenvolverem continuamente novas técnicas para acessar dados. Apesar do aumento constante na frequência e na complexidade desses ataques, as vulnerabilidades relacionadas à corrupção de memória continuam sendo o principal problema, que já persiste há quatro décadas.
Os administradores podem aproveitar seu conhecimento sobre corrupção de memória para proteger ativamente sua infraestrutura contra ciberataques. Este guia tem como objetivo fornecer aos administradores o conhecimento necessário para compreender a corrupção de memória e suas consequências em caso de exploração de vulnerabilidades.
O que são vulnerabilidades do kernel do Linux?
O kernel do Linux está sujeito a uma variedade de problemas relacionados à memória. As vulnerabilidades relacionadas à memória a seguir são o foco dos invasores e constituem a base de muitas das correções de segurança lançadas mensalmente. Se você já se perguntou por que uma vulnerabilidade específica requer uma correção crítica, saiba que esses problemas podem levar a graves violações de dados.
Estouramento de buffer
Um estouro de buffer ocorre quando os desenvolvedores não validam as variáveis antes de atribuir dados a elas. Quando os dados excedem a capacidade definida da variável, ocorre um “estouro”, permitindo que um invasor injete seu próprio código no espaço de memória adjacente. Sem a validação adequada dos dados, um estouro de buffer pode resultar na obtenção de acesso root por parte de um invasor ou na possibilidade de ele executar código remotamente.
Como o Linux é escrito em C, ele é vulnerável a ataques de estouro de buffer, ao contrário de outras linguagens de programação, como Python e Java, que não são vulneráveis a esses ataques. Isso torna as vulnerabilidades do Linux particularmente perigosas, pois podem ser exploradas para causar danos significativos ao sistema.
CVE-2023-0179 é um exemplo de vulnerabilidade de estouro de buffer. Esse problema pode permitir o vazamento de endereços tanto da pilha quanto da pilha dinâmica e, potencialmente, permitir a escalada de privilégios local para o usuário root por meio da execução de código arbitrário.
Estouro de inteiro
Os desenvolvedores definem o valor máximo que pode ser armazenado em uma variável inteira com base no tipo de dados utilizado. Por exemplo, uma variável inteira sem sinal de 32 bits pode armazenar valores que variam de 0 a 4.294.967.295, enquanto uma variável inteira com sinal pode armazenar valores entre −2.147.483.648 e 2.147.483.647. No entanto, se o código adicionar um valor que exceda o limite máximo da variável, ocorre um “estouro”, levando a resultados inesperados.
Por exemplo, se uma instrução tentar somar 1 a uma variável que armazena o valor 2.147.483.647, o resultado será um valor negativo de -2.147.483.648. Da mesma forma, se um inteiro negativo sofrer estouro, o resultado será um número positivo. O comportamento dos inteiros sem sinal depende da linguagem de programação utilizada, mas, no caso da linguagem C, os resultados costumam ser imprevisíveis.
CVE-2022-0998 é uma vulnerabilidade de estouro de inteiro encontrada no código do driver de dispositivo virtio do kernel do Linux. Um usuário local pode explorar essa falha para causar uma falha no sistema ou, potencialmente, escalar seus privilégios no sistema.
Corrupção de memória
Desenvolvedores e administradores de servidores frequentemente consideram a corrupção de memória no kernel do Linux um problema desafiador. Essa corrupção pode levar a comportamentos imprevisíveis e, em alguns casos, nenhum erro é gerado. Esse problema surge quando os desenvolvedores alteram inadvertidamente dados na memória ou modificam ponteiros que apontam para locais específicos da memória onde os dados estão armazenados.
CVE-2023-1073 é um exemplo de vulnerabilidade de corrupção de memória descoberta no subsistema de dispositivos de interface humana (HID) do kernel do Linux. Um invasor local pode usar essa falha para causar uma falha no sistema ou, potencialmente, escalar seus privilégios no sistema.
Negação de Serviço
Os ataques distribuídos de negação de serviço (DDoS) são amplamente conhecidos; neles, os invasores utilizam vários dispositivos comprometidos para inundar um alvo com tráfego, o que resulta na falha do servidor.
No entanto, qualquer ataque que interfira no funcionamento de um serviço é conhecido como ataque de negação de serviço (DoS). O gerenciamento inadequado da memória costuma causar ataques DoS baseados em memória, conhecidos como ataques de esgotamento de recursos. Essas vulnerabilidades podem ser prejudiciais, levando a falhas críticas no serviço que afetam milhares de usuários, caso estejam presentes nos servidores.
CVE-2023-1390 é um exemplo de vulnerabilidade remota de negação de serviço descoberta no módulo TIPC do kernel do Linux. Essa falha permite que um invasor remoto provoque uma negação de serviço.
Dereferência de ponteiro NULL
Na programação em C, um ponteiro é uma variável que armazena o endereço de memória de um valor, em vez do próprio valor. Isso permite que os desenvolvedores manipulem o valor armazenado em um local específico da memória, mesmo que a variável associada a esse local esteja fora do escopo.
A desreferência de um ponteiro NULL ocorre quando um aplicativo tenta acessar um local na memória por meio de um ponteiro que ele considera válido, mas que, na verdade, é NULL. Isso pode levar à falha ou ao encerramento inesperado do aplicativo.
CVE-2022-47929 é uma vulnerabilidade de desreferência de ponteiro NULL encontrada na implementação da disciplina de enfileiramento de rede do kernel do Linux. Essa vulnerabilidade permite que um invasor local provoque uma negação de serviço (falha do sistema).
Uso antes da inicialização
Quando uma função utiliza uma variável para modificar ou criar dados, a própria variável deve primeiro ser inicializada com um valor. Se não for atribuído um valor à variável, ela é considerada não inicializada e causa comportamento indefinido caso seja referenciada no programa.
É difícil detectar comportamentos indefinidos decorrentes de dados não inicializados, pois os compiladores de C não são obrigados a diagnosticar ou gerar um erro. A maioria dos desenvolvedores utiliza ferramentas de teste ou de fuzzing para identificar dados não inicializados que possam causar erros indefinidos.
CVE-2022-29968 é um exemplo de vulnerabilidade do tipo “uso antes da inicialização” encontrada no kernel do Linux, na qual o subsistema io_uring não inicializa kiocb->private. Essa falha permite que um invasor local exponha informações confidenciais (memória do kernel).
Quais são as vulnerabilidades de memória mais perigosas?
Todos os anos, a MITRE publica seu relatório “As 25 Vulnerabilidades de Software Mais Perigosas”. Observe que esse relatório inclui ataques baseados na web, mas as três vulnerabilidades de memória mais comuns e perigosas são:
- Estouros de buffer
- Estouros de inteiros que levam a um estouro de buffer
- Desreferência de ponteiro (falta de verificação de ponteiro)
Todas as três vulnerabilidades podem levar a graves violações de dados. As vulnerabilidades relacionadas à corrupção de memória têm sido responsáveis por algumas das maiores violações de dados até o momento. Por exemplo, as explorações de vulnerabilidades em CPUs da Intel destacaram o papel crítico das falhas de hardware na facilitação de violações em todo o sistema. Uma conclusão importante de um relatório de inteligência recente é que cerca de 72% dos ataques são específicos a aplicativos e ataques a aplicativos da web. Um invasor pode identificar problemas no código e criar um exploit para tirar proveito da vulnerabilidade, já que programas de código aberto são frequentemente incluídos no código dependente ou constituem o próprio aplicativo principal.
A terceira estatística interessante do relatório é que 21% dos ataques têm como alvo o setor de tecnologia. Informações confidenciais precisam ser armazenadas, conectadas em rede, protegidas e transferidas pelo setor de tecnologia. Ao concentrarem-se nesse setor, os invasores podem obter acesso à infraestrutura que armazena os dados e explorá-la discretamente, possivelmente expondo a empresa por meses.
Como você identifica vulnerabilidades relacionadas à corrupção de memória?
A corrupção de memória geralmente é resultado de erros dos desenvolvedores, mas em situações em que vários aplicativos estão em execução em uma única máquina, identificar qual aplicativo está causando os problemas pode ser um desafio. Uma maneira de identificar erros no Linux é verificar os logs do sistema, onde o sistema operacional detecta quaisquer problemas.
Por exemplo, o Linux reserva os primeiros 64 KB de memória para o BIOS, e quaisquer modificações feitas nesse espaço de memória são verificadas pelo sistema operacional. Se o Linux detectar alguma alteração nessa memória reservada, ele registra um aviso para que os administradores resolvam o problema.
Como o Linux é um sistema operacional de código aberto, muitas vulnerabilidades relacionadas à memória são relatadas por pesquisadores. Uma dessas descobertas recentes é a vulnerabilidade “BleedingTooth”, que permite que invasores que possuam o endereço bd de uma máquina alvo a travem, causando uma negação de serviço (DoS), elevando privilégios e, possivelmente, obtendo acesso a chaves de criptografia. Outro exemplo é a vulnerabilidade da glibc, que tem sido amplamente divulgada e permite que invasores executem código arbitrário, o que frequentemente leva ao comprometimento do sistema.
Pesquisadores de segurança utilizam diversas ferramentas e técnicas para identificar falhas em softwares, incluindo a análise minuciosa do código e o uso de ferramentas de varredura, como o fuzzing, para provocar erros que possam ser relatados aos desenvolvedores. Após identificarem as vulnerabilidades, os desenvolvedores corrigem o código, e uma atualização de segurança é lançada para resolver o problema.
Como se corrige uma corrupção de memória?
Felizmente, o Linux implementou vários recursos de segurança para ajudar a combater a corrupção de memória, incluindo a Randomização do Layout do Espaço de Endereço do Kernel (KASL), a Integridade do Fluxo de Controle (CFI) e o Isolamento da Tabela de Páginas do Kernel (KPI). Apesar desses recursos de mitigação, no entanto, o sistema operacional e suas dependências ainda estão vulneráveis a ataques.
As técnicas de mitigação variam dependendo da vulnerabilidade identificada, mas as soluções temporárias geralmente envolvem a desativação de um componente crítico. Por exemplo, durante o incidente Heartbleed, os administradores podiam desativar o sinal de heartbeat usado no OpenSSL para a comunicação entre cliente e servidor. Embora isso tenha resolvido temporariamente o problema, qualquer aplicativo que exigisse um sinal de heartbeat do servidor teria enfrentado resultados inesperados, como falhas ou negação de serviço.
No entanto, as técnicas de mitigação temporárias não são permanentes, e é necessário aplicar correções para impedir a exploração da vulnerabilidade de forma definitiva. As correções de segurança atualizam o código, mas exigem a reinicialização do sistema, o que resulta em tempo de inatividade. Consequentemente, os administradores de sistema costumam adiar a aplicação de correções para vulnerabilidades até que haja uma janela de manutenção disponível, o que tem levado a algumas das maiores violações de dados já registradas.
Como proteger sua infraestrutura contra vulnerabilidades relacionadas à corrupção de memória?
Como os administradores ficam à mercê dos desenvolvedores, é essencial que tomem as medidas corretas para impedir os invasores. Você pode não ter controle sobre o código, mas os administradores podem tomar as medidas corretas para minimizar a superfície de ataque da rede e evitar se tornarem o próximo alvo. Aqui estão algumas maneiras pelas quais os administradores podem impedir ataques baseados em memória:
- Execute verificações de vulnerabilidades regularmente. Essas verificações identificarão problemas, inclusive aqueles já divulgados publicamente. Quando uma vulnerabilidade for detectada, será possível instalar uma correção.
- Realize testes completos em todos os aplicativos de terceiros antes de implementá-los em um servidor de produção.
- Uso o recurso de correção em tempo real do KernelCare para aplicar rapidamente os patches de segurança mais recentes sem a necessidade de reinicialização.
Conclusão
Detectar vulnerabilidades relacionadas à memória e até mesmo problemas mais complexos, como vulnerabilidades de autenticação, é um desafio, e a aplicação imediata de patches é fundamental para oferecer proteção ideal contra erros. O KernelCare Enterprise oferece um serviço de aplicação de patches em tempo real que elimina a necessidade de os administradores adiarem a aplicação de patches. Ele aplica patches automaticamente em várias versões do Linux sem tempo de inatividade ou interrupções, garantindo que a infraestrutura crítica não fique exposta a vulnerabilidades enquanto se aguarda uma janela de manutenção.

