iOS Exploiting
Uso físico após a liberação
Este é um resumo do post de https://alfiecg.uk/2024/09/24/Kernel-exploit.html, além disso, mais informações sobre a exploração usando esta técnica podem ser encontradas em https://github.com/felix-pb/kfd
Gerenciamento de memória no XNU
O espaço de endereços de memória virtual para processos de usuário no iOS varia de 0x0 a 0x8000000000. No entanto, esses endereços não mapeiam diretamente para a memória física. Em vez disso, o kernel usa tabelas de páginas para traduzir endereços virtuais em endereços físicos reais.
Níveis de Tabelas de Páginas no iOS
As tabelas de páginas são organizadas hierarquicamente em três níveis:
Tabela de Páginas L1 (Nível 1):
Cada entrada aqui representa uma grande faixa de memória virtual.
Cobre 0x1000000000 bytes (ou 256 GB) de memória virtual.
Tabela de Páginas L2 (Nível 2):
Uma entrada aqui representa uma região menor de memória virtual, especificamente 0x2000000 bytes (32 MB).
Uma entrada L1 pode apontar para uma tabela L2 se não conseguir mapear toda a região sozinha.
Tabela de Páginas L3 (Nível 3):
Este é o nível mais fino, onde cada entrada mapeia uma única página de memória de 4 KB.
Uma entrada L2 pode apontar para uma tabela L3 se um controle mais granular for necessário.
Mapeamento de Memória Virtual para Física
Mapeamento Direto (Mapeamento de Bloco):
Algumas entradas em uma tabela de páginas mapeiam um intervalo de endereços virtuais para um intervalo contíguo de endereços físicos (como um atalho).
Ponteiro para Tabela de Páginas Filha:
Se um controle mais fino for necessário, uma entrada em um nível (por exemplo, L1) pode apontar para uma tabela de páginas filha no próximo nível (por exemplo, L2).
Exemplo: Mapeando um Endereço Virtual
Vamos supor que você tente acessar o endereço virtual 0x1000000000:
Tabela L1:
O kernel verifica a entrada da tabela de páginas L1 correspondente a este endereço virtual. Se tiver um ponteiro para uma tabela de páginas L2, ele vai para essa tabela L2.
Tabela L2:
O kernel verifica a tabela de páginas L2 para um mapeamento mais detalhado. Se esta entrada apontar para uma tabela de páginas L3, ele prossegue para lá.
Tabela L3:
O kernel consulta a entrada final L3, que aponta para o endereço físico da página de memória real.
Exemplo de Mapeamento de Endereço
Se você escrever o endereço físico 0x800004000 no primeiro índice da tabela L2, então:
Endereços virtuais de 0x1000000000 a 0x1002000000 mapeiam para endereços físicos de 0x800004000 a 0x802004000.
Isso é um mapeamento de bloco no nível L2.
Alternativamente, se a entrada L2 apontar para uma tabela L3:
Cada página de 4 KB na faixa de endereços virtuais 0x1000000000 -> 0x1002000000 seria mapeada por entradas individuais na tabela L3.
Uso físico após a liberação
Um uso físico após a liberação (UAF) ocorre quando:
Um processo aloca alguma memória como legível e gravável.
As tabelas de páginas são atualizadas para mapear essa memória para um endereço físico específico que o processo pode acessar.
O processo desaloca (libera) a memória.
No entanto, devido a um bug, o kernel esquece de remover o mapeamento das tabelas de páginas, mesmo que marque a memória física correspondente como livre.
O kernel pode então realocar essa memória física "liberada" para outros fins, como dados do kernel.
Como o mapeamento não foi removido, o processo ainda pode ler e gravar nessa memória física.
Isso significa que o processo pode acessar páginas de memória do kernel, que podem conter dados ou estruturas sensíveis, potencialmente permitindo que um atacante manipule a memória do kernel.
Estratégia de Exploração: Heap Spray
Como o atacante não pode controlar quais páginas específicas do kernel serão alocadas para a memória liberada, ele usa uma técnica chamada heap spray:
O atacante cria um grande número de objetos IOSurface na memória do kernel.
Cada objeto IOSurface contém um valor mágico em um de seus campos, facilitando a identificação.
Eles escaneiam as páginas liberadas para ver se algum desses objetos IOSurface caiu em uma página liberada.
Quando encontram um objeto IOSurface em uma página liberada, podem usá-lo para ler e gravar na memória do kernel.
Mais informações sobre isso em https://github.com/felix-pb/kfd/tree/main/writeups
Processo Passo a Passo do Heap Spray
Spray de Objetos IOSurface: O atacante cria muitos objetos IOSurface com um identificador especial ("valor mágico").
Escanear Páginas Liberadas: Eles verificam se algum dos objetos foi alocado em uma página liberada.
Ler/Gravar na Memória do Kernel: Manipulando campos no objeto IOSurface, eles ganham a capacidade de realizar leituras e gravações arbitrárias na memória do kernel. Isso permite que eles:
Use um campo para ler qualquer valor de 32 bits na memória do kernel.
Use outro campo para gravar valores de 64 bits, alcançando um primitivo de leitura/gravação do kernel estável.
Gere objetos IOSurface com o valor mágico IOSURFACE_MAGIC para buscar mais tarde:
Procure por IOSurface
objetos em uma página física liberada:
Conseguindo Leitura/Escrita no Kernel com IOSurface
Após conseguir controle sobre um objeto IOSurface na memória do kernel (mapeado para uma página física liberada acessível a partir do espaço do usuário), podemos usá-lo para operações arbitrárias de leitura e escrita no kernel.
Campos Chave em IOSurface
O objeto IOSurface possui dois campos cruciais:
Ponteiro de Contagem de Uso: Permite uma leitura de 32 bits.
Ponteiro de Timestamp Indexado: Permite uma escrita de 64 bits.
Ao sobrescrever esses ponteiros, redirecionamos eles para endereços arbitrários na memória do kernel, habilitando capacidades de leitura/escrita.
Leitura de 32 Bits no Kernel
Para realizar uma leitura:
Sobrescreva o ponteiro de contagem de uso para apontar para o endereço alvo menos um deslocamento de 0x14 bytes.
Use o método
get_use_count
para ler o valor naquele endereço.
64-Bit Kernel Write
Para realizar uma escrita:
Sobrescreva o ponteiro de timestamp indexado para o endereço alvo.
Use o método
set_indexed_timestamp
para escrever um valor de 64 bits.
Recapitulação do Fluxo de Exploit
Acionar Uso-Físico Após Liberação: Páginas liberadas estão disponíveis para reutilização.
Spray Objetos IOSurface: Alocar muitos objetos IOSurface com um "valor mágico" único na memória do kernel.
Identificar IOSurface Acessível: Localizar um IOSurface em uma página liberada que você controla.
Abusar do Uso-Físico Após Liberação: Modificar ponteiros no objeto IOSurface para habilitar leitura/escrita arbitrária no kernel via métodos IOSurface.
Com esses primitivos, o exploit fornece leituras de 32 bits e escritas de 64 bits controladas na memória do kernel. Passos adicionais de jailbreak podem envolver primitivos de leitura/escrita mais estáveis, que podem exigir a superação de proteções adicionais (por exemplo, PPL em dispositivos arm64e mais novos).
Last updated