Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Herramientas/GitHubGitHub/soralis0912/cve-2026-43499-pmg110-root
Seguridad AndroidEscalada de PrivilegiosAnálisis de VulnerabilidadesExplotaciónPost-ExplotaciónPruebas de PenetraciónSeguridad MóvilRed TeamingDesarrollo de Payloads

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
Explotación de Binarios
GitHubsoralis0912/cve-2026-43499-pmg110-root

CVE-2026-43499-pmg110-root

Exploit de escalada local de privilegios (LPE) para Android de CVE-2026-43499 dirigido al OPPO PMG110 (kernel 6.6). Utiliza UAF de futex PI para obtener root e instalar un daemon su mediante LD_PRELOAD.

Ver Repositorio
1hace 24 díasAún no revisado

pmg110-root

CVE-2026-43499 (use-after-free de rt_mutex_waiter en futex PI), escalada de privilegios local, portada al OPPO PMG110 / K15 Pro+ — MediaTek MT6991, ColorOS 16.

Un solo archivo enviado, ejecutado mediante 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

En caso de éxito, queda un su persistente:

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

Verificado en el dispositivo (2026-07-27): uid=0 en unos 35 segundos desde una ejecución simple sin anular variables de entorno, y su respondiendo después desde una adb shell normal y sin privilegios:

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

El exploit y la instalación de su están verificados en este dispositivo. Lo que esa shell con root leyó después también confirma P0_KERNEL_PHYS_LOAD, los offsets de símbolos y KS_MTE_TAGGED=0 independientemente del exploit — ver targets/pmg110-16.0.9.400/NOTES.md.

Qué hace y qué no hace

Ejecuta Write 1 (SELinux permisivo) y Write 2 (cred → init_cred), consigue que un proceso hijo tenga uid=0 y desde ahí instala el demonio su integrado.

  • sigue siendo un solo archivo enviado. su no es un segundo artefacto: su_daemon.c se compila como un PIE aarch64 independiente y se incrusta con .incbin en el .rodata de la librería, de modo que viaja dentro de preload.so y se vuelve a escribir en tiempo de ejecución. La vía de warhol-root, sin cambios.
  • sin script de root, sin ksud, sin KernelSU
  • el proceso que llama sigue sin privilegios — obtiene root preguntándole al demonio, que es lo mismo que harás después desde la shell
  • SELinux queda en modo permisivo, igual que lo deja warhol-root: el demonio tiene que atender a clientes sin privilegios a través de su socket. Reinicia para restaurar el modo enforcing.

su se instala en tres lugares, porque uno de ellos es al que llegarás realmente:

El demonio escucha en /data/local/tmp/temp_su.sock y registra en /data/local/tmp/su_daemon.log. El root no persiste entre reinicios: vuelve a ejecutar la línea de LD_PRELOAD después de cada arranque.

Para instalar KernelSU, usa en su lugar la vía /data/local/tmp/a/e de ghostlock-oneplus.

Relación con warhol-root

Todo excepto el núcleo del exploit es de warhol-root, tomado en lugar de reinventado:

  • la estructura — cabeceras por dispositivo en targets/<device>/, preparadas en source/src/ en tiempo de compilación, de modo que cambiar DEVICE nunca pueda dejar atrás las cabeceras del dispositivo anterior
  • la compilación — la selección de cadena de herramientas de source/Makefile (NDK si lo hay, clang del host contra el sysroot del NDK si no) y la regla de incrustación en dos etapas que produce build/embed/su_daemon_aarch64_pie antes de enlazar el .so
  • la vía de su — su_daemon.c y su_blob.S son byte-idénticos a los de warhol-root, y su_install.c es su instalador preload.c

El núcleo del exploit no es de warhol-root. warhol-root es popsicle, que está fijado a GKI 6.12 / android16 y cuyo generate_target.py rechaza cualquier otro banner. El PMG110 es 6.6 / android15, así que el núcleo aquí es el árbol 6.6 de ghostlock — descendiente a su vez del mismo código (kernelsnitch/utils.h y timeutils.h son byte-idénticos entre los dos repos), desarrollado más a fondo.

