voucher_swap (CVE-2019-6225)¶
Brandon Azad'ın, XNU'nun
task_swap_mach_voucher()'ındaki bir MIG reference-counting kusurunu istismarı; biripc_voucher'ı over-release eder ve iOS 12'de (PAC'li A12 dahil) fake bir kernel task port'a reclaim edilen bir dangling pointer verir.
Mechanism¶
Note
MIG (Mach Interface Generator), service routine'leri için katı bir ownership sözleşmesi
tanımlar: success durumunda routine, içeri geçirilen her kaynağın ownership'ini alır
ve döndürdüğü herhangi bir out kaynağı açıkça üretmelidir. task_swap_mach_voucher(),
bunu görmezden gelen bir placeholder'dı — önceki reference'ı release etmeden in/out
old_voucher'ı overwrite etti ve borç alınmış new_voucher'ı sahibiymiş gibi geri verdi.
Net etki, bir ipc_voucher üzerinde bir reference'ın saldırgan tarafından kontrol
edilebilen fazladan bir add/drop'udur. Onu bir over-release olarak sürmek voucher'ı free
ederken bir dangling pointer hayatta kalır — bir
Mach port / IPC object use-after-free.
Bug, Brandon Azad (@bazad, Project Zero) ve Qixun Zhao (@S0rryMyBad, Qihoo 360 Vulcan) tarafından ortaklaşa bulundu; @S0rryMyBad bunu "Chaos" adıyla, Tianfu Cup'ta gösterilen uzaktan bir iOS 12 jailbreak'i için weaponize etti (bkz. Chaos). iOS 12.0–12.1.2 sürümlerini etkiler (12.1.3'te düzeltildi).
Walkthrough¶
Üst düzey, Project Zero writeup'ından. Yalnızca kavramsal aşamalar.
- Voucher'ları spray'le. Zone'u doldurmak ve bir target voucher'ı öngörülebilir şekilde
yerleştirmek için birçok
ipc_voucherobject'i allocate et; bir dangling reference hayatta kalabilsin diye birini bir thread'in voucher slot'unda sakla (heap grooming). - Over-release. Target voucher'ın reference'ını bir fazla düşürmek için buglı MIG routine'ini çağır; thread'in slot'u hâlâ free edilmiş object'i gösterirken onu free et.
- Komşuları free et + GC'yi zorla. Çevredeki voucher'ları free et ve zone garbage collection'ı zorla ki page farklı bir zone'a geri dönüştürülsün.
- Bir OOL ports array ile reclaim et. Free edilmiş voucher slot'una inecek boyutta bir out-of-line ports array taşıyan bir Mach mesajı gönder — bkz. ool-ports-array-spray. Array'i bir port pointer'ı voucher'ın reference-count alanıyla örtüşecek şekilde hizalamak, aynı refcount bug'ını kontrollü bir pointer increment'ine çevirir.
- Kontrol edilebilir bir port'a pivot et. Free edilmiş object için bir voucher port
materialize et, örtüşmeyi kötüye kullanarak kontrollü bir buffer (örn. bir pipe buffer) ile
örtüşen bir
ipc_port'a bir send right elde et; bu, file descriptor'lar üzerinden bir fake port üstünde read/write verir. - Kernel R/W ve tfp0. Kontrollü buffer içinde fake bir kernel task yapısı kur, dar bir
read'i bootstrap et (
pid_for_taskhilesi), sonra arbitrary kernel memory erişimi için tam bir kernel task port.
Warning
A12'de arbitrary kernel R/W, arbitrary code execution değildir: ARMv8.3 Pointer Authentication kernel pointer'larını imzalar. voucher_swap, A-key-imzalı pointer'ları forge etmenin sonraki analizini mümkün kılan R/W primitive'ini sağladı — bkz. pac-signing-gadget-bypass.
Detection¶
task_swap_mach_voucherkullanımı tek başına güçlü bir sinyaldir — meşru app'lerin çağırdığı bir routine değildir.- Bir process'ten voucher allocation patlamaları + toplu free + zorlanmış zone GC, reclaim grooming'i gösterir.
- Voucher etkinliğiyle korelasyonlanmış, free edilmiş bir zone'a boyutlanmış OOL ports array mesajları, anormal IPC trafiğidir.
- Başarısız denemelerde malformed reclaim edilmiş object'lerden gelen kernel panic'leri, gürültülü bir post-failure göstergesidir.
Mitigation¶
- iOS 12.1.3 / macOS 10.14.3 / tvOS 12.1.2'de patch'lendi — voucher swap routine'inin MIG semantiği düzeltildi (birincil mitigation).
- MIG lifetime auditing / generated-wrapper hardening, bu ve önceki bug'ların istismar ettiği geniş reference miscounting sınıfını önler.
- Reference-count range check'leri (iOS 12 geçerli refcount'ları kısıtladı, örn. 1..0x0fffffff), over-release/overflow oyunlarının güvenilirliğini azaltır, ama bu bug'ı engellemediler.
zone_require, bir voucher slot'unu bir OOL ports array ile cross-zone reclaim etmeyi kırar.- PAC / PPL, R/W'yi kalıcı kernel-task kontrolüne çevirmenin maliyetini artırır.