Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-43499-pmg110-root — Exploit LPE per Android per CVE-2026-43499 che ha come target OPPO PMG110 (kernel 6.6). Utilizza futex PI UAF per ottenere root e installare un daemon su tramite LD_PRELOAD. | Kitploit
Strumenti/GitHubGitHub/soralis0912/cve-2026-43499-pmg110-root
Sicurezza AndroidEscalation di PrivilegiAnalisi delle VulnerabilitàExploitPost-ExploitPenetration TestingSicurezza MobileRed TeamingSviluppo Payload

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
Binary Exploitation
GitHubsoralis0912/cve-2026-43499-pmg110-root

CVE-2026-43499-pmg110-root

Exploit LPE per Android per CVE-2026-43499 che ha come target OPPO PMG110 (kernel 6.6). Utilizza futex PI UAF per ottenere root e installare un daemon su tramite LD_PRELOAD.

Vedi Repository
124 giorni faNon ancora revisionato

pmg110-root

CVE-2026-43499 (use-after-free di rt_mutex_waiter in futex PI) escalation dei privilegi locale, portata su OPPO PMG110 / K15 Pro+ — MediaTek MT6991, ColorOS 16.

Un solo file trasferito, eseguito tramite LD_PRELOAD:

root@kitploit:~
adb push out/preload-pmg110-16.0.9.400.so /data/local/tmp/preload.so
adb shell chmod 644 /data/local/tmp/preload.so
adb shell LD_PRELOAD=/data/local/tmp/preload.so /system/bin/true

In caso di successo viene lasciato un su persistente:

root@kitploit:~
adb shell /data/local/tmp/su -c id      # uid=0(root)

Verificato sul dispositivo (2026-07-27): uid=0 in circa 35 secondi da un'esecuzione semplice senza override delle variabili d'ambiente, e su risponde successivamente da una normale adb shell non privilegiata:

root@kitploit:~
$ adb shell "/data/local/tmp/su -c 'echo 0 > /proc/sys/kernel/kptr_restrict'"
$ adb shell "/data/local/tmp/su -c 'grep -w init_task /proc/kallsyms'"
ffffffe89033e780 D init_task

Sia l'exploit sia l'installazione di su sono verificati su questo dispositivo. Ciò che quella shell con privilegi di root ha poi letto conferma anche P0_KERNEL_PHYS_LOAD, gli offset dei simboli e KS_MTE_TAGGED=0 indipendentemente dall'exploit — vedi targets/pmg110-16.0.9.400/NOTES.md.

Cosa fa e cosa non fa

Esegue Write 1 (SELinux permissive) e Write 2 (cred → init_cred), porta un processo figlio a uid=0 e da lì installa il demone su incorporato.

  • sempre un solo file trasferito. su non è un secondo artefatto: su_daemon.c è compilato come PIE aarch64 autonomo e incluso con .incbin nel .rodata della libreria, quindi viaggia dentro preload.so e viene riscritto su file in fase di esecuzione. È la via di warhol-root, invariata.
  • nessuno script di root, niente ksud, niente KernelSU
  • il processo chiamante resta non privilegiato — ottiene root chiedendo al demone, che è esattamente ciò che farai dalla shell successivamente
  • SELinux viene lasciato permissive, come fa warhol-root: il demone deve servire client non privilegiati tramite la sua socket. Riavvia per ripristinare enforcing.

su viene installato in tre posti, perché uno di questi è quello a cui accederai davvero:

Il demone ascolta su /data/local/tmp/temp_su.sock e scrive il log in /data/local/tmp/su_daemon.log. Root non è persistente tra i riavvii — rilancia la riga LD_PRELOAD dopo ogni avvio.

Per l'installazione di KernelSU, usa invece la via /data/local/tmp/a/e in ghostlock-oneplus.

Relazione con warhol-root