Cada línea del exploit en sí — Write 1, Write 2, KernelSnitch, la vía pselect — es el mismo código en ambos árboles.

Desde dónde se llama a la instalación de su

Esta es la única diferencia estructural, y viene impuesta porque los dos árboles obtienen root de formas distintas.

warhol-root obtiene root en el propio proceso del exploit y por eso llama a install_embedded_su() directamente desde run_direct_root(). Aquí Write 2 intercambia el puntero cred de un hijo bifurcado y el padre sigue siendo el llamador sin privilegios, así que el hijo en child_main() es el único contexto que puede hacer la instalación — ahí es donde se ejecuta.

Ambos árboles llevan el mismo stub débil install_embedded_su() en util.c que devuelve ENOSYS; proporcionar la definición fuerte es lo que activa la vía. Conviene saberlo porque una compilación que por lo que sea deje fuera su_install.c igualmente enlaza y se ejecuta — solo informa de su=0/38 y no instala nada.

Compilación

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 cadena de herramientas se encuentra sola: primero ANDROID_NDK_HOME / ANDROID_NDK_ROOT, luego las ubicaciones habituales de instalación del NDK para Linux y macOS y, si todas fallan, clang del host apuntando al sysroot del NDK. Define ANDROID_NDK_HOME solo para anular la búsqueda. make info imprime lo que eligió.

La compilación es de dos etapas, que es la parte que conviene saber:

  1. su_daemon.c → build/embed/su_daemon_aarch64_pie, un PIE aarch64 independiente
  2. su_blob.S incrusta ese binario con .incbin en .rodata, y todo el conjunto se enlaza en el único preload.so

Así que make clean y una recompilación son la única forma de cambiar el su integrado — basta con editar su_daemon.c, la dependencia está declarada, pero el blob es un artefacto de compilación y no está bajo seguimiento.

targets/<device>/{target.h,device_offsets.h} se vuelven a preparar en source/src/ en cada compilación, de modo que una cabecera obsoleta de otro dispositivo no puede recogerse silenciosamente.

