Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-98260 — Android kernel LPE research for CVE-2026-98260 (posix-cpu-timers UAF): trigger PoC, fake-cred and real-cred uid-0 shell chains, plus a Shizuku/KernelSU bootstrap app. | Kitploit
工具/GitHubGitHub/woshigenm/cve-2026-98260
Android SecurityPrivilege EscalationMemory ForensicsExploitationPost-ExploitationMobile SecurityPayload DevelopmentBinary Exploitation
GitHubwoshigenm/cve-2026-98260

CVE-2026-98260

Android kernel LPE research for CVE-2026-98260 (posix-cpu-timers UAF): trigger PoC, fake-cred and real-cred uid-0 shell chains, plus a Shizuku/KernelSU bootstrap app.

4415天前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
查看仓库

CVE-2026-98260 — exec 失败后的 posix-cpu-timers UAF

English | 简体中文

Android 本地提权研究。漏洞位于 posix-cpu-timers 的退出路径:非 leader 线程 execve() 失败后,已排队的 timer 节点没有被摘除,父进程回收 zombie 时 cleanup_timerqueue() 会对已释放的 k_itimer 执行 rb_erase()。

仓库包含:仅触发的 PoC、fake-cred 验证型 EXP、真实 cred 的 uid-0 shell、 基于 Shizuku 的 KernelSU 提权 App,以及漏洞 pre-check。

分支 magicos-11.0.0.109-6.12.58: 当前分支是双 profile。APK 和 native 二进制在运行时按精确 uname -r 选择 profile:MagicOS 10.0.0 / 6.12.38 是已验证 profile,MagicOS 11.0.0.109 / 6.12.58 是静态适配、 设备端运行验证仍待完成。APK 同时打包两套 226 条 ko-syms 表,并按 内核版本选择。

一览

项目值
CVECVE-2026-98260
类型LPE(use-after-free,timerqueue rb-tree erase)
目标荣耀 MagicPad3 Pro 13.3 YLP-W00,MagicOS 10.0.0 / 11.0.0.109(Android 16),分支 magicos-11.0.0.109-6.12.58
内核6.12.38-android16-5-gfde7767f6ef6-abogki481467632-4k(已验证)
6.12.58-android16-6-g3a7ac1674240-abogki541502914-4k(已适配)
profile 状态双 profile;6.12.38 已验证,6.12.58 运行时验证待做
SELinuxEnforcing
补丁测试构建上不存在
缓解措施KASLR 开,SMEP/SMAP/PAN 开,KASAN 编译但未启用
Bootloader锁定且不可解锁;不写任何分区
组件状态结果
src/poc.c已在 6.12.38 验证破坏性触发;reap 在 cleanup_timerqueue 中 panic
src/exp.c已在 6.12.38 验证fake cred;getuid()==0 && geteuid()==0;不能 exec
src/uid0.c已在 6.12.38 验证真实 cred;uid-0 shell,u:r:shell:s0
app/已在 6.12.38 验证Shizuku + KernelSU 引导;uid 0,u:r:ksu:s0
src/vuln_precheck.h已加入profile/环境门禁;--check / --force
6.12.58 profile已适配分配点、selinux_state 和对应 226 条 ko-syms 表已重提取;设备运行待做
双 profile APK已在 6.12.38 测试按 uname -r 选择 profile 和 ko-syms;6.12.38 live-KSU 路径通过

当前 release: v1.4.3-app。 v1.4.2-app pre-release 已于 2026-10-30 撤下,其 tag 仅作历史保留。发布记录 与已知缺口见 docs/release-notes.md。

仓库结构

src/poc.c              仅触发;在测试内核上 reap 会 panic
src/exp.c              fake-cred 链;用 getuid/geteuid 验证 uid 0
src/uid0.c             真实 cred 链;清零 cred->uid/gid 后 exec sh
src/kernel_profile.h   各 release 的分配点、符号和结构偏移
src/trace_ids.h        运行时 kmem trace event ID;无 root 探测
src/vuln_precheck.h    共享的 profile/环境 pre-check
app/                   Android 提权 App(Shizuku + KernelSU 引导)
docs/analysis.md       根因、利用链与设备数据
scripts/dump_device.sh  设备端全量导出(全部 .ko/modinfo、kernel/config/policy、perf/tracefs、vendor mount、harness、活动分区 boot.img)
Makefile               唯一构建入口(NDK 交叉编译、App APK)
README.zh-CN.md        本文

