
desc_race exploit para iOS 15.0 - 15.1.1 (com primitivas estáveis de leitura/escrita do kernel) (CVE-2021-30955)
"desc_race" (CVE-2021-30955) exploit para iOS 15.0 - 15.1.1 (com primitivas estáveis de leitura/escrita no kernel)
Aumente a capacidade do array de IOSurfaceClient para 0x2000, o objetivo é escrever um ponteiro cujo conteúdo seja totalmente controlado e depois usar as interfaces de IOSurfaceRootUserClient para alcançar leitura/escrita no kernel. O tamanho do array é 0x2000 * 8 bytes, portanto reside no mapa grande de KHEAP_KEXT, que é o mesmo que KHEAP_DEFAULT.
Em seguida, aloque um buffer de kernel de 0x4000 bytes usando um kmsg assistente com um descritor ool de 0x4000 bytes que será sobrescrito por trás. E então acione o bug com a mensagem alocada, chamada de kmsg de double copyin, colocada logo atrás do buffer de kernel assistente. E esta mensagem contém um descritor de ports ool cuja contagem é 0x2000, portanto ficará bem próximo do array de IOSurfaceClient.
Então você deve receber a mensagem assistente. Se a corrida for bem-sucedida, o descritor de ports ool será revelado e poderemos localizar o endereço do array de IOSurfaceClient.
Em seguida, aloque novamente um buffer de kernel de 0x4000 bytes, que ocupará o buffer de kernel mencionado anteriormente. Desta vez, construo um cabeçalho kmsg falso com corpo adequado. Então destruo o kmsg de double copyin, e o kernel começará com nosso cabeçalho falso. Uso um mach_msg_ool_descriotpor_t falso e aciono
vm_copy_discard() com uma cópia totalmente controlada. Durante a destruição da cópia, as linhas mais valiosas estão em _vm_map_entry_unlink_ll:
1
2
3
4
5
6
#define _vm_map_entry_unlink_ll(hdr, entry) \
MACRO_BEGIN \
(hdr)->nentries--; \
(entry)->vme_next->vme_prev = (entry)->vme_prev; \
(entry)->vme_prev->vme_next = (entry)->vme_next; \
MACRO_END
O entry está sob nosso controle, o que nos dá uma primitiva perfeita de leitura/escrita. Uso isso para escrever um ponteiro controlado no array de IOSurfaceClient e, em seguida, alcanço leitura/escrita no kernel combinada com as interfaces de IOSurfaceRootUserClient.
Li o post de bazad "One byte to rule them all" várias e várias vezes durante o desenvolvimento deste exploit, e usei a mesma técnica, falsificando vm_copy_t, em seu exploit. Mas há alguns pontos que diferem.
O XNU assina a mensagem e não podemos mais receber um kmsg corrompido.
No procedimento de destruição, defino mapping_in_progress do vm_object para fazer o kernel girar, evitando assim um panic devido à verificação de zona.
Muito obrigado a bazad por seu excelente post, e a WangTielei por me informar que as interfaces de IOSurfaceClient agora são inválidas para a primitiva de leitura/escrita, e a pedantcoder por sua gentileza.