out/*.so no está bajo seguimiento (misma convención que warhol-root) — clona y ejecuta make.

El .so se compila con -fvisibility=hidden y exporta cero símbolos. Una librería LD_PRELOAD gana la resolución de símbolos para todo el proceso, así que cualquier cosa que exportara podría hacer sombra a un símbolo homónimo en el binario anfitrión o en libc. Ese indicador solo gobierna la generación de código C, así que su_blob.S marca sus dos símbolos como .hidden a mano — sin esas líneas, los límites del blob serían lo único que la librería seguiría exportando.

Variables de entorno

Ninguna de estas fue necesaria en la ejecución verificada.

Lectura del registro

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 es el exploit teniendo éxito; todo lo que va después es la instalación. Ambos se informan por separado a propósito, y también el veredicto:

El del medio es la distinción que merece la pena tener: dice que los offsets de target.h son correctos para esta compilación y que el problema está en algún punto de la instalación, que es algo completamente distinto de depurar. su=0/38 (ENOSYS) en su interior significa concretamente que se enlazó el stub débil.

mm_struct leak failed seguido de prepare_kernel_page retry N/24 no es un fallo. Es el progreso del bucle, y la ejecución exitosa también lo muestra. Nada ha fallado hasta que se agotan los 24 intentos y aparece prepare_kernel_page timeout. Del mismo modo, probing cfi ... expected=9 con child uid = 2000 es una ronda fallida de diez.

No juzgues una ejecución por un registro truncado — ese error costó una ronda completa de diagnóstico erróneo aquí.

Una ejecución completamente fallida también es normal. La condición de carrera de pselect no es 100% fiable: una ejecución puede perderla cinco veces seguidas y terminar en Write 1 failed, y la siguiente la gana al primer intento con ret=9. Observado en este dispositivo. ret=4 expected=9 es lo que parece perder la carrera, no un target.h equivocado — un fallo no es motivo para volver a derivar los offsets. Vuelve a ejecutarla.

Archivos

Licencia

Solo para investigación de seguridad autorizada y fines educativos.

Descargar herramienta
DispositivoOPPO PMG110 / K15 Pro+ / OP61E5L1
SoCMediaTek MT6991 (Dimensity 9500s)
Kernel6.6.118-android15-8-g93e223c276e7-abogki500782043-4k (GKI, páginas de 4K)
CompilaciónColorOS 16 / PMG110_16.0.9.400(CN01) — mismos bytes de kernel que 16.0.8.300
BugCVE-2026-43499, sin corregir en esta imagen (demostrado por desensamblado, no por versión)
RutaPor qué
/apex/com.android.virt/bin/suen un tmpfs montado sobre ese directorio; en el PATH de una shell con root
/data/local/tmp/suaccesible desde un adb shell normal sin juegos de PATH
/apex/com.android.virt/bin/su en el mount namespace de adbdinstalado mediante setns, de modo que una nueva adb shell lo ve
ArchivoRelación
util.c slide.c fops.c pipe.c root.c miniadb.c common.h offset.h kernelsnitch/*de ghostlock, byte-idénticos
su_daemon.c su_blob.Sde warhol-root, byte-idénticos (su_blob.S añade dos líneas .hidden — ver Compilación)
su_install.cel instalador preload.c de warhol-root, movido a su propio archivo porque el preload.c de este árbol ya tiene otra función
main.cde ghostlock, más la llamada a su en el hijo con root y el informe de resultados
preload.csolo aquí — el constructor y el registro de doble destino
offsets.hsolo la definición de la struct; la entrada se prepara desde targets/<device>/device_offsets.h
VariableEfecto
GHOSTLOCK_LOGdestino del registro (por defecto /data/local/tmp/.ghostlock.log); la salida va a stdout y al archivo
GHOSTLOCK_KS_VERBOSE=1imprime las direcciones de colisión y los rangos de barrido de KernelSnitch
GHOSTLOCK_KS_THRESHOLD=<n>anula el multiplicador del umbral de colisión
GHOSTLOCK_MTE=1barre también las etiquetas de puntero del kernel (15 veces más lento)
GHOSTLOCK_PHYS_LOAD=0x...anula la dirección de carga física del kernel
PSELECT_SHIFT=<n>anula el desplazamiento de la superposición de pila (reemplaza, no suma)
VeredictoSignificado
EXPLOIT OKroot, y su responde
EXPLOIT OK, SU INSTALL FAILEDWrite 1 y Write 2 acertaron; solo falló la instalación
EXPLOIT FAILEDlas escrituras no acertaron
ABORTEDla ejecución murió antes de poder informar — lee la última línea [!]
RutaContenido
source/src/preload.cconstructor: ejecuta el exploit, informa, se detiene
source/src/main.cel exploit en sí (Write 1 / Write 2)
source/src/su_daemon.cel binario su — compilado de forma independiente como PIE aarch64, no enlazado en el .so
source/src/su_blob.Sincrusta ese PIE con .incbin en el .rodata del .so
source/src/su_install.cescribe el blob de vuelta, arranca el demonio y lo comprueba
source/src/target.hdestino de preparación (ignorado por git)
targets/<device>/target.hestructura en tiempo de compilación: offsets de structs, constantes de physmap, formas de slab y futex
targets/<device>/device_offsets.hoffsets de símbolos globales de kallsyms
tools/extract_device.pyboot.img → offsets, campos de struct BTF, resultado de la superposición pselect
tools/preloader_memlayout.pyMediaTek preloader → P0_KERNEL_PHYS_LOAD
tools/qemu_verify.pyarranca el kernel bajo QEMU: mide la superposición de pila y comprueba la estabilidad del mapa lineal
tools/device_probe.shcomprobación previa desde una adb shell sin privilegios