Vulnerabilidade raiz no kernel Linux e negação de serviço no systemd

Pesquisadores de segurança da Qualys revelaram detalhes de duas vulnerabilidades que afetam o kernel Linux e o gerenciador de sistema systemd. Uma vulnerabilidade no kernel (CVE-2021-33909) permite que um usuário local consiga a execução de código com direitos de root por meio da manipulação de diretórios altamente aninhados.

O perigo da vulnerabilidade é agravado pelo fato de que os pesquisadores foram capazes de preparar exploits funcionais que funcionam no Ubuntu 20.04/20.10/21.04, Debian 11 e Fedora 34 na configuração padrão. Nota-se que outras distribuições não foram testadas, mas teoricamente também são suscetíveis ao problema e podem ser atacadas. O código completo dos exploits está prometido para ser publicado depois que o problema for eliminado em todos os lugares, mas por enquanto apenas um protótipo de funcionalidade limitada está disponível, causando o travamento do sistema. O problema está presente desde julho de 2014 e afeta versões do kernel a partir do 3.16. A correção da vulnerabilidade foi coordenada com a comunidade e aceita no kernel em 19 de julho. As principais distribuições já geraram atualizações para seus pacotes de kernel (Debian, Ubuntu, Fedora, RHEL, SUSE, Arch).

A vulnerabilidade é causada pela falha na verificação do resultado de uma conversão de size_t para int antes de executar operações no código seq_file, que cria arquivos a partir de uma sequência de registros. A falha na verificação pode resultar em gravações fora dos limites no buffer ao criar, montar e excluir uma estrutura de diretório muito aninhada (tamanho do caminho maior que 1 GB). Como resultado, um invasor pode obter uma string de 10 bytes "//deleted" escrita em um deslocamento de "-2 GB - 10 bytes" apontando para a área imediatamente anterior ao buffer alocado.

A exploração preparada requer 5 GB de memória e 1 milhão de inodes livres para funcionar. A exploração funciona chamando mkdir() para criar uma hierarquia de cerca de um milhão de subdiretórios para atingir um tamanho de caminho de arquivo superior a 1 GB. Este diretório é montado via bind-mount em um namespace de usuário separado, após o qual a função rmdir() é executada para removê-lo. Paralelamente, é criada uma thread que carrega um pequeno programa eBPF, que é bloqueado na etapa após a verificação do pseudocódigo eBPF, mas antes de sua compilação JIT.

No namespace de ID de usuário sem privilégios, o arquivo /proc/self/mountinfo é aberto e o nome do caminho longo do diretório montado em bind é lido, resultando na gravação da string "//deleted" na área antes do início do buffer. A posição de escrita da linha é escolhida de forma que ela sobrescreva a instrução do programa eBPF já testado, mas ainda não compilado.

Em seguida, no nível do programa eBPF, a escrita fora do buffer não controlada é transformada em capacidade controlada de ler e escrever em outras estruturas do kernel através da manipulação das estruturas btf e map_push_elem. Como resultado, a exploração determina a localização do buffer modprobe_path[] na memória do kernel e sobrescreve o caminho “/sbin/modprobe” nele, o que permite iniciar o lançamento de qualquer arquivo executável com direitos de root no caso de um chamada request_module(), que é executada, por exemplo, ao criar o soquete netlink.

Os pesquisadores fornecem diversas soluções alternativas que são eficazes apenas para uma exploração específica, mas não eliminam o problema em si. Recomenda-se definir "/proc/sys/kernel/unprivileged_userns_clone" como 0 para desabilitar a montagem de diretórios em um namespace de ID de usuário separado e "/proc/sys/kernel/unprivileged_bpf_disabled" como 1 para desabilitar o carregamento de programas eBPF no kernel.

Vale ressaltar que ao analisar um ataque alternativo envolvendo o uso do mecanismo FUSE em vez do bind-mound para montar um grande diretório, os pesquisadores se depararam com outra vulnerabilidade (CVE-2021-33910) afetando o gerenciador do sistema systemd. Descobriu-se que ao tentar montar um diretório com tamanho de caminho superior a 8 MB via FUSE, o processo de inicialização do controle (PID1) fica sem memória de pilha e trava, o que coloca o sistema em estado de “pânico”.

O problema é que o systemd rastreia e analisa o conteúdo de /proc/self/mountinfo e processa cada ponto de montagem na função unit_name_path_escape(), que executa uma operação strdupa() que coloca os dados na pilha em vez de na memória alocada dinamicamente. . Como o tamanho máximo da pilha é limitado por RLIMIT_STACK, o processamento de um caminho muito grande para o ponto de montagem faz com que o processo PID1 trave e pare o sistema. Para um ataque, você pode usar o módulo FUSE mais simples em combinação com o uso de um diretório altamente aninhado como ponto de montagem, cujo tamanho do caminho excede 8 MB.

O problema vem aparecendo desde o systemd 220 (abril de 2015), já foi corrigido no repositório principal do systemd e corrigido nas distribuições (Debian, Ubuntu, Fedora, RHEL, SUSE, Arch). Notavelmente, na versão 248 do systemd, a exploração não funciona devido a um bug no código do systemd que causa falha no processamento de /proc/self/mountinfo. Também é interessante que em 2018 surgiu uma situação semelhante e, ao tentar escrever uma exploração para a vulnerabilidade CVE-2018-14634 no kernel Linux, os pesquisadores da Qualys encontraram três vulnerabilidades críticas no systemd.

Fonte: opennet.ru

Adicionar um comentário