根因

非 leader 线程创建了 CLOCK_THREAD_CPUTIME_ID posix timer,随后在 de_thread() 之后 execve() 失败。打断 exec 的 SIGKILL 让线程走 exit_itimers(),但此时 task 已经在退出,timer 无法被 disarm。 k_itimer 被释放时,它的 timerqueue_node 仍留在该 task 的 posix_cputimers 队列里。父进程回收 zombie 时:

release_task()
  -> posix_cpu_timers_exit()
     -> cleanup_timerqueue()
        -> timerqueue_del() / rb_erase(stale node)

rb_erase() 就是写原语:它把可控的 __rb_parent_color 写到可控的 rb_left 目标。利用链通过 slab/页回收编排,让已释放的 stale node 落在 被 payload 填满的页上,再选择目标地址和写入值。

更详细的 panic 栈、YLP-W00 偏移、tracefs 泄漏、SLUB/RCU 编排、两次 reap 的 fake-cred 链和一次 reap 的 real-cred 链见 docs/analysis.md。

构建

依赖 Android NDK r29(/opt/android-ndk-r29,可用 NDK= 覆盖),目标默认 arm64/API 24。App 额外需要 Android SDK(build-tools 37.0.0、platform 37)、 JDK,以及 ~/.local/share/android-cve-env/cve98260-app 下的 Shizuku jars (可用 APP_DEPS= 覆盖)。编译产物只写 build/,已被 git 忽略。Shizuku jars 由用户自备;scripts/fetch-deps.sh 按 deps.lock 校验 SHA-256,不做 任何下载。

目标输出 / 行为
make / make pocbuild/poc
make expbuild/exp
make uid0build/uid0(静态;shell 阶段会 re-exec 自己)
make build-all构建 poc + exp + uid0 + apk
make hostbuild/poc.static,用于 host 侧 qemu 验证
make emu在 qemu 下运行 build/poc.static(带 --force)
make apkapp/CVE98260Root.apk
make clean删除 build/
make help列出目标

漏洞 pre-check

poc、exp、uid0 在接触内核之前都会先过 profile 门禁:

  • 只接受 kernel_profile.h 中的精确 release(6.12.38 已验证,6.12.58 已静态适配);
  • 要求 arm64 + 4 KiB 页;
  • exp/uid0 还检查 tracefs/kmem 是否可用;
  • exp 的 fake-cred 链还要求 panic_on_warn=0。

其他 release 一律视为“未确认”,程序退出码为 2:

build/uid0 --check          # 只打印结论,不触发漏洞
build/uid0 --check --force  # 对未确认环境放行,只做检查

只有独立验证过内核后,才使用 --force 或 CVE98260_FORCE=1。--force 只放宽环境检查;exp、uid0 和 App 仍必须匹配 kernel_profile.h 中的 精确 profile。这个门禁故意不做“运行时探测”:任何真正走到 bug 路径的探测 都会留下 stale timerqueue node,而回收它就是破坏性步骤。

在 YLP-W00 上,普通 shell 读不到 /proc/sys/kernel/panic_on_warn 和 /proc/cmdline;对已知 profile,pre-check 在不可读时沿用 6.12.38 的已验证 值 0;6.12.58 在完成实测前也沿用该假设,未知 profile 仍拒绝。

用法:uid-0 shell

利用程序以普通 shell 进程启动(uid 2000,SELinux u:r:shell:s0),不使用 su。不要通过 su 启动:测试前提就是非特权启动。

make uid0
adb push build/uid0 /data/local/tmp/uid0
adb shell chmod 755 /data/local/tmp/uid0
adb shell /data/local/tmp/uid0          # 打印 id 和 context
adb shell /data/local/tmp/uid0 shell    # 交互式 sh -i

完整利用前先用非破坏性模式:

adb shell /data/local/tmp/uid0 --probe-ids  # 探测 kmem trace event ID
adb shell /data/local/tmp/uid0 leak         # 只做 timer/cred 泄漏,不触发 UAF

kmem trace event ID 在启动时分配,跨内核构建不稳定(6.12.38 是 318/319/322/324)。--probe-ids 通过可写的 rss_stat/trigger 一次只启用 一个事件,从 raw trace 反查 ID;正常运行也会自动探测。leak 会打印 [base]、完整的 timer_site/slide 和 cred 分配点,不会进入 run_plant()。

