Exploração do CVE-2021-21220
Do Comportamento Incorreto do JIT à Execução Remota de Código
Visão Geral
Esta apresentação explica a exploração do CVE-2021-21220, uma vulnerabilidade no mecanismo V8 JavaScript do Google Chrome causada por suposições incorretas do compilador JIT durante a otimização.
A apresentação percorre:
- Como o V8 realiza a compilação Just-In-Time (JIT)
- Como um bug de confusão de tipo com sinal/sem sinal aparece durante a otimização
- Como o bug leva a uma primitiva de array fora dos limites (OOB)
- Como atacantes podem usar o acesso OOB para vazar endereços e obter escritas arbitrárias de memória
- Como o WebAssembly (Wasm) se torna um alvo para execução de código nativo
- Mitigações existentes e defesas modernas de navegadores
Objetivos da Apresentação
O objetivo desta apresentação é demonstrar como um erro sutil de otimização dentro de um mecanismo JavaScript moderno pode escalar para:
- Corrupção de memória
- Primitivas arbitrárias de leitura/escrita
- Modificação de código nativo
- Potencial Execução Remota de Código (RCE)
A cadeia de exploração destaca como os mecanismos JIT equilibram desempenho e segurança, e como suposições incorretas de otimização podem se tornar exploráveis.
Tópicos Abordados
1. Arquitetura do V8
A apresentação apresenta os principais componentes do V8:
Interpretador Ignition
- Executa bytecode JavaScript
- Coleta feedback de tempo de execução
- Armazena informações de tipo em vetores de feedback
Otimizador TurboFan
- Constrói grafos otimizados a partir do feedback de tempo de execução
- Insere suposições especulativas e guardas
- Realiza passes agressivos de otimização
Backend de Código de Máquina
- Emite instruções nativas da CPU
- Produz código de máquina otimizado para funções "quentes"
O diagrama de arquitetura na apresentação ilustra como o JavaScript se move de:
Parsing → Bytecode → Optimization → Execution
2. Por Que o JavaScript é Difícil de Otimizar
O JavaScript é desafiador para execução de alto desempenho porque:
- Variáveis mudam de tipo dinamicamente
- Arrays mudam de estrutura e tipos de elementos
- Operadores como
+ podem ter múltiplos significados
- Verificações em tempo de execução são caras
O V8 usa compilação JIT para otimizar padrões comuns de execução especulando sobre o comportamento em tempo de execução.
3. Causa Raiz do CVE-2021-21220
A vulnerabilidade se origina de uma incompatibilidade de inteiros com sinal vs sem sinal durante a otimização JIT.
Conceitos-chave demonstrados:
Uint32Array
Word32Xor
- Propagação incorreta de tipo
ChangeInt32ToInt64
- Seleção incorreta de instrução de montagem
A exploração abusa do valor:
que define o bit de sinal de um inteiro de 32 bits.
4. Incompatibilidade de Otimização
A vulnerabilidade ocorre porque o TurboFan otimiza:
eliminando-o completamente.
Durante essa otimização:
- A operação XOR desaparece
- As informações de tipo são perdidas
- Valores com sinal passam a ser interpretados como sem sinal
- O comportamento do JIT diverge do comportamento do interpretador
Isso resulta em geração incorreta de código de máquina e valores controlados pelo atacante.
5. Construindo uma Primitiva OOB
A exploração converte o resultado incorreto do JIT em controle sobre o comportamento do array.
A apresentação demonstra:
- Valor inteiro otimizado incorreto
- Conversão na variável de controle
i
- Incompatibilidade entre a execução de aquecimento (warmup) e a de gatilho (trigger)
- Subfluxo de comprimento em
Array.shift()
- Criação de um array capaz de acesso OOB
Conceitos importantes de exploração mostrados:
- Otimização de aquecimento
- Otimização especulativa
- Confusão de tipo
- Corrupção do comprimento do array
6. Acesso Fora dos Limites
Quando o comprimento do array se torna -1, o atacante obtém:
- Leituras fora dos limites
- Escritas fora dos limites
- Acesso a objetos V8 adjacentes no heap
A exploração então demonstra:
- Vazamentos de ponteiros
- Descoberta de endereços de objetos
- Arrays sobrepostos
- Extração de ponteiros V8 brutos
7. Abuso do WebAssembly
A apresentação explica como atacantes podem mirar:
- Páginas de código compilado do WebAssembly
- Memória executável nativa gerada pelo V8
Fluxo de ataque:
- Criar uma função Wasm
- Localizar memória executável
- Sobrescrever o código de máquina compilado
- Reexecutar o Wasm
- Alcançar execução nativa arbitrária
Isso demonstra como um bug do mecanismo JavaScript pode transitar para execução de código no nível do processo.
Defesas e Mitigações
A seção final aborda as defesas modernas dos navegadores:
Ponteiros Compactados
Reduzem a exposição direta de ponteiros e a previsibilidade do heap.
Indireção de Ponteiros
Previnem o acesso direto a endereços brutos de memória.
Sandboxing do Heap
Isolam regiões de memória e reduzem o impacto da exploração.
W^X (Write XOR Execute)
Impedem que páginas sejam graváveis e executáveis simultaneamente.
A apresentação também inclui o diff real do patch do V8 mostrando a correção para o problema de extensão de sinal.
Principais Conclusões
Esta apresentação demonstra como:
- Pequenos erros de otimização podem se tornar vulnerabilidades críticas
- Compiladores JIT aumentam significativamente a complexidade da superfície de ataque
- A especulação em tempo de execução pode introduzir inconsistências perigosas
- O WebAssembly muda o cenário de exploração
- Navegadores modernos exigem múltiplas defesas em camadas
Tecnologias Discutidas
- JavaScript
- Mecanismo Google V8
- TurboFan
- Ignition
- WebAssembly (Wasm)
- Compilação JIT
- Corrupção de Memória
- Acesso Fora dos Limites
- Exploração de Navegadores
Propósito Educacional
Este material é destinado estritamente a:
- Pesquisa em segurança
- Demonstrações educacionais
- Aprendizado sobre o funcionamento interno dos navegadores
- Análise de vulnerabilidades
Não use estas informações contra sistemas que você não possui ou não tem permissão para testar.
Referência