
GhostLock (CVE-2026-43499) exploit de kernel para dispositivos Android con bootloader bloqueado
Exploit de kernel para dispositivos Android con bootloader bloqueado. Logra root temporal + instalación de KernelSU sin desbloquear el bootloader ni modificar la imagen de arranque. Detección automática en tiempo de ejecución de la versión del kernel con tabla de offsets multi-dispositivo.
CVE-2026-43499 — Futex PI (Priority Inheritance) Use-After-Free
Afecta al kernel de Linux 5.7 ~ 7.1. Corregido en las versiones estables 6.1.175, 6.6.140, 6.12.86. La mayoría de los dispositivos Android permanecen sin parchear a septiembre de 2026.
La llamada al sistema pselect6 copia datos de fd_set en la pila del kernel. Cuando se combina con el mecanismo de espera futex PI, un marco de pila liberado puede ser reclamado como una estructura rt_mutex_waiter. El rebalanceo del rb-tree durante el recorrido de la cadena PI escribe entonces valores controlados en direcciones arbitrarias del kernel.
La superposición de pila de pselect requiere que el rt_mutex_waiter liberado aterrice dentro de la región stack_fds controlable por el usuario (words 0–14). Dónde aterriza está determinado por los perfiles PGO/LTO del compilador, no por la versión del kernel. Ver Diseño de la Pila.
Nota sobre factibilidad en 6.1: Los kernels OPLUS 6.1 son consistentemente no factibles debido a que PGO inlinea
do_futex. Sin embargo, algunos kernels no-OPLUS 6.1 (vivo) conservan la cadena de llamadas estándar y son factibles (vivo T4, X Fold3 Pro). La factibilidad debe comprobarse por dispositivo.
Dos rutas de root, seleccionadas automáticamente según las capacidades del dispositivo:
Requiere off_ashmem_misc_fops != 0 (C ashmem con miscdevice estático en BSS).
Escritura PI (modo=4) → redirigir fops de miscdevice a fops falsos
→ r/w configfs → physrw de tubería (r/w de kernel preciso de 1 byte)
→ SELinux enforcing = 0 (byte único, sin corrupción de policycap)
→ UMH: inyectar work_struct en system_unbound_wq
→ script de root → carga tardía de ksud → KSU instalado
Disponible en: OnePlus 13, OPPO Pad 4 Pro, dispositivos C ashmem 5.10/6.1. No disponible en Rust ashmem (GKI 6.12) — miscdevice asignado en heap.
Escritura 1 (modo=1) → SELinux enforcing = 0 (escritura de 8 bytes, corrompe bytes adyacentes)
Escritura 2 (modo=2) → task->cred = init_cred (uid=0, todas las capacidades)
Shell de root → carga tardía de ksud → KSU → corrección de política SELinux
Después de W1+W2, el exploit parchea el campo de configuración del binario de política SELinux (|= 0xC0000000 para ANDROID_NETLINK_ROUTE + GETNEIGH) y lo recarga vía /sys/fs/selinux/load para restaurar la conectividad de red.
App (seccomp) → Escritura 1 → mini-adb TCP → adb shell: exploit completo → root
El lanzador de arranque lo proporciona la aplicación separada GhostLock Anchor.
Con NFDS=320, core_sys_select asigna un buffer stack_fds de 256 bytes en la pila del kernel:
stack_fds: 0 5 10 14 | 15 20 25 29
├─in─┤─out─┤─ex──┤ ├res_in┤res_out┤res_ex┤
◄── CONTROLADO POR USUARIO ──►│◄── CERO DEL KERNEL ──►
El exploit coloca campos falsos de waiter (task, lock) en los mapas de bits de entrada de fd_set. Para waiter anidado 6.12 (14 words): word de waiter máxima factible = 3. Para waiter compacto 5.10/6.1 (10 words): word de waiter máxima factible = 7.
La posición del waiter depende de la profundidad de la cadena de llamadas:
Todas las escrituras al kernel usan el alias de mapa lineal. El bootloader elige kernel_phys_load, que varía según el SoC:
| SoC | kernel_phys_load |
|---|---|
| SM8845 (Ace 6T, 15T) | 0xa8000000 |
| SM8750 (OnePlus 13, OPPO Pad 4 Pro) | 0xa8000000 |
Un valor incorrecto falla silenciosamente. Léelo en una unidad con root:
su -c 'grep -i "Kernel code" /proc/iomem' # c7810000-... → 0xc7800000
Anulación en tiempo de ejecución: KPHYS=0xc7800000 /data/local/tmp/a/e
/data/local/tmp/a/e # Predeterminado (shift=0)
PSELECT_SHIFT=-2 /data/local/tmp/a/e # OnePlus 13 (6.6)
Los kernels 5.10 usan 0xffffffc008000000 (VA_BITS=39, diferente del valor predeterminado 6.x 0xffffffc080000000). Esto se maneja automáticamente mediante el campo kimage_text_base en la entrada de offsets del dispositivo.
make NDK_ROOT=/ruta/al/android-ndk
O directamente:
NDK=/ruta/al/android-ndk
"$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android35-clang" \
-O2 -Wall -Isrc/core -Isrc/devices -DTARGET_CONFIG_H=\"target.h\" \
src/core/main.c src/core/util.c src/core/slide.c \
src/core/fops.c src/core/pipe_physrw.c src/core/root.c \
src/core/miniadb.c src/core/umh_root.c \
-o ./ghostlock -fPIE -pie -pthread
GhostLock proporciona root temporal. La instalación de KernelSU requiere ksud, que incluye kernelsu.ko para cada versión de KMI.
| Método | Pasos |
|---|---|
| APK ReSukiSU (recomendado) | Instala ReSukiSU o este . Incluye . |
adb shell mkdir -p /data/local/tmp/a
adb push ./ghostlock /data/local/tmp/a/e
adb shell chmod 755 /data/local/tmp/a/e
adb shell /data/local/tmp/a/e
Ejecutar después de que el arranque se complete y ADB esté listo.
Solo se necesita boot.img — sin root, sin acceso al dispositivo.
Consulta la guía de herramientas kallsyms para el flujo de trabajo completo, o:
python tools/extract_target.py --kallsyms kallsyms.txt
python tools/extract_btf.py kernel
Comprueba si do_futex está inlineado por PGO buscando en el binario del kernel todas las instrucciones de salto dirigidas a futex_wait_requeue_pi. Si __arm64_sys_futex lo llama directamente (omitiendo do_futex), es probable que el dispositivo no sea factible.
Añade src/devices/<nombre>/offsets.h con los offsets extraídos e inclúyelo en src/devices/offsets.h. Usa la macro de offsets de estructura apropiada:
Para dispositivos con waiter compacto 5.10/6.1, también establece .kimage_text_base=0xffffffc008000000ULL.
Solo para investigación de seguridad autorizada y fines educativos.
| Dispositivo | SoC | Kernel | Rama GKI | SHIFT |
|---|
| OnePlus Ace 6T (PLR110) | SM8845 | 6.12.38 | android16-5 | 0 |
| OnePlus 15 (CPH2745/2747/2749) | SM8850 | 6.12.23 | android16-5 | 0 |
| Xiaomi 17 (pudding) | SM8850 | 6.12.23 / 6.12.69 | android16-5 / android16-6 | 0 |
| OnePlus 13 (IN2060) | SM8750 | 6.6.89 | android15-8 | -2 |
| OPPO Pad 4 Pro | SM8750 | 6.6.89 | android15-8 | -2 |
| Dispositivo | SoC | Kernel | Notas |
|---|
| OnePlus 15T (PLZ110) | SM8845 | 6.12.38 | Mismo kernel que Ace 6T |
| OPPO Reno10 Pro+ (CPH2521) | SM8475 | 5.10.236 | Waiter compacto 5.10, waiter word=0 |
| Vivo X Fold3 Pro (PD2337) | SM8650 | 6.1.124 | Waiter compacto 6.1, waiter word=3 |
| Vivo T4 | SM8650 | 6.1.145 | Waiter compacto 6.1, waiter word=3 |
| Dispositivo | SoC | Kernel | Causa Raíz |
|---|
| OPPO Find X9 Ultra | SM8750 | 6.12.58 | PGO elimina do_futex → waiter word=14 |
| OnePlus 12 | SM8650 | 6.1.141 | PGO inlinea do_futex → waiter word=13/19 |
| OnePlus 13R / Ace 5 | SM8650 | 6.1.x | OPLUS 6.1: waiter word=13 |
| realme RMX5070 | SM6650 | 6.1.141 | OPLUS 6.1: waiter word=13 |
| OPPO Pad 5 (OPD2502) | MT6878 | 6.1.134 | OPLUS 6.1: waiter word=13 |
| Motorola Edge 60 Fusion | MT6878 | 6.1.145 | No-OPLUS 6.1: mismo resultado |
| iQOO Neo 10 CN | SM8650 | 6.1.84 | Marco do_futex 0xD0 → waiter word=-11 |
| OPPO PKW110 | — | 5.15.180 | Marco do_futex 0x140 → waiter word=-29 |
| iQOO Z9 5G | — | 5.15.178 | Marco do_futex demasiado grande |
| CPH2763 (OPPO) | — | 6.1.115 | OPLUS 6.1: PGO inlineado, waiter word=24 |
| Patrón | Cadena de Llamadas | Factible |
|---|
| android16-5 (6.12) | sys_futex → do_futex → fwrpi | ✅ waiter word=2 |
| android15-8 (6.6) | sys_futex → do_futex → fwrpi | ✅ waiter word=2 (SHIFT=-2) |
| vivo 6.1 | sys_futex → do_futex → fwrpi | ✅ waiter word=3 |
| OPLUS 6.1 | sys_futex → fwrpi (PGO inlineado) | ❌ waiter word=13+ |
| android16-6 (X9 Ultra) | sys_futex → fwrpi (PGO inlineado) | ❌ waiter word=14 |
| 5.10 OPLUS | sys_futex → do_futex → fwrpi | ✅ waiter word=0 |
| SM8650 (vivo T4, X Fold3 Pro) |
0xa8000000 |
| SM8850 (OnePlus 15, Xiaomi 17) | 0xc7800000 |
libksud.so| Lanzamiento CI | Descárgalo desde ReSukiSU CI |
| Kernel | Diseño del Waiter | Macro |
|---|
| 6.12.x | Anidado (14 words) | STRUCT_OFFSETS_6_12 |
| 6.6.x | Anidado (14 words) | STRUCT_OFFSETS_6_6 |
| 6.1.x (vivo) | Compacto (10 words) | STRUCT_OFFSETS_6_1 |
| 5.10.x | Compacto (10 words) | STRUCT_OFFSETS_5_10 |
| Archivo | Descripción |
|---|
src/core/main.c | Entrada del exploit, W1/W2, ruta UMH, bootstrap, script de root, corrección de política SELinux |
src/core/fops.c | Ruta pselect, escritura PI, etapa CFI, soporte de waiter compacto |
src/core/util.c | Heap spray, KernelSnitch, drenaje de slab, configuración de payload |
src/core/pipe_physrw.c | r/w de memoria física del buffer de tubería |
src/core/umh_root.c | Root UMH mediante inyección de workqueue |
src/core/miniadb.c | Cliente Mini ADB (TCP + autenticación RSA) |
src/core/target.h | Diseño de memoria, valores predeterminados de campos de estructura (6.12) |
src/core/runtime_struct_offsets.h | Anulación de campos de estructura por dispositivo |
src/devices/offsets.h | Tablas de offsets de dispositivos + macros STRUCT_OFFSETS_* |
tools/extract_target.py | Extracción de offsets desde kallsyms |
tools/extract_btf.py | Extracción de offsets de estructura desde BTF |
tools/kallsyms/ | Flujo de trabajo completo de recuperación de kallsyms |