AppleAVE2Driver exploit (CVE-2019-8795)¶
AppleAVE2Driver'ın session-settings path'indeki bir loop counter üzerinde eksik bounds validation, attacker'ın kontrol edilen bir buffer'ı
statsMapBufferArray'in sonunun ötesine kadar yürümesine, bir virtual method call ve nihayetinde kernel read/write elde etmesine olanak tanır.
Mechanism¶
Note
AppleAVE2Driver, yalnızca iOS cihazlarda bulunan bir IOKit video-encoder driver'ıdır. _SetSessionSettings external method'u, userland'den gelen büyük bir bloğu memmove(&client->sessionSettings_block1, userBuf, 0x630) ile doğrudan bir AVEClient kernel objesine kopyalar. İkinci bir field olan memoryInfoCnt2, AVE_DestroyContext içindeki bir loop'un statsMapBufferArray girdilerini temizlerken kaç iterasyon çalıştıracağını kontrol eder. Driver memoryInfoCnt1'i doğrular (max 4) ama memoryInfoCnt2 üzerinde hiç validation yapmaz, dolayısıyla efektif loop bound'u max(memoryInfoCnt1 + 2, memoryInfoCnt2) olur. Kontrol edilen sessionSettings_block1 kopyası struct layout'unda statsMapBufferArray'in hemen ardına düştüğü için, out-of-bounds iterasyonlar attacker'ın kontrol ettiği data'ya index'lenir ve her elemanı sahte bir IOSurfaceBufferMngr* pointer'ına dönüştürür. Cleanup sırasında ~IOSurfaceBufferMngr, offset +0x58'i dereference eder, +0x0'da başka bir pointer yükler, sonra +0x28'deki pointer'ı çağırır — kernel içinde program-counter kontrolü veren, tamamen kontrol edilen bir virtual-dispatch zinciri.
Yardımcı bir bug olan AppleSPUProfileDriver içindeki CVE-2019-8794, userspace'e uninitialized kernel stack byte'ları sızdırır ve overwrite'ı tetiklemeden önce gereken KASLR slide'ı sağlar.
Walkthrough¶
Exploit, başlangıçta araştırmacı 08Tc3wBB tarafından TyphoonPwn'da gösterilmiş ve sonradan Google Project Zero tarafından analiz edilmiştir; üç primitive'i zincirler:
Step 1 — KASLR Leak (CVE-2019-8794)
AppleSPUProfileDriver, padding'i sıfırlamadan bir userland buffer'ını kernel stack data ile dolduran bir IOKit external method açar. O byte'ları okumak bir kernel pointer'ı açığa çıkarır ve slide'ı ifşa eder.
// Open AppleSPUProfileDriver userclient, call external method index N
// Returned buffer contains uninitialized stack bytes including a kernel ptr
uint64_t kernel_ptr = leaked_buf[OFFSET];
uint64_t kaslr_slide = kernel_ptr - KNOWN_SYMBOL_UNSLID;
Step 2 — IOSurface Properties ile Heap Spray
Bug'ı tetiklemeden önce attacker, IOSurface property-set çağrıları üzerinden birçok OSData blob'u allocate eder. Her blob, sahte bir task port yapısı olarak craft edilir (sonraki pid_for_task() zinciri için):
// spray N fake port objects of known size into kalloc zones
for (int i = 0; i < SPRAY_COUNT; i++) {
IOSurfaceSetValue(surf, key[i], fake_port_data, sizeof(fake_port_data));
}
Step 3 — OOB Write Trigger (CVE-2019-8795)
AppleAVE2Driver userclient'ını aç, _SetSessionSettings'i şu değerlerle çağır:
- memoryInfoCnt1 = 0 (kontrol edilen guard'ı geçer)
- memoryInfoCnt2 = LARGE_VALUE (kontrolsüz; loop'u array sınırlarının ötesine sürer)
- sessionSettings_block1 bölgesi craft edilmiş IOSurfaceBufferMngr pointer'larıyla doldurulur
// Pseudo-layout inside AVEClient struct:
// [statsMapBufferArray: 6 * ptr_size]
// [sessionSettings_block1: 0x630 bytes] <-- memmove target
//
// With memoryInfoCnt2 = 8, loop iterates indices 0..7,
// entries 6 and 7 land in sessionSettings_block1 — attacker controlled.
struct SessionSettings ss = { 0 };
ss.memoryInfoCnt2 = 8;
memcpy(ss.statsMapBuffer_ext[6], &fake_mgr, sizeof(fake_mgr));
io_connect_call(ave_conn, SET_SESSION_SETTINGS_SEL, &ss, sizeof(ss), ...);
Step 4 — Kontrol Edilen PC'ye Virtual Dispatch
Userclient kapatıldığında, AVE_DestroyContext her girdi için DeleteMemoryInfo'yu çağırır. OOB girdileri için sahte pointer zincirini yükler:
x0 = statsMapBufferArray[6] // attacker-controlled IOSurfaceBufferMngr*
x8 = [x0 + 0x00] // vtable ptr
x8 = [x8 + 0x28] // virtual method slot
blr x8 // PC → attacker gadget
Beklenen: kernel panic ya da kaslr_slide + known_gadget_offset adresindeki JOP/ROP gadget'ına kontrol edilen redirect.
Step 5 — Fake Task Port ile Kernel R/W
Kontrol edilen execution, spray'lenen OSData blob'larından birini sahte bir kernel task port'una dönüştüren bir JOP chain'ine pivot edilir. O port üzerindeki sonraki pid_for_task() / mach_vm_read() çağrıları arbitrary kernel memory read verir; mach_vm_write() arbitrary write verir.
Expected output (successful exploit):
[*] KASLR slide: 0x5e34000
[*] Sprayed 2048 fake ports
[*] AVE2 OOB triggered, closing userclient...
[*] Reallocated dangling region with OOL ports
[*] tfp0 acquired: 0x...
[*] kernel R/W established
Detection¶
- Olağandışı bir PC ile
AppleAVE2DriverveyaAVE_DestroyContext'e atıfta bulunan Jetsam / kernel panic log'ları. - KDK + kernel debugger:
DeleteMemoryInfosırasındastatsMapBufferArrayindex > 5 olduğunu izle. - Syscall auditing: sandbox'lı bir process'ten hem
AppleSPUProfileDriverhemAppleAVE2Driverüzerinde olağandışıio_connect_methoddizileri.
Mitigation¶
- iOS 13 / watchOS 6 / tvOS 13'te patch'lendi (Ekim 2019 security update).
- Fix:
loopMaxhesaplanmadan önceif (memoryInfoCnt2 > MAX_ALLOWED) return kIOReturnBadArgument;eşdeğeri bir bounds check ekle. - A12+ üzerindeki Pointer Authentication Codes (PAC), JOP/ROP chain'lerini kısıtlar ama ilk OOB trigger'ı engellemez.