root 是静态链接的,子进程会通过 /proc/self/exe 重新执行自己来获得私有的 真实 cred,因此它必须留在 push 的路径上。

成功时输出以这些行结束:

[child] woke uid=0 euid=2000
[child] setuid(0)=0 errno=0 resuid=0/0/2000
uid=0(root) gid=0(root) groups=0(root),...
context=u:r:shell:s0
ROOT_SHELL_OK

如果 adb 会话可能中断,请用 detached 方式启动。parked 进程绝不能被 kill(见“限制”):

adb shell 'setsid /data/local/tmp/uid0 >/data/local/tmp/uid0.log 2>&1 &'

任何未验证状态(victim slab 未释放、目标页被其他分配抢走、reap 状态不符) 都会选择 park 而不回收:对 stale node 的不可控回收会 panic 内核。launcher 现在由 lifecycle.h 放进独立 session、忽略 SIGPIPE,并有一个 PR_SET_CHILD_SUBREAPER keeper;关闭管道/adbd 组杀不得杀死 zombie owner。 若出现 PARKED=1,不要把重启当作干净清理:关机路径仍可能回收僵尸并 panic。

用法:Root App

app/ 是一个 Android UI,通过普通 Shizuku shell 在 YLP-W00 上引导 KernelSU。它复用同一套利用核心作为 native 库,src/poc.c 和 src/exp.c 保持不动。界面只保留必要操作:授权 Shizuku、部署资产、开始提权、清理临时 文件、导出/复制当前日志。

make apk        # -> app/CVE98260Root.apk
adb install -r app/CVE98260Root.apk

典型流程:

  1. 启动 Shizuku(adb/root),点 1. 授权 Shizuku;
  2. 点 2. 部署资产,把 launcher、脚本和 libmagicroot.so 部署到 /data/local/tmp/cveapp;
  3. 点 3. 开始提权。干净启动时执行完整 KernelSU 引导;如果 kernelsu 已经加载,则只检查 su -c id。

开始提权会清空上一次“授权/部署”在界面留下的日志,远程 run.sh 的 stdout 直接流式显示;native worker 另外追加 /data/local/tmp/cve98260-worker-<pid>.log,管道关闭也不会丢失记录。 导出日志会覆盖 /sdcard/MagicRoot.log。任务运行期间前四个按钮禁用, 任务结束后恢复。

这个 App 是 YLP-W00 专用的:它依赖管理器里的 KMI 模块、随包的 ko-syms-6.12.38.txt / ko-syms-6.12.58.txt 和所选 profile 的 selinux_state 地址,不是通用一键 root。App 的 native 库已在进入链路前 调用 src 里的共享 pre-check;live 分支先执行 magicroot --check。

Shell 阶段原理

src/uid0.c 保留 exp.c 的触发、泄漏和页回收,但不再伪造 cred。子进程 exec 本二进制,prepare_exec_creds() 会通过 cred_jar 分配一个私有的真实 cred R(trace 特征:type 318、call-site low21 在 6.12.38 为 0x18a248、 在 6.12.58 为 0x19c474,bytes_req 0xb8、bytes_alloc 0xc0)。子进程阻塞在 pipe 上,父进程用只含零写的 payload reap stale node:

[R + 8] = 0        # cred->uid / cred->gid

cred->uid 变成 0 后,子进程调用 setuid(0):kuid == old->uid,不需要 CAP_SETUID,内核把 euid/fsuid 置 0。此时 cred == real_cred 仍成立, SELinux blob 是 exec 时分配的真实 blob,因此 execve("/system/bin/sh") 可以通过 commit_creds(),最终运行在 u:r:shell:s0。

exec 的 capability fixup 只按 bounding set 重算(本机是 CAP_SETGID、 CAP_SETUID、CAP_SYS_NICE),所以 shell 没有 CAP_DAC_OVERRIDE。 这是真正的 uid-0 shell,但不是不受限制的系统 root,SELinux 仍把它限制在 shell 域。

make run 执行的是破坏性 PoC。在 YLP-W00 上它会在 6 秒后 reap,预期 panic; QCOM watchdog 大约 40–50 秒后重启,临时 root(如果有)随之丢失。

App 的 KernelSU 引导流程

干净启动(没有 kernelsu 模块)时,点 开始提权 会依次执行:

下载工具