Vulnerabilidade root no núcleo do Linux e negação de serviço no systemd

Pesquisadores de segurança da Qualys revelaram os detalhes de duas vulnerabilidades que afetam o núcleo Linux e o gerenciador de sistema systemd. A vulnerabilidade no núcleo (CVE-2021-33909) permite que um usuário local consiga executar código com privilégios de root através da manipulação de diretórios com grande profundidade.

O perigo da vulnerabilidade é agravado pelo fato de que os pesquisadores conseguiram desenvolver exploits funcionais, que operam em Ubuntu 20.04/20.10/21.04, Debian 11 e Fedora 34 na configuração padrão. Observa-se que outras distribuições não foram testadas, mas teoricamente também estão suscetíveis ao problema e podem ser atacadas. O código completo dos exploits promete ser publicado após a resolução generalizada da questão, enquanto isso, apenas um protótipo funcional limitado, que causa a falha do sistema, está disponível. O problema existe desde julho de 2014 e afeta versões do núcleo a partir da 3.16. A correção da vulnerabilidade foi coordenada com a comunidade e foi aceita no núcleo em 19 de julho. As principais distribuições já formaram atualizações de pacotes com o núcleo (Debian, Ubuntu, Fedora, RHEL, SUSE, Arch).

A vulnerabilidade é causada pela ausência de verificação do resultado da conversão de tipo size_t para int antes de realizar operações no código seq_file, que cria arquivos a partir de sequências de registros. A falta de verificação pode levar à gravação fora dos limites do buffer ao criar, montar e excluir estruturas de diretórios com um nível de profundidade muito grande (tamanho do caminho superior a 1 GB). Como resultado, um invasor pode conseguir gravar uma string de 10 bytes "//deleted" com um deslocamento "- 2 GB - 10 bytes", indicando uma área imediatamente anterior ao buffer alocado.

O exploit preparado requer 5 GB de memória e 1 milhão de inodes livres para funcionar. A operação do exploit consiste em criar, através da chamada mkdir(), uma hierarquia de cerca de um milhão de diretórios aninhados para alcançar um tamanho de caminho de arquivo superior a 1 GB. Este diretório é montado por meio de um bind-mount em um espaço de nomes de identificadores de usuários (user namespace) separado, após o que a função rmdir() é chamada para sua exclusão. Paralelamente, um thread é criado que carrega um pequeno programa eBPF, que é bloqueado na fase após a verificação do pseudocódigo eBPF, mas antes de sua compilação JIT.

No espaço de nomes não privilegiado dos identificadores de usuários, o arquivo /proc/self/mountinfo é aberto e a leitura do longo caminho do diretório, montado através de bind-mount, começa, o que leva à escrita da string "//deleted" na área antes do início do buffer. A posição para escrever a string é escolhida de tal forma que sobreescreve a instrução em um programa eBPF já verificado, mas ainda não compilado.

Em seguida, no nível do programa eBPF, a gravação fora do buffer incontrolada é transformada em uma capacidade gerenciada de leitura e escrita em outras estruturas do núcleo através da manipulação das estruturas btf e map_push_elem. Como resultado, o exploit determina a localização do buffer modprobe_path[] na memória do núcleo e sobrescreve nele o caminho "/sbin/modprobe", permitindo iniciar a execução de qualquer arquivo executável com privilégios de root no caso de uma chamada request_module() ser realizada, que ocorre, por exemplo, ao criar um socket netlink.

Os pesquisadores apresentam várias técnicas de contorno de proteção que são eficazes apenas para o exploit específico, mas não resolvem o problema em si. Recomenda-se configurar o parâmetro "/proc/sys/kernel/unprivileged_userns_clone" para 0 para proibir a montagem de diretórios em um espaço de nomes de identificadores de usuários separado, assim como "proc/sys/kernel/unprivileged_bpf_disabled" para 1 para proibir o carregamento de programas eBPF no núcleo.

Notavelmente, ao examinar uma alternativa de ataque relacionada ao uso do mecanismo FUSE em vez de bind-mount para montar um grande diretório, os pesquisadores se depararam com mais uma vulnerabilidade (CVE-2021-33910) que afeta o gerenciador de sistema systemd. Descobriu-se que, ao tentar montar um diretório via FUSE com um tamanho de caminho superior a 8 MB, ocorre esgotamento da memória da pilha no processo de inicialização (PID1) levando ao colapso do sistema e ao estado de "panic".

O problema está relacionado ao fato de que o systemd rastreia e analisa o conteúdo de /proc/self/mountinfo, tratando cada ponto de montagem na função unit_name_path_escape(), onde a operação strdupa() aloca dados na pilha, e não na memória dinamicamente alocada. Como o tamanho máximo da pilha é limitado pelo RLIMIT_STACK, o processamento de um caminho de ponto de montagem muito grande resulta na falha do processo PID1 e na parada do sistema. Um ataque pode explorar um módulo FUSE básico em combinação com o uso de um diretório como ponto de montagem com um alto nível de aninhamento, cujo tamanho do caminho ultrapassa 8 MB.

O problema se manifesta a partir do systemd 220 (abril de 2015), já foi corrigido no repositório principal do systemd e reparado em distribuições (Debian, Ubuntu, Fedora, RHEL, SUSE, Arch). Curiosamente, na versão systemd 248, o exploit não funciona devido a um erro no código do systemd, o que leva a falhas ao processar /proc/self/mountinfo. Também é interessante notar que, em 2018, surgiu uma situação semelhante ao tentar escrever um exploit para a vulnerabilidade CVE-2018-14634 no núcleo do Linux, onde os pesquisadores da Qualys se depararam com três vulnerabilidades críticas no systemd.

Fonte: opennet.ru

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster