
desc_race exploit para iOS 15.0 - 15.1.1 (con primitivas estables de lectura/escritura del kernel) (CVE-2021-30955)
"desc_race" (CVE-2021-30955) exploit para iOS 15.0 - 15.1.1 (con primitivas estables de lectura/escritura del kernel)
Aumentar la capacidad del array de IOSurfaceClient a 0x2000, el objetivo es escribir un puntero cuyo contenido esté totalmente controlado y luego usar las interfaces de IOSurfaceRootUserClient para lograr lectura/escritura del kernel. El tamaño del array es de 0x2000 * 8 bytes, por lo que reside en el mapa grande de KHEAP_KEXT, que es el mismo que KHEAP_DEFAULT.
Luego asignar un búfer de kernel de 0x4000 bytes usando un kmsg auxiliar con un descriptor ool de 0x4000 bytes que será sobrescrito desde atrás. Y luego disparar el bug con el mensaje asignado, llamado kmsg de doble copyin, colocado justo detrás del búfer de kernel auxiliar. Y este mensaje contiene un descriptor de puertos ool cuyo recuento es 0x2000, por lo que estará bastante cerca del array de IOSurfaceClient.
Luego deberías recibir el mensaje auxiliar. Si la carrera tiene éxito, el descriptor de puertos ool será revelado y podremos localizar la dirección del array de IOSurfaceClient.
Luego asignar nuevamente un búfer de kernel de 0x4000 bytes, esto ocupará el búfer de kernel mencionado anteriormente. Esta vez construyo una cabecera kmsg falsa con el cuerpo adecuado. Luego destruyo el kmsg de doble copyin, el kernel comenzará con nuestra cabecera falsa. Uso un mach_msg_ool_descriotpor_t falso y disparo
vm_copy_discard() con una copia totalmente controlada. Durante la destrucción de la copia, las líneas más valiosas están en _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
El entry está bajo nuestro control, esto nos da una primitiva perfecta de lectura/escritura. Uso esto para escribir un puntero controlado en el array de IOSurfaceClient, y luego logro lectura/escritura del kernel combinado con las interfaces de IOSurfaceRootUserClient.
He leído la publicación de bazad "One byte to rule them all" una y otra vez durante el desarrollo de este exploit, y usé la misma técnica, falsificar vm_copy_t, en su exploit. Pero hay algunos puntos que difieren.
XNU firma el mensaje y ya no podemos recibir un kmsg corrupto.
En el procedimiento de destrucción, configuro mapping_in_progress del vm_object para que el kernel gire y así no entre en pánico debido a la verificación de zona.
Muchas gracias a bazad por su gran publicación, y a WangTielei por hacerme saber que las interfaces de IOSurfaceClient ahora son inválidas para la primitiva de lectura/escritura, y a pedantcoder por su amabilidad.