
CVE-2026-43499 adattatore di exploit per MT6985 MediaTek Dimensity 9300 (vivo PD2241)
Conclusione: spesi 68M token, nessun root ottenuto.
Motivo: l'attacco di timing KernelSnitch non è affidabile su MTK Dimensity 9200,CONFIG_PANIC_ON_OOPS=ynon lascia spazio a tentativi ed errori.
Questo articolo documenta l'intero processo di difficoltà incontrate, come riferimento per evitare le stesse trappole.
| Progetto | Valore |
|---|---|
| Dispositivo | vivo PD2241 (Dimensity 9200 / MT6985), Android 15 |
| Firmware | PD2241_A_15.2.10.2.W10.V000L1 |
| Kernel | 5.15.178-android13-8-gfb31f5bdd612-dirty |
| Bootloader | Bloccato (ro.boot.flash.locked=1) |
| SELinux | Enforcing |
| panic_on_oops | Attivo → qualsiasi OOPS del kernel = riavvio immediato |
| Exploit | CyberMeowfia — CVE-2026-43499 (IonStack) |
| Albero sorgente | android_15.0_kernel_MT6985 (5.15.178) — non corrisponde alla versione del dispositivo (sorgente è android15 GKI, il dispositivo esegue android13 GKI) |
Estratto da arch/arm64/include/asm/memory.h + include/linux/fs.h + android/abi_gki_aarch64.xml:
KIMAGE_TEXT_BASE = 0xffffffc008000000, VA_BITS=39, DIRECT_MAP=256GBlayout-offset-in-bits)iopoll (android13 GKI), IOCTL=0x48, open=0x68atomic_t usage = 4 byte, uid=0x04slab_cache=0x18Scoperta chiave: il sorgente è android15 GKI, il dispositivo è android13 GKI — gli offset di task_struct differiscono di 0x40~0x88 byte, non si possono copiare direttamente dal sorgente.
OTA zip (8.3GB)
→ payload.bin (8.2GB)
→ payload_dumper → boot.img (96MB, header v4)
→ decompressione LZ4 → Image (50MB ARM64)
→ kallsyms-finder → 187810 simboli
Simboli estratti da due versioni di firmware (15.2.7.6 / 15.2.10.2) — lo stesso simbolo differisce di 10KB~200KB tra le due versioni, è necessario usare la versione corretta.
# In rt_mutex_adjust_pi:
LDR x21, [x19, #0x8b0] → pi_blocked_on = 0x8b0 (valore android15, non frankel)
Questo conferma che il layout di task_struct è il ramo android15, non l'android13 di frankel.
NDK r29, make PROJECT=android_15.0_kernel_MT6985 → preload.so (150KB).
[+] preload starting pid=25414
[+] p0 profile ... tutti i simboli caricati correttamente
[-] KernelSnitch mm_struct leak failed ← a volte assente (occasionalmente riuscito)
[+] slide child context route=pselect ← avvio processo figlio per leak KASLR slide
[panic del kernel] ← rt_mutex_adjust_prio_chain+0x1b0
Istruzione del crash (capstone):
ldar w8, [x27] ; x27 = waiter->lock (caricato da [x28, #0x38])
; il valore di x27 è spazzatura → nessuna mappatura nella tabella pagine → translation fault
; → die() → panic → riavvio
KernelSnitch è il punto di ingresso dell'intero exploit — sfrutta la differenza di timing nei bucket hash di futex per rivelare l'indirizzo di mm_struct:
MT6985 ha CONFIG_KASAN_HW_TAGS=y → il kernel etichetta le allocazioni slab con tag MTE
il puntatore di mm_struct ha un tag KASAN → futex_hash calcola basandosi sul puntatore taggato
ma la scansione bruteforce della direct map (indirizzi untagged) → l'hash calcolato non corrisponde
anche aggiungendo l'iterazione dei tag MTE (0-14, 15 totali), su sistemi con VA_BITS=39
i bit del tag (bit56-59) si sovrappongono ai bit di estensione del segno → alcune combinazioni di tag
producono indirizzi non validi → mancato rilevamento
I dispositivi Pixel non hanno KASAN_HW_TAGS, questo meccanismo funziona. Su MTK no.
CONFIG_PANIC_ON_OOPS è il killerPixel: OOPS del kernel → dump_stack → continua → l'exploit può riprovare
MT6985: OOPS del kernel → die() → panic() → riavvio immediato → nessuno spazio per tentativi
una minima deviazione nella catena π e tutto crolla; su Pixel una deviazione significa solo
"questo tentativo non è riuscito, riprova con un altro set di indirizzi".
E il bootloader è bloccato (flash.locked=1) → non è possibile flashare un kernel personalizzato per rimuovere questa opzione.
Albero sorgente: 5.15.178 android15 GKI
Dispositivo: 5.15.178-android13 (vendor vivo)
Sebbene il numero di versione principale sia lo stesso 5.15.178, i rami GKI differiscono (android13 vs android15), quindi il layout delle strutture critiche come task_struct/cred non è coerente. Dopo ripetuti tentativi di passare tra gli offset frankel/android15, solo il disassemblaggio ha permesso di fissare la versione corretta.
| Modifica | Scopo | Risultato |
|---|---|---|
THRESHOLD_MULT 10→5→3 | Abbassare la soglia di rilevamento collisioni | <5 troppi falsi positivi |
APPENDED_FUTEXES 4096→8192 | Aumentare la differenza nella catena hash | Nessun effetto |
REPEAT_MEASUREMENT/AVERAGE | Aumentare la precisione del campionamento | Nessun effetto |
MTE=1 | Far iterare i tag al bruteforce | Più lento, anzi meno crash |
MM_STRUCT_SZ 0x500→0x400 | Correggere il passo di mm_struct | Necessario, l'ABI reale è 992 byte |
IDENTITY_END 64GB→256GB | Ampliare l'intervallo di scansione | Troppo lento (iterazione MTE), ancora nessuna corrispondenza |
| Offset TASK: android15↔frankel | Fissare gli offset corretti | Disassemblaggio conferma android15 |
| Offset FOPS: android15↔frankel | android13 non ha iopoll | Usato frankel |
In exploit/targets/android_15.0_kernel_MT6985/target.h:
| Categoria | Affidabilità | Metodo di verifica |
|---|---|---|
| Layout di memoria | Corretto | Calcolo da memory.h + verifica kallsyms _text |
| Offset simboli (22) | Corretti | Estratti da boot.img 15.2.10.2 |
| Offset task_struct | Corretti | ABI XML + disassemblaggio capstone (pi_blocked_on=0x8b0) |
| Offset FOPS | Errati (corretti il 2026-07-31) | Valori originali copiati da frankel (android13 senza iopoll); l'ABI dell'albero sorgente ha effettivamente iopoll@0x30, ioctl=0x50, open=0x70 — vedi VERIFICATION.md |
| Offset CRED | Corretti (verificati) | ABI XML: uid=0x04, securebits=0x24, caps=0x28, security=0x78 |
L'assembly compila, l'esecuzione parte, si perde solo nell'ultimo chilometro.
CONFIG_PANIC_ON_OOPS — o flashare un kernel personalizzato (richiede sblocco del bootloader), oppure trovare un dispositivo MT6985 con questa opzione disattivata di default