Sobre o CVE-2024-0517
A CVE-2024-0517 é uma vulnerabilidade de escrita fora dos limites no motor V8 JavaScript do Google Chrome anterior à versão 120.0.6099.224, que permite a atacantes remotos explorar a corrupção de heap através de uma página HTML criada. A vulnerabilidade foi relatada pela primeira vez por Toan (Suto) Pham da Qrious Secure.
Esta vulnerabilidade surge da confusão de tipos, que ocorre quando uma aplicação aloca ou inicializa um recurso como um ponteiro, objeto ou variável utilizando um tipo, mas mais tarde acede a esse recurso utilizando um tipo que é incompatível com o tipo original (CWE-843). Neste CVE, a confusão de tipos é despoletada durante um processo de alocação de memória chamado folded allocation, que é empregue para otimização de memória pelo Maglev, um compilador de otimização para o motor V8 JavaScript.
Ao explorar a confusão de tipos e escrever códigos de shell arbitrários através do WebAssembly, um atacante pode executar comandos no computador da vítima.
Fases de ataque
Os atacantes podem alojar um sítio Web que contém uma página HTML criada e enganar os utilizadores para que acedam ao mesmo através de e-mails de phishing ou redes sociais. Quando os utilizadores visitam o site utilizando uma versão vulnerável do Google Chrome, o código malicioso incorporado executa comandos arbitrários.
Motor JavaScript V8
Os atacantes podem alojar um sítio Web que contém uma página HTML criada e enganar os utilizadores para que acedam ao mesmo através de e-mails de phishing ou redes sociais. Quando os utilizadores visitam o site utilizando uma versão vulnerável do Google Chrome, o código malicioso incorporado executa comandos arbitrários.
Maglev e afetação dobrada
O Maglev, um compilador de otimização no V8, melhora a execução do código e a atribuição de memória. O Maglev é executado apenas quando o código é executado frequentemente e marcado como "quente", indicando a necessidade de uma execução mais rápida através da compilação em vez de uma interpretação linha a linha mais lenta.
Normalmente, as alocações ocorrem em regiões de memória não contíguas, levando ao uso esparso e ineficiente da memória. Para resolver este problema, o V8 emprega uma técnica chamada alocação dobrada, que aloca múltiplas variáveis de forma contínua e simultânea. O Maglev também optimiza as atribuições utilizando a atribuição dobrada no seu progresso.
Recolha de lixo geracional
Para limpar as regiões de memória não utilizadas, o V8 emprega uma técnica de coleta de lixo geracional (GC), dividindo a memória em dois espaços: a geração jovem e a geração antiga. Além disso, há dois coletores de lixo: o coletor de lixo menor, que é responsável pela limpeza do espaço jovem, e o coletor de lixo maior, que lida com a limpeza do espaço antigo. A geração jovem é a área da memória onde os objetos recém-criados são inicialmente alocados e a geração antiga é uma região da memória onde os objetos de longa duração são armazenados. Os objectos que sobreviveram a vários ciclos menores do GC na geração jovem são eventualmente promovidos para a geração antiga.
Análise de vulnerabilidade
Visão geral
A vulnerabilidade surge quando um objeto é criado a partir de uma classe herdada de uma classe de base sem construtor explicitamente definido (construtor de base por defeito) e outro objeto é subsequentemente criado. Devido à atribuição dobrada, a atribuição do primeiro objeto pode ser seguida pela atribuição do segundo objeto. Se ocorrer um evento como a recolha de lixo entre estas duas atribuições, pode surgir uma vulnerabilidade de confusão de tipos.
Análise da causa raiz
Os Graduate Fellows OPSWAT efectuaram uma análise detalhada do fluxo de trabalho V8 durante o processo de atribuição e determinaram que as seguintes funções são invocadas durante este processo:
Neste processo, foi identificado um problema na função TryBuildFindNonDefaultConstructorOrConstruct: A função BuildAllocateFastObject estende current_raw_allocation_ (um ponteiro para a região de memória alocada para múltiplas variáveis simultaneamente) para construir a instância da classe filha, mas não a limpa definindo-a como nula.
Como resultado, o próximo objeto criado é sempre atribuído imediatamente a seguir à memória apontada por current_raw_allocation_, independentemente de quaisquer eventos anteriores à segunda atribuição.
Se o GC for invocado, a região de memória próxima da memória adjacente a current_raw_allocation_ pode ser atribuída a outros objectos. Isto pode levar a uma situação em que, após o GC ser acionado e outro objeto ser criado, dois ponteiros referenciam a mesma região de memória mas têm tipos de dados diferentes, resultando numa vulnerabilidade de confusão de tipos.
Exploração
Para explorar esta vulnerabilidade, os bolseiros de pós-graduação OPSWAT criaram instâncias WebAssembly que continham código de shell e tentaram desencadear confusão de tipos pelo GC para controlar a memória e executar o código de shell:
Confusão de tipos de gatilho
Durante a inicialização, primeiro definimos uma matriz (_arrayObject) contendo objectos vazios. Em seguida, construímos uma instância da classe filha, bem como um coletor de lixo de gatilho. Finalmente, definimos outro array com um número de ponto flutuante, chamado _arrayDouble.
Essas construções devem ser repetidas para que o código seja executado várias vezes, fazendo com que o V8 o marque como "quente" e acione o compilador Maglev. Conseguimos isso invocando o construtor da classe filha dentro de um loop, como segue:
A confusão de tipos será desencadeada após a inicialização repetida destes objectos num ciclo.
Criar primitivas de leitura e escrita
Depois de desencadear com sucesso a confusão de tipos, a execução do código de shell requer a leitura da memória e a substituição da memória num endereço controlado. Para isso, criámos primitivas de leitura e escrita. As primitivas de exploração tirarão partido dos metadados nos objectos para nos darem regiões de memória de leitura/escrita arbitrárias e usá-las para executar código arbitrário.
As primitivas de leitura e escrita nesta etapa permitir-nos-ão controlar o ponteiro da tabela de saltos da instância do WebAssembly na etapa seguinte.
Criar instâncias do WebAssembly
Em seguida, criámos duas instâncias do WebAssembly: uma para armazenar o código da shell e outra para o ativar. Para evitar escrever diretamente o código shell na memória da instância do WebAssembly através de primitivas de leitura e escrita, definimos alguns valores constantes de ponto flutuante na instância do WebAssembly.
Ponteiro da tabela de saltos de controlo da instância do WebAssembly
Usando primitivas de leitura e escrita, ajustamos o ponteiro da tabela de saltos da segunda instância do WebAssembly para saltar alguns bytes do código compilado de constantes na primeira instância do WebAssembly, de modo a que as constantes de vírgula flutuante sejam interpretadas como o nosso shellcode pretendido:
Executar a instância do WebAssembly para executar o código de shell
Finalmente, depois de desencadear a confusão de tipos e usar primitivas de leitura/escrita para controlar os ponteiros da tabela de saltos das instâncias do WebAssembly, invocámos a função exportada da segunda instância do WebAssembly, que faz com que o código da shell na primeira instância do WebAssembly seja executado.
O shellcode que estamos a utilizar foi concebido para terminar todos os processos numa máquina Linux, como através do seguinte comando:
O código de montagem para executar este comando, convertido a partir dos números de vírgula flutuante, será o seguinte:
Simular a vulnerabilidade de segurança
Para simular esta exploração num cenário real, os bolseiros OPSWAT criaram uma página HTML maliciosamente elaborada.
É enviado à vítima um e-mail de phishing com uma hiperligação para o domínio que aloja esta página HTML criada.
Se a vítima aceder à ligação utilizando a versão vulnerável do Google Chrome, o shellcode é executado, fazendo com que todos os processos sejam terminados. Como resultado, o utilizador é desconectado, como se mostra abaixo:
Remediação
MetaDefender Endpoint™ foi utilizado para mitigar proactivamente este CVE, aproveitando a sua capacidade de "Aplicação Vulnerável". A solução identifica e exibe efetivamente todos os CVEs associados aos aplicativos do Google Chrome no ambiente do endpoint. Para neutralizar a ameaça, os utilizadores podem desinstalar imediatamente o Chrome ou aplicar o patch de segurança mais recente. Ao implementar qualquer uma das contramedidas, o CVE é totalmente contido, reduzindo significativamente o risco de um ataque informático bem sucedido no ponto final.
Segurança de Endpoint de nível seguinte
Descubra porque é que as organizações, instituições e entidades de todo o mundo confiam no MetaDefender Endpoint para proteger os terminais críticos. Fale com um especialista hoje para saber mais e veja por si mesmo com uma demonstração gratuita.
Referências
https://nvd.nist.gov/vuln/detail/CVE-2024-0517
https://cwe.mitre.org/data/definitions/843.html
https://blog.exodusintel.com/2024/01/19/google-chrome-v8-cve-2024-0517-out-of-bounds-write-code-execution/
https://jhalon.github.io/chrome-browser-exploitation-1/
https://whenderson.dev/blog/webgl-garbage-collection/
https://v8.dev/
https://github.com/Uniguri/CVE-nday/tree/master/Chrome/V8/CVE-2024-0517