Tutto tranne il nucleo dell'exploit è di warhol-root, preso invece che reinventato:

  • il layout — header per dispositivo in targets/<device>/, copiati in source/src/ in fase di build, così cambiando DEVICE non si possono mai lasciare indietro gli header del dispositivo precedente
  • la build — selezione della toolchain di source/Makefile (NDK se presente, altrimenti clang dell'host contro il sysroot NDK) e la regola di embedding in due fasi che produce build/embed/su_daemon_aarch64_pie prima di linkare il .so
  • la via di su — su_daemon.c e su_blob.S sono byte-identici a quelli di warhol-root, e su_install.c è il suo installer preload.c

Il nucleo dell'exploit non è di warhol-root. warhol-root è popsicle, ancorato a GKI 6.12 / android16 e il suo generate_target.py rifiuta qualsiasi altro banner. PMG110 è 6.6 / android15, quindi il nucleo qui è l'albero ghostlock 6.6 — a sua volta discendente dello stesso codice (kernelsnitch/utils.h e timeutils.h sono byte-identici tra i due repository), ulteriormente sviluppato.

Ogni riga dell'exploit vero e proprio — Write 1, Write 2, KernelSnitch, la via pselect — è lo stesso codice in entrambi gli alberi.

Da dove viene chiamata l'installazione di su

Questa è l'unica differenza strutturale, ed è imposta dal fatto che i due alberi ottengono root in forme diverse.

warhol-root porta a root il processo dell'exploit stesso e quindi chiama install_embedded_su() direttamente da run_direct_root(). Qui Write 2 sostituisce il puntatore cred di un figlio forkato e il padre resta il chiamante non privilegiato, quindi il figlio in child_main() è l'unico contesto che può fare l'installazione — ed è lì che viene eseguita.

Entrambi gli alberi hanno lo stesso stub weak install_embedded_su() in util.c che restituisce ENOSYS; fornire la definizione strong è ciò che attiva la via. Vale la pena saperlo perché una build che per qualche motivo esclude su_install.c viene comunque linkata e funziona — riporta solo su=0/38 e non installa nulla.

Build

root@kitploit:~
make                      # = make preload -> out/preload-<DEVICE>.so
make DEVICE=<name>        # use targets/<name>/
make devices              # list available DEVICE values
make info                 # show the selected target and the resolved toolchain

La toolchain viene trovata da sola: prima ANDROID_NDK_HOME / ANDROID_NDK_ROOT, poi le solite posizioni di installazione di NDK per Linux e macOS e, se tutte falliscono, clang dell'host con target sul sysroot NDK. Imposta ANDROID_NDK_HOME solo per sovrascrivere la ricerca. make info stampa cosa ha scelto.

La build è in due fasi, ed è la parte che vale la pena conoscere:

  1. su_daemon.c → build/embed/su_daemon_aarch64_pie, un PIE aarch64 autonomo
  2. su_blob.S include con .incbin quel binario in .rodata, e il tutto viene linkato nell'unico preload.so

Quindi make clean e una rebuild sono l'unico modo per cambiare il su incorporato — modificare il solo su_daemon.c è sufficiente, la dipendenza è dichiarata, ma il blob è un artefatto di build e non è tracciato.

targets/<device>/{target.h,device_offsets.h} vengono ricopiati in source/src/ a ogni build, così un header obsoleto di un altro dispositivo non può essere raccolto silenziosamente.

out/*.so non è tracciato (stessa convenzione di warhol-root) — clona e fai make.

Il .so è compilato con -fvisibility=hidden ed esporta zero simboli. Una libreria LD_PRELOAD vince la risoluzione dei simboli per l'intero processo, quindi qualsiasi cosa esportata potrebbe oscurare un simbolo con lo stesso nome nel binario host o in libc. Quel flag governa solo la generazione di codice C, quindi su_blob.S marca i suoi due simboli come .hidden a mano — senza quelle righe i limiti del blob sarebbero l'unica cosa che la libreria esporterebbe ancora.

Variabili d'ambiente

Nessuna di queste è servita nell'esecuzione verificata.

Lettura del log

root@kitploit:~
[*] futex_hashsize 2048 (8 possible CPUs)
[*] ks collisions=3/3 baseline=8 threshold=10x (80) accepted=[1244..1597] slowest_rejected=N
[+] child uid = 0
[+] embedded su wrote 15304 bytes to /apex/com.android.virt/bin/su
[+] embedded su daemon ready pid=NNNN socket=/data/local/tmp/temp_su.sock daemon=/apex/com.android.virt/bin/su
[+] embedded su install ok=1 errno=0 daemon=NNNN
[+] su ready: /data/local/tmp/su and /apex/com.android.virt/bin/su
[+] ghostlock preload verdict: EXPLOIT OK

child uid = 0 è l'exploit riuscito; tutto ciò che viene dopo è l'installazione. I due eventi sono riportati separatamente di proposito, e così anche il verdetto:

Quello di mezzo è la distinzione che vale la pena avere: dice che gli offset in target.h sono giusti per questa build e che il problema è da qualche parte nell'installazione, che è una cosa completamente diversa da debuggare. su=0/38 (ENOSYS) al suo interno significa specificamente che è stato linkato lo stub weak.

mm_struct leak failed seguito da prepare_kernel_page retry N/24 non è un fallimento. È l'avanzamento del loop, e anche l'esecuzione riuscita lo mostra. Nulla è fallito finché i 24 tentativi non sono esauriti e appare prepare_kernel_page timeout. Allo stesso modo probing cfi ... expected=9 con child uid = 2000 è un giro mancato, su dieci.

Non giudicare un'esecuzione da un log troncato — quell'errore è costato un intero giro di diagnosi sbagliata qui.

Anche un'intera esecuzione fallita è normale. La race di pselect non è al 100%: un'esecuzione può perderla cinque volte di fila e terminare con Write 1 failed, e quella successiva la vince al primo tentativo con ret=9. Osservato su questo dispositivo. ret=4 expected=9 è l'aspetto di una race persa, non di un target.h sbagliato — un singolo fallimento non è un motivo per ricalcolare gli offset. Rieseguila.

File

Licenza

Solo per ricerca sulla sicurezza autorizzata e scopi educativi.

Scarica lo strumento
DeviceOPPO PMG110 / K15 Pro+ / OP61E5L1
SoCMediaTek MT6991 (Dimensity 9500s)
Kernel6.6.118-android15-8-g93e223c276e7-abogki500782043-4k (GKI, 4K pages)
BuildColorOS 16 / PMG110_16.0.9.400(CN01) — stessi byte del kernel di 16.0.8.300
BugCVE-2026-43499, non corretto in questa immagine (mostrato dal disassembly, non dalla versione)
PathWhy
/apex/com.android.virt/bin/susu un tmpfs montato sopra quella directory; nel PATH di una shell root
/data/local/tmp/suraggiungibile da una semplice adb shell senza giochi di PATH
/apex/com.android.virt/bin/su nel mount namespace di adbdinstallato via setns, quindi una nuova adb shell lo vede
FileRelationship
util.c slide.c fops.c pipe.c root.c miniadb.c common.h offset.h kernelsnitch/*di ghostlock, byte-identici
su_daemon.c su_blob.Sdi warhol-root, byte-identici (su_blob.S aggiunge due righe .hidden — vedi Build)
su_install.cl'installer preload.c di warhol-root, spostato in un file proprio perché il preload.c di questo albero ha già un compito diverso
main.cdi ghostlock, più la chiamata a su nel figlio con root e la segnalazione del risultato
preload.csolo qui — il costruttore e il log a doppia destinazione
offsets.hsolo definizione della struct; la voce è copiata da targets/<device>/device_offsets.h
VariableEffect
GHOSTLOCK_LOGdestinazione del log (default /data/local/tmp/.ghostlock.log); l'output va su stdout e sul file
GHOSTLOCK_KS_VERBOSE=1stampa gli indirizzi di collisione e gli intervalli di sweep di KernelSnitch
GHOSTLOCK_KS_THRESHOLD=<n>sovrascrive il moltiplicatore di soglia delle collisioni
GHOSTLOCK_MTE=1esegue lo sweep anche dei tag dei puntatori del kernel (15x più lento)
GHOSTLOCK_PHYS_LOAD=0x...sovrascrive l'indirizzo di caricamento fisico del kernel
PSELECT_SHIFT=<n>sovrascrive lo shift dell'overlay di stack (sostituisce, non aggiunge)
VerdictMeaning
EXPLOIT OKroot, e su risponde
EXPLOIT OK, SU INSTALL FAILEDWrite 1 e Write 2 sono andati a segno; solo l'installazione è fallita
EXPLOIT FAILEDle scritture non sono andate a segno
ABORTEDl'esecuzione è terminata prima di poter riportare — leggi l'ultima riga [!]
PathContents
source/src/preload.ccostruttore: esegue l'exploit, riporta, si ferma
source/src/main.cl'exploit stesso (Write 1 / Write 2)
source/src/su_daemon.cil binario su — compilato standalone come PIE aarch64, non linkato nel .so
source/src/su_blob.Sinclude con .incbin quel PIE nel .rodata del .so
source/src/su_install.criscrive il blob su file, avvia il demone, lo sonda
source/src/target.hdestinazione di staging (gitignored)
targets/<device>/target.hlayout a tempo di compilazione: offset delle struct, costanti physmap, forme di slab e futex
targets/<device>/device_offsets.hoffset dei simboli globali da kallsyms
tools/extract_device.pyboot.img → offset, campi delle struct BTF, risultato dell'overlay pselect
tools/preloader_memlayout.pypreloader MediaTek → P0_KERNEL_PHYS_LOAD
tools/qemu_verify.pyavvia il kernel sotto QEMU: misura l'overlay di stack, verifica la stabilità della mappa lineare
tools/device_probe.shcontrollo preliminare da una shell adb non privilegiata