Memory Tagging Extension (MTE)

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras maneiras de apoiar o HackTricks:

Informações Básicas

A Extensão de Marcação de Memória (MTE) é projetada para aprimorar a confiabilidade e segurança do software ao detectar e prevenir erros relacionados à memória, como estouros de buffer e vulnerabilidades de uso após liberação. O MTE, como parte da arquitetura ARM, fornece um mecanismo para anexar uma pequena tag a cada alocação de memória e uma tag correspondente a cada ponteiro que referencia essa memória. Essa abordagem permite a detecção de acessos ilegais à memória em tempo de execução, reduzindo significativamente o risco de explorar tais vulnerabilidades para executar código arbitrário.

Como a Extensão de Marcação de Memória Funciona

O MTE opera dividindo a memória em blocos pequenos de tamanho fixo, com cada bloco atribuído a uma tag, geralmente de alguns bits de tamanho.

Quando um ponteiro é criado para apontar para essa memória, ele recebe a mesma tag. Essa tag é armazenada nos bits não utilizados de um ponteiro de memória, vinculando efetivamente o ponteiro ao seu bloco de memória correspondente.

Quando um programa acessa a memória por meio de um ponteiro, o hardware MTE verifica se a tag do ponteiro corresponde à tag do bloco de memória. Se as tags não corresponderem, isso indica um acesso ilegal à memória.

Tags de Ponteiro MTE

As tags dentro de um ponteiro são armazenadas em 4 bits dentro do byte superior.

Portanto, isso permite até 16 valores de tag diferentes.

Tags de Memória MTE

Cada 16B de memória física tem uma tag de memória correspondente.

As tags de memória são armazenadas em uma região de RAM dedicada (não acessível para uso normal). Tendo tags de 4 bits para cada 16B de tags de memória, até 3% da RAM.

A ARM introduz as seguintes instruções para manipular essas tags na memória RAM dedicada:

STG [<Xn/SP>], #<simm>    Store Allocation (memory) Tag
LDG <Xt>, [<Xn/SP>]       Load Allocatoin (memory) Tag
IRG <Xd/SP>, <Xn/SP>      Insert Random [pointer] Tag
...

Modos de Verificação

Síncrono

A CPU verifica as tags durante a execução da instrução, se houver uma diferença, ela gera uma exceção. Este é o mais lento e mais seguro.

Assíncrono

A CPU verifica as tags de forma assíncrona, e quando encontra uma diferença, define um bit de exceção em um dos registradores do sistema. É mais rápido que o anterior, mas é incapaz de apontar a instrução exata que causou a diferença e não gera a exceção imediatamente, dando tempo ao atacante para concluir seu ataque.

Misto

???

Exemplos de Implementação e Detecção

Chamado de KASAN baseado em Tags de Hardware, KASAN baseado em MTE ou MTE no kernel. Os alocadores do kernel (como kmalloc) irão chamar este módulo que irá preparar a tag a ser usada (aleatoriamente), anexá-la ao espaço do kernel alocado e ao ponteiro retornado.

Observe que ele irá marcar apenas grânulos de memória suficientes (16B cada) para o tamanho solicitado. Portanto, se o tamanho solicitado foi 35 e um bloco de 60B foi fornecido, ele marcará os primeiros 16*3 = 48B com esta tag e o restante será marcado com uma chamada tag inválida (0xE).

A tag 0xF é o combinar todos os ponteiros. Uma memória com este ponteiro permite qualquer tag ser usada para acessar sua memória (sem diferenças). Isso poderia impedir o MET de detectar um ataque se essa tag estiver sendo usada na memória atacada.

Portanto, existem apenas 14 valores que podem ser usados para gerar tags, pois 0xE e 0xF são reservados, dando uma probabilidade de reutilização de tags de 1/17 -> cerca de 7%.

Se o kernel acessar o grânulo de tag inválida, a diferença será detectada. Se acessar outra localização de memória, se a memória tiver uma tag diferente (ou a tag inválida), a diferença será detectada. Se o atacante tiver sorte e a memória estiver usando a mesma tag, não será detectado. As chances são de cerca de 7%.

Outro bug ocorre no último grânulo da memória alocada. Se a aplicação solicitou 35B, foi dado o grânulo de 32 a 48. Portanto, os bytes de 36 a 47 estão usando a mesma tag mas não foram solicitados. Se o atacante acessar esses bytes extras, isso não será detectado.

Quando o kfree() é executado, a memória é retageada com a tag de memória inválida, então em um uso após liberação, quando a memória é acessada novamente, a diferença é detectada.

No entanto, em um uso após liberação, se o mesmo bloco for realocado novamente com a MESMA tag como anteriormente, um atacante poderá usar esse acesso e isso não será detectado (cerca de 7% de chance).

Além disso, apenas slab e page_alloc usam memória marcada, mas no futuro isso também será usado em vmalloc, stack e globals (no momento do vídeo, esses ainda podem ser explorados).

Quando uma diferença é detectada, o kernel irá entrar em pânico para evitar futuras explorações e tentativas do exploit (MTE não tem falsos positivos).

Referências

Last updated