
GhostLock (CVE-2026-43499) exploit noyau pour appareils Android avec bootloader verrouillé
Exploit noyau pour appareils Android avec bootloader verrouillé. Obtient un root temporaire + installation de KernelSU sans déverrouiller le bootloader ni modifier l'image de boot. Détection automatique au runtime de la version du noyau avec table d'offsets multi-appareils.
CVE-2026-43499 — Futex PI (Priority Inheritance) Use-After-Free
Affecte les noyaux Linux 5.7 ~ 7.1. Corrigé dans les versions stables 6.1.175, 6.6.140, 6.12.86. La plupart des appareils Android restent non corrigés en septembre 2026.
L'appel système pselect6 copie les données fd_set sur la pile du noyau. Combiné au mécanisme d'attente futex PI, une trame de pile libérée peut être récupérée comme structure rt_mutex_waiter. Le rééquilibrage de l'arbre rb pendant la traversée de la chaîne PI écrit alors des valeurs contrôlées à des adresses noyau arbitraires.
Le chevauchement de pile pselect exige que le rt_mutex_waiter libéré atterrisse dans la région stack_fds contrôlable par l'utilisateur (mots 0–14). L'emplacement est déterminé par les profils PGO/LTO du compilateur, pas par la version du noyau. Voir Disposition de la pile.
Remarque sur la faisabilité 6.1 : Les noyaux OPLUS 6.1 sont systématiquement non réalisables en raison de l'inlining PGO de
do_futex. Cependant, certains noyaux non-OPLUS 6.1 (vivo) conservent la chaîne d'appels standard et sont réalisables (vivo T4, X Fold3 Pro). La faisabilité doit être vérifiée appareil par appareil.
Deux chemins de root, sélectionnés automatiquement selon les capacités de l'appareil :
Nécessite off_ashmem_misc_fops != 0 (C ashmem avec miscdevice statique dans BSS).
Écriture PI (mode=4) → redirige les fops miscdevice vers de faux fops
→ configfs r/w → pipe physrw (r/w noyau précis à 1 octet)
→ SELinux enforcing = 0 (octet unique, sans corruption policycap)
→ UMH : injection work_struct dans system_unbound_wq
→ script root → chargement tardif ksud → KSU installé
Disponible sur : OnePlus 13, OPPO Pad 4 Pro, appareils C ashmem 5.10/6.1. Non disponible sur Rust ashmem (GKI 6.12) — miscdevice alloué sur le tas.
Écriture 1 (mode=1) → SELinux enforcing = 0 (écriture 8 octets, corrompt les octets adjacents)
Écriture 2 (mode=2) → task->cred = init_cred (uid=0, toutes les capacités)
Shell root → chargement tardif ksud → KSU → correction de la politique SELinux
Après W1+W2, l'exploit corrige le champ config du binaire de politique SELinux (|= 0xC0000000 pour ANDROID_NETLINK_ROUTE + GETNEIGH) et recharge via /sys/fs/selinux/load pour restaurer la connectivité réseau.
App (seccomp) → Écriture 1 → mini-adb TCP → adb shell : exploit complet → root
Le lanceur au démarrage est fourni par l'application séparée GhostLock Anchor.
Avec NFDS=320, core_sys_select alloue un tampon stack_fds de 256 octets sur la pile du noyau :
stack_fds: 0 5 10 14 | 15 20 25 29
├─in─┤─out─┤─ex──┤ ├res_in┤res_out┤res_ex┤
◄── CONTRÔLÉ UTILISATEUR ──►│◄── ZÉRO NOYAU ──►
L'exploit place de faux champs waiter (task, lock) dans les bitmaps d'entrée fd_set. Pour le waiter imbriqué 6.12 (14 mots) : mot waiter maximal réalisable = 3. Pour le waiter compact 5.10/6.1 (10 mots) : mot waiter maximal réalisable = 7.
La position du waiter dépend de la profondeur de la chaîne d'appels :
Toutes les écritures noyau utilisent l'alias de carte linéaire. Le bootloader choisit kernel_phys_load, qui varie selon le SoC :
| SoC | kernel_phys_load |
|---|---|
| SM8845 (Ace 6T, 15T) | 0xa8000000 |
| SM8750 (OnePlus 13, OPPO Pad 4 Pro) | 0xa8000000 |
Une valeur incorrecte échoue silencieusement. Lisez-la sur une unité rootée :
su -c 'grep -i "Kernel code" /proc/iomem' # c7810000-... → 0xc7800000
Remplacement au runtime : KPHYS=0xc7800000 /data/local/tmp/a/e
/data/local/tmp/a/e # Défaut (shift=0)
PSELECT_SHIFT=-2 /data/local/tmp/a/e # OnePlus 13 (6.6)
Les noyaux 5.10 utilisent 0xffffffc008000000 (VA_BITS=39, différent du défaut 6.x 0xffffffc080000000). Ceci est géré automatiquement via le champ kimage_text_base dans l'entrée d'offsets de l'appareil.
make NDK_ROOT=/chemin/vers/android-ndk
Ou directement :
NDK=/chemin/vers/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 fournit un root temporaire. L'installation de KernelSU nécessite ksud qui regroupe kernelsu.ko pour chaque version KMI.
| Méthode | Étapes |
|---|---|
| APK ReSukiSU (recommandé) | Installez ReSukiSU ou ce . Regroupe . |
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
Exécutez après le démarrage complet et lorsque ADB est prêt.
Seul boot.img est nécessaire — pas de root, pas d'accès à l'appareil requis.
Voir le guide des outils kallsyms pour le flux complet, ou :
python tools/extract_target.py --kallsyms kallsyms.txt
python tools/extract_btf.py kernel
Vérifiez si do_futex est inliné par PGO en recherchant dans le binaire du noyau toutes les instructions de branche ciblant futex_wait_requeue_pi. Si __arm64_sys_futex l'appelle directement (en contournant do_futex), l'appareil n'est probablement pas réalisable.
Ajoutez src/devices/<nom>/offsets.h avec les offsets extraits et incluez-le dans src/devices/offsets.h. Utilisez la macro d'offsets de structure appropriée :
Pour les appareils à waiter compact 5.10/6.1, définissez également .kimage_text_base=0xffffffc008000000ULL.
Uniquement à des fins de recherche en sécurité autorisée et d'éducation.
| Appareil | SoC | Noyau | Branche 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 |
| Appareil | SoC | Noyau | Remarques |
|---|
| OnePlus 15T (PLZ110) | SM8845 | 6.12.38 | Même noyau que l'Ace 6T |
| OPPO Reno10 Pro+ (CPH2521) | SM8475 | 5.10.236 | Waiter compact 5.10, waiter word=0 |
| Vivo X Fold3 Pro (PD2337) | SM8650 | 6.1.124 | Waiter compact 6.1, waiter word=3 |
| Vivo T4 | SM8650 | 6.1.145 | Waiter compact 6.1, waiter word=3 |
| Appareil | SoC | Noyau | Cause racine |
|---|
| OPPO Find X9 Ultra | SM8750 | 6.12.58 | PGO élimine do_futex → waiter word=14 |
| OnePlus 12 | SM8650 | 6.1.141 | PGO inline 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 | Non-OPLUS 6.1 : même résultat |
| iQOO Neo 10 CN | SM8650 | 6.1.84 | Trame do_futex 0xD0 → waiter word=-11 |
| OPPO PKW110 | — | 5.15.180 | Trame do_futex 0x140 → waiter word=-29 |
| iQOO Z9 5G | — | 5.15.178 | Trame do_futex trop grande |
| CPH2763 (OPPO) | — | 6.1.115 | OPLUS 6.1 : PGO inline, waiter word=24 |
| Modèle | Chaîne d'appels | Réalisable |
|---|
| 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 inline) | ❌ waiter word=13+ |
| android16-6 (X9 Ultra) | sys_futex → fwrpi (PGO inline) | ❌ 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| Version CI | Téléchargez depuis ReSukiSU CI |
| Noyau | Disposition du waiter | Macro |
|---|
| 6.12.x | Imbriqué (14 mots) | STRUCT_OFFSETS_6_12 |
| 6.6.x | Imbriqué (14 mots) | STRUCT_OFFSETS_6_6 |
| 6.1.x (vivo) | Compact (10 mots) | STRUCT_OFFSETS_6_1 |
| 5.10.x | Compact (10 mots) | STRUCT_OFFSETS_5_10 |
| Fichier | Description |
|---|
src/core/main.c | Entrée de l'exploit, W1/W2, chemin UMH, bootstrap, script root, correction de politique SELinux |
src/core/fops.c | Route pselect, écriture PI, étape CFI, prise en charge du waiter compact |
src/core/util.c | Heap spray, KernelSnitch, drain de slab, configuration du payload |
src/core/pipe_physrw.c | Lecture/écriture mémoire physique du tampon pipe |
src/core/umh_root.c | Root UMH via injection workqueue |
src/core/miniadb.c | Client Mini ADB (TCP + authentification RSA) |
src/core/target.h | Disposition mémoire, valeurs par défaut des champs de structure (6.12) |
src/core/runtime_struct_offsets.h | Remplacement des champs de structure par appareil |
src/devices/offsets.h | Tables d'offsets appareils + macros STRUCT_OFFSETS_* |
tools/extract_target.py | Extraction d'offsets depuis kallsyms |
tools/extract_btf.py | Extraction d'offsets de structure depuis BTF |
tools/kallsyms/ | Flux de travail complet de récupération kallsyms |