
Análise técnica e demonstração de exploração do CVE-2022-32898, uma vulnerabilidade de corrupção de memória do kernel no driver do Apple Neural Engine, com técnicas detalhadas de engenharia reversa e exploração para o kernel iOS.
Nov 23, 2022 • Mohamed GHANNAM (@_simo36)
Estou compartilhando duas outras vulnerabilidades do kernel do iOS acessíveis a partir da sandbox padrão do aplicativo que não exigem que você abra um UserClient:

+16 bugs do kernel que reportei à Apple foram corrigidos no iOS 16/16.1. Farei uma palestra sobre como encadeei alguns bugs para conseguir r/w do kernel no #POC2022 no próximo mês, e o exploit do kernel para iOS 15 será lançado junto com algumas outras vulnerabilidades de alto impacto após a conferência.
Minha característica favorita do IDA 8.0 até agora: importações artificiais de métodos Obj-C

No iOS 15.5 beta 3, a Apple removeu IOMallocAligned(KHEAP_DEFAULT,...) de IOSharedDataQueue/IODataQueue::initWithCapacity() (agora usa kernel_memory_allocate() com a flag KMA_DATA). Era uma técnica elegante para preparar o heap padrão do kernel com dados controlados pelo usuário. RIP

Durante a engenharia reversa do processo pelo qual o Apple Neural Engine carrega um modelo no nível do kernel, identifiquei duas vulnerabilidades interessantes de corrupção de memória no código responsável por processar as características da rede neural em H11ANEIn::ANE_ProgramCreate_gated(). Esse tipo de vulnerabilidade, na minha opinião, é fácil de encontrar ao auditar manualmente o driver do kernel, mas quase impossível de detectar com fuzzers a menos que você construa algo incrivelmente sofisticado.
As funções ZinComputeProgramGetNamesFromMultiPlaneLinear() e ZinComputeProgramGetNamesFromMultiPlaneTiledCompressed() são responsáveis por analisar a entrada e saída do procedimento, ou mais precisamente, o comando LC_THREAD com thread flavor 2 (ane_bind_state) cujo valor binding_type_info é 4 e 5.
Pelo que posso dizer, binding_type_info = 4 significa que a entrada de um procedimento tem mais de um plano, e binding_type_info = 5 significa que a entrada não apenas tem mais de um plano, mas também é comprimida.
A função ZinComputeProgramGetNamesFromMultiPlaneLinear() por exemplo recebe 5 argumentos: um ponteiro para o comando load, um ponteiro para o thread binding, e três argumentos de saída extras. O último argumento de saída planes é um array que conterá planos, ou ponteiros do kernel, cujo conteúdo é controlado pelo usuário, e o último argumento planeCount indicará quantos planos (ou ponteiros do kernel) foram copiados para planes a partir do arquivo model.hwx. A seguir está a definição da função:

Devido à falta de validação de quantos planos um modelo pode fornecer, ponteiros do kernel podem ser escritos fora dos limites do array planes, potencialmente levando a muitos cenários interessantes de corrupção de memória.
O array planes é uma variável na pilha localizada em H11ANEIn::ANE_ProgramCreate_gated(), e ao estourar esta variável (que deve conter múltiplos planos até 4 elementos) com mais de 4 planos, outras variáveis da pilha também podem ser corrompidas, o que pode levar a outros problemas, como type-confusion, já que os ponteiros do kernel sobrescritos estão completamente sob controle do usuário.
Obviamente, estourar o array planes com muitas entradas provavelmente sobrescreveria o stack cookie, bem como o ponteiro do quadro de pilha antigo salvo, resultando em um kernel panic. Felizmente, o número total de planos está inteiramente sob controle do modelo fornecido, então podemos corromper várias variáveis da pilha sem afetar essas áreas sensíveis da pilha.
Outro cenário interessante, e como ilustrado na imagem abaixo, é possível estourar dois objetos do heap: H11ANEProgramBindingInfo (na linha 528) e H11ANEProgramCreateArgsStructOutput (na linha 533).

struct H11ANEProgramBindingInfo
{
struct {
uint32_t field_0;
char names[8][512];
uint32_t field_1004;
char *procedure_name;
} inputs[255], outputs[255];
};
A definição da estrutura de H11ANEProgramCreateArgsStructOutput é mostrada acima, e corrompê-la pode resultar nas seguintes falhas:
"panicString" : "panic(cpu 4 caller 0xfffffe00112e6184): Kernel data abort. at pc 0xfffffe0010a8a48c, lr 0x03effe0011b1b47c (saved state: 0xfffffe6089dca980)
x0: 0x1122334411223344 x1: 0xfffffe3000ecff20 x2: 0x0000000000000040 x3: 0x0000000000000000
x4: 0x0000000000000000 x5: 0x0000000000000000 x6: 0x00000000000000e8 x7: 0x0000000000000830
x8: 0xfffffe608949c000 x9: 0xfffffe24cec0d1b0 x10: 0xfffffe24cd7d4010 x11: 0xfffffe1667fa93e0
x12: 0x0000000000000001 x13: 0x0000000000000858 x14: 0xfffffe3000ed0760 x15: 0x00292a20736d6172
x16: 0x5bd9fe0010a8a470 x17: 0xfffffe0013ad55d8 x18: 0x0000000000000000 x19: 0x0000000000000000
x20: 0x0000000000000001 x21: 0xfffffe1b33ee3860 x22: 0xfffffe299a621a00 x23: 0xfffffe2999c72208
x24: 0xfffffe3000ec0000 x25: 0x00000000e00002d1 x26: 0xfffffe608949c000 x27: 0xfffffe60895a2054
x28: 0xfffffe6089dcb850 fp: 0xfffffe6089dcacd0 lr: 0x03effe0011b1b47c sp: 0xfffffe6089dcacd0
pc: 0xfffffe0010a8a48c cpsr: 0x00401208 esr: 0x96000004 far: 0x1122334411223344
O que torna essas vulnerabilidades interessantes é que não exige que você interaja diretamente com o kernel, em outras palavras, não há necessidade de abrir uma conexão UserClient, você simplesmente precisa compilar (ou criar) um modelo malicioso e deixar o aned carregá-lo em seu nome.
Como você deve saber, para carregar qualquer modelo via aned, o modelo deve ser compilado pelo serviço de sistema ANECompilerService ou assinado pela Apple. Em outras palavras, o aplicativo deve fornecer um diretório .mlmodelc para o aned, que então solicitará ao ANECompilerService que o compile para model.hwx usando duas estruturas chamadas Espresso e ANECompiler. Se você não sabe do que estou falando, sinta-se à vontade para dar uma olhada nos slides do #POC2022 aqui onde dei uma visão geral básica de como o aned funciona. Além disso, você pode obter mais detalhes sobre o processo de compilação na excelente palestra do BlackHat de Wish Wu sobre sua pesquisa no ANE, bem como sua ótima ferramenta que imita exatamente o que o ANECompilerService faz.