
desc_race Exploit für iOS 15.0 – 15.1.1 (mit stabilen Kernel-r/w-Primitiven) (CVE-2021-30955)
„desc_race“ (CVE-2021-30955) Exploit für iOS 15.0 – 15.1.1 (mit stabilen Kernel-Lese-/Schreib-Primitiven)
Erhöhe die Kapazität des IOSurfaceClient-Arrays auf 0x2000, Ziel ist es, einen Zeiger zu schreiben, dessen Inhalt vollständig kontrolliert wird, und dann IOSurfaceRootUserClient-Schnittstellen zu nutzen, um Kernel-Lese-/Schreibzugriff zu erreichen. Die Größe des Arrays beträgt 0x2000 * 8 Bytes und liegt damit in der großen Map von KHEAP_KEXT, die identisch mit KHEAP_DEFAULT ist.
Allokiere dann einen 0x4000 Bytes großen Kernel-Puffer mithilfe einer Assistenten-Kmsg mit einem 0x4000 Bytes großen OOL-Deskriptor, der von hinten überschrieben wird. Löse dann den Bug mit der allokierten Nachricht aus, genannt Double-Copyin-Kmsg, die direkt hinter dem Assistenten-Kernel-Puffer platziert wird. Diese Nachricht enthält einen OOL-Ports-Deskriptor, dessen Zähler 0x2000 beträgt und der damit ziemlich nahe am IOSurfaceClient-Array liegt.
Dann solltest du die Assistenten-Nachricht empfangen. Wenn das Racing gelingt, wird der OOL-Ports-Deskriptor offengelegt und wir können die Adresse des IOSurfaceClient-Arrays lokalisieren.
Allokiere dann erneut einen 0x4000 Bytes großen Kernel-Puffer; dieser wird den zuvor genannten Kernel-Puffer belegen. Diesmal konstruiere ich einen gefälschten Kmsg-Header mit passendem Body. Dann zerstöre ich die Double-Copyin-Kmsg, und der Kernel beginnt mit unserem gefälschten Header. Ich verwende einen gefälschten mach_msg_ool_descriotpor_t und löse vm_copy_discard() mit einer vollständig kontrollierten Kopie aus. Während der Zerstörung der Kopie sind die wertvollsten Zeilen in _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
Der entry liegt unter unserer Kontrolle, was uns ein perfektes Lese-/Schreib-Primitiv gibt. Ich nutze dies, um einen kontrollierten Zeiger in das IOSurfaceClient-Array zu schreiben und erreiche dann Kernel-Lese-/Schreibzugriff in Kombination mit IOSurfaceRootUserClient-Schnittstellen.
Ich habe bazads Beitrag „One byte to rule them all“ während der Entwicklung dieses Exploits immer wieder gelesen und in seinem Exploit dieselbe Technik verwendet, nämlich das Fälschen von vm_copy_t. Es gibt jedoch einige Unterschiede.
XNU signiert die Nachricht und wir können keine beschädigte Kmsg mehr empfangen.
Im Zerstörungsprozess setze ich mapping_in_progress des vm_object, damit der Kernel spinnt und nicht aufgrund der Zonenprüfung einen Panic auslöst.
Vielen Dank an bazad für seinen großartigen Beitrag, an WangTielei dafür, dass er mich wissen ließ, dass IOSurfaceClient-Schnittstellen für Lese-/Schreib-Primitive nun ungültig sind, und an pedantcoder für seine Freundlichkeit.