Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
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.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
ghostlock-pfem10 — GhostLock (CVE-2026-43499) para OPPO Find X5 Pro (PFEM10) — ingeniería inversa del watchdog de OPlus y del detector de heap-spray | Kitploit
Herramientas/GitHubGitHub/imeiplus/ghostlock-pfem10
Seguridad AndroidEscalada de PrivilegiosForensia de MemoriaAnálisis de VulnerabilidadesExplotaciónIngeniería InversaSeguridad MóvilDesarrollo de PayloadsExplotación de Binarios
GitHubimeiplus/ghostlock-pfem10

ghostlock-pfem10

GhostLock (CVE-2026-43499) para OPPO Find X5 Pro (PFEM10) — ingeniería inversa del watchdog de OPlus y del detector de heap-spray

46hace 22 díasAún no revisado

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
Ver Repositorio

GhostLock — OPPO Find X5 Pro (PFEM10)

English · 中文

build

GhostLock (CVE-2026-43499) port para el OPPO Find X5 Pro en ColorOS 16. Alcanza un proceso hijo con uid=0 y un kernelsu.ko cargado; el proceso root es interceptado.

Vulnerabilidad

CVE-2026-43499 — use-after-free de futex PI. remove_waiter() limpia current->pi_blocked_on cuando current es el requeuer, en la ruta de rollback -EDEADLK de rt_mutex_start_proxy_lock().

remove_waiter @ 0xffffffc0081ed254 — forma previa al fix.

Dispositivo

DispositivoOPPO Find X5 Pro (PFEM10)
SoCSM8450 / Adreno 730
SOColorOS 16.0.3.520 (CN01)
Kernel5.10.236-android12-9-o-gaf2075ad2c06
Bootloaderbloqueado, verde
VA_BITS39 — KIMAGE_TEXT_BASE = 0xffffffc008000000

Estado

Etapa
Disparo de waiter compacto (CMP_REQUEUE_PI → EDEADLK)funciona
Fuga de task_struct (perf)funciona
Escritura PI (8 bytes; valor = 0 o una dirección de kernel válida)funciona
task+0x778 o task+0x780 por sí solos → Uid=rootfunciona — pero un aterrizaje de un solo campo deja la tarea divergente, y eso es un BUG_ON duro latente. Ver el riesgo de divergencia
Ambos campos escritos con UN solo valor (un par consistente)❌ nunca producido con una página rociada. Solo observado con el alias global init_cred (09-14, CONTROL=1). El runner ahora lo impone (SAME_VALUE=1); no ejecutado en el dispositivo
Blanqueo de credenciales (setresgid + setresuid)implementado detrás de V12_LAUNDER=1; no ejecutado en el dispositivo
kernelsu.ko cargadofunciona
El proceso root sobrevive⚠ no establecido — ver abajo
Mecanismo de reinicio❌ no establecido. Un candidato (la divergencia) ahora está excluido; ver abajo
probe_state como criterio de aterrizaje❌ incorrecto — no usar. Tres contraejemplos; ver la tabla de abajo
Canal de pánico pstore/ramoops⚠ el instrumento existe; canal nunca validado (aún sin prueba nula)
"La víctima gira en espacio de usuario puro"⚠ aún sin lectura — uid.stream ahora registra utime/stime/nvcsw para poder comprobarlo
doble escritura de una sola pasada del lado pi⚠ no establecido; pi.pc/pi.left están codificados a 0 en fdset_map.h
Ruta A (UMH / modprobe_path)STATIC_USERMODEHELPER_PATH=""

Sobre "el proceso root sobrevive": las ejecuciones en evidence/kill.log alcanzan uid=0 y cargan kernelsu.ko, y en la ejecución que realmente lo sondeó el proceso del gestor de KernelSU sobrevivió 120 s con kernelsu aún Live en /proc/modules. En una ejecución posterior la misma cadena dejó los servicios del framework de Android inalcanzables (Can't find service: package/power/input/phone/wifi) mientras el módulo seguía Live. Nunca se ha capturado ninguna línea de kernel [ROOTCHECK-*] ni ningún payload $$sys_call_number@@, por lo que la causa del estado de la ejecución posterior no se atribuye. Ver evidence/notes.md §2.3, §2.4 y §7.

Offsets

task_struct

CampoOffset
real_cred / cred0x778 / 0x780
syscallno en caché0xdf8
uid / euid / gid / egid en caché0xe00 / 0xe08 / 0xe10 / 0xe18

thread_info

CampoOffset
flags0x0
addr_limit0x8
ttbr00x10
preempt_count0x18

cred

CampoOffsetCampoOffset
uid0x4cap_inheritable0x28
gid0x8cap_permitted0x30
suid0xccap_effective0x38
sgid0x10cap_bset0x40
euid0x14cap_ambient0x48
egid0x18
fsuid / fsgid0x1c / 0x20

Flujo del Exploit```

LT perf leak target task_struct → file W7 stage 1 task+0x778 = V (real_cred → private sprayed page; V observed) W7 stage 2 task+0x780 = V (cred) ★ V12_W7_VALUE=V — THE SAME VALUE, not a new page W7 stage 3 V+8 = 0 (LOCAL repair of the page that was installed, ZERO shape) LT child fexecve(memfd of loader) — no execve of a /data path loader ksud late-load → kernelsu ... Live

**La etapa 2 debe recibir explícitamente el valor de la etapa 1.** Las etapas 1 y 2 son dos
procesos independientes, cada uno con su propio spray, por lo que "escribir la página de credenciales en ambas
ranuras" es una trampa: leído ingenuamente produce `(pageA, pageB)`, y como
`commit_creds` compara **punteros**, ese par es divergente incluso cuando ambas escrituras
se realizan. Esto no es hipotético — es exactamente lo que hicieron las ejecuciones 3 y 9:```
run 9   0x778 shot  write value = 0xffffff88679bade0
        0x780 shot  write value = 0xffffff8785d6ade0     <- a different page
run 3   0x778 shot  write value = 0xffffff8787b5ade0
        0x780 shot  write value = 0xffffff881bad2de0     <- a different page

run_bootA.sh por lo tanto dispara la etapa 2 con V12_W7_VALUE=<valor observado de la etapa 1> y se niega a dispararla por completo si ese valor no puede recuperarse. HOLD debe sobrevivir a la etapa 2, o la página de la etapa 1 se libera y se reasigna y "el mismo valor" se convierte en un puntero colgante. Véase la regla del mismo valor.

Se repara una página por arranque. La etapa 3 pone a cero V+8. Con dos páginas diferentes, poner a cero ambas borraría el sello gid/suid (abajo) y haría que una divergencia pareciera un acuerdo, por lo que el ejecutor repara solo la página que realmente se instaló y se detiene si los dos valores no coinciden.

La página de credenciales es construida por payload.c: los ocho campos de id a cero, los cinco conjuntos de capacidades completos, y user / user_ns / group_info apuntando a root_user / init_user_ns / init_groups. La etapa 3 existe porque el efecto secundario de la escritura siempre sobrescribe cred+8 (gid/suid) de cualquier credencial que instale.

Sobre init_cred — una dicotomía explícita

Dos secciones aquí solían contradecirse entre sí ("nunca el init_cred global" vs "CONTROL=1 reproduce la celda 2", y la celda 2 es init_cred). Ambas afirmaciones son ciertas para roles diferentes:

  • Prohibido como objetivo. Escribir el puntero init_cred hace que el efecto secundario corrompa init_cred+8 globalmente — init_cred es compartido por cada hilo del kernel, y Uid: 0 0 4294967176 0 es precisamente esa corrupción. El código rechaza esta ruta a menos que V12_ALLOW_INIT_CRED=1 se establezca deliberadamente.
  • Retenido como el único par consistente PROBADO. La cadena 09-14 que alcanzó ksud escribió una dirección fija (0xffffff802a7e0be0) en ambas ranuras, por lo que real_cred == cred por construcción — es por eso que sobrevivió hasta execve. CONTROL=1 lo reproduce. Es un control, no una configuración sobre la que construir.

fuga de perf: PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_CLOCK, PERF_SAMPLE_REGS_INTR, exclude_user=1. Aceptar [0xffffff8400000000, 0xffffff90000000), votos ≥ 15%.

La primitiva de escritura, y su efecto secundario

Descargar herramienta