
kfd, abreviatura de kernel file descriptor, es un proyecto para leer y escribir memoria del kernel en dispositivos Apple.
Aviso rápido: no tengo intención de añadir offsets para otros dispositivos y versiones de iOS.
kfd, abreviatura de kernel file descriptor, es un proyecto para leer y escribir memoria del kernel en dispositivos Apple. Aprovecha varias vulnerabilidades que pueden explotarse para obtener PTEs colgantes, a lo que llamaremos primitiva PUAF, abreviatura de "physical use-after-free". Luego, reasigna ciertos objetos del kernel dentro de esas páginas físicas y los manipula directamente desde el espacio de usuario a través de los PTEs colgantes para lograr una primitiva KRKW, abreviatura de "kernel read/write". El código del exploit está completamente contenido en una librería, libkfd, pero el proyecto también contiene simples envoltorios ejecutables para iOS y macOS. La API pública de libkfd es bastante pequeña e intuitiva:
enum puaf_method {
puaf_physpuppet,
puaf_smith,
puaf_landa,
};
enum kread_method {
kread_kqueue_workloop_ctl,
kread_sem_open,
};
enum kwrite_method {
kwrite_dup,
kwrite_sem_open,
};
u64 kopen(u64 puaf_pages, u64 puaf_method, u64 kread_method, u64 kwrite_method);
void kread(u64 kfd, u64 kaddr, void* uaddr, u64 size);
void kwrite(u64 kfd, void* uaddr, u64 kaddr, u64 size);
void kclose(u64 kfd);
kopen() abre conceptualmente un "descriptor de archivo del kernel". Acepta los siguientes 4 argumentos:
puaf_pages: El número objetivo de páginas físicas con PTEs colgantes.puaf_method: El método utilizado para obtener la primitiva PUAF, con las siguientes opciones:
puaf_physpuppet:
puaf_smith:
puaf_landa:
kread_method: El método utilizado para obtener la primitiva kread() inicial.kwrite_method: El método utilizado para obtener la primitiva inicial.Si el exploit tiene éxito, kopen() devuelve un descriptor de archivo opaco de 64 bits. En la
práctica, esto es solo un puntero de espacio de usuario a una estructura necesaria para libkfd. Sin
embargo, dado que no se debe acceder a esa estructura desde fuera de la librería, se devuelve como
un entero opaco. Si el exploit no tiene éxito, la librería imprimirá un mensaje de error, dormirá
durante 30 segundos y luego saldrá con un código de estado 1. Duerme durante 30 segundos porque el
kernel podría entrar en pánico al salir para ciertos métodos PUAF que requieren una limpieza
posterior a KRKW (p. ej. puaf_smith).
kread() y kwrite() son el equivalente en espacio de usuario de copyout() y copyin(),
respectivamente. Ten en cuenta que las opciones para kread_method y kwrite_method se describen
en un análisis aparte. Además, las primitivas iniciales otorgadas
por esos métodos pueden usarse para construir una mejor primitiva KRKW. Finalmente, kclose()
simplemente cierra el descriptor de archivo del kernel. Todos toman el entero opaco devuelto por
kopen() como su primer argumento.
En Xcode, abre la carpeta raíz del proyecto y conecta tu dispositivo iOS.
En una terminal, navega a la carpeta raíz del proyecto.
Opcionalmente, para aumentar los límites globales y por proceso de descriptores de archivo, lo que
mejorará la tasa de éxito especialmente en múltiples ejecuciones consecutivas, introduce el comando
make s y escribe la contraseña de sudo.
make b.make r.make br.Este README presentó una visión general de alto nivel del proyecto kfd. Una vez que se ha logrado una primitiva PUAF, el resto del exploit es genérico. Por lo tanto, he extraído la parte común de los exploits a un análisis dedicado:
Además, he dividido la parte específica de vulnerabilidad de los exploits utilizados para lograr la primitiva PUAF en análisis distintos, listados a continuación en orden cronológico de descubrimiento:
Sin embargo, ten en cuenta que estos análisis han sido escritos para una audiencia que ya está familiarizada con el sistema de memoria virtual de XNU.
kwrite()