
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/proc/self/pagemap — limitato su questo dispositivo (restituisce tutti zeri)/proc/mtk_*) — esistono ma richiedono ulteriore analisisymbols/kallsyms_PD2241_15.2.10.2.txt — tabella simboli completa della 15.2.10.2, utilizzabile direttamente da altridevice_config.txt — configurazione reale del kernel del dispositivo, mostra cosa ha modificato il vendorexploit/targets/android_15.0_kernel_MT6985/target.h — offset delle strutture verificatiscripts/server_compile.py — compilazione automatizzata, ricompilazione rapida dopo modifiche ai parametritar -xf può fallire su zip di grandi dimensioni, usare Python zipfile o decomprimere prima manualmenteupdate_metadata_pb2.py generato richiede protobuf 5.x, è necessario rimuovere manualmente la riga di importazione runtime_version./preload.so causa segfault: è obbligatorio usare /system/bin/linker64 /data/local/tmp/preload.solayout-offset-in-bits è calcolato dal compilatore, 100 volte più preciso che contare manualmente 5000 byteCONFIG_ANDROID_VENDOR_OEM_DATA=y, CONFIG_SCHED_INFO=y, CONFIG_RSC_* → devia dal GKI standardboot.img → kernel.bin → decompressione LZ4 → Image → kallsyms-finder → tabella simboli07/28 Download repository CyberMeowfia + sorgente MT6985
07/29 Analisi sorgente (memory.h, fs.h, ABI XML, varie struct)
Decompressione firmware (payload.bin → boot.img → Image)
Estrazione simboli (kallsyms-finder → 187810 simboli)
Molteplici cicli di compilazione + crash + verifica disassemblaggio
5 tentativi automatici → tutti falliti
Scrittura di questo articolo
-------------------------------------------
Totale: ~68M token, 0 shell root
2026-07-29, sopravvissuto per raccontarlo
Dopo aver ottenuto android_15.0_kernel_MT6985.tar.gz (albero sorgente 5.15.178 + ABI XML) è stata eseguita
una verifica incrociata completa, dettagli in VERIFICATION.md. Riepilogo:
target.h è stato corretto, con
autoverifica di fallback sul dispositivo reale tramite leak_kernel_base() integrato nell'exploit.KSNITCH_MTE_ENABLED=1 è realmente
effettivo (il util.c originale aveva mte=0 hardcoded);rt_mutex_adjust_prio_chain+0x1b0 si trova nella fase pselect/pi chain, prima
dell'autoverifica FOPS; dopo le correzioni sopra vale la pena rieseguire la verifica sul dispositivo.Dispositivo (PD2241, compiler251203103903) testato in 8+ round:
MM_STRUCT_SZ=0x400 (l'originale 0x500 causava una griglia di
scansione disallineata e solo falsi positivi) + iterazione tag MTE 0..15 (il tag del puntatore mm del
dispositivo cambia) + untag degli indirizzi falsificati. Ora trova stabilmente il vero mm_struct.rt_mutex_adjust_prio_chain+0x1b0: competizione di timing nella
catena pselect/pi (il waiter falsificato non raggiunge l'offset corretto nello stack del kernel).
Lo scheduler RSC di vivo ha modificato il percorso futex/pi, probabilmente rompendo alla radice questa
race condition. L'allineamento dello stack slide è stato parametrizzato come variabile d'ambiente
SLIDE_SHIFT, scansione non completata.Scelta finale: downgrade a sblocco bootloader a pagamento (non si dipende più da questo percorso).