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

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

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

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-98937 — Verified PoC and analysis for a Linux perf/core permission-check bypass that leaks kernel callchain addresses to unprivileged Android tasks, enabling KASLR slide derivation. | Kitploit
工具/GitHubGitHub/woshigenm/cve-2026-98937
Android SecurityPrivilege EscalationVulnerability AnalysisExploitationInformation GatheringPapers & Research
GitHubwoshigenm/cve-2026-98937

CVE-2026-98937

Verified PoC and analysis for a Linux perf/core permission-check bypass that leaks kernel callchain addresses to unprivileged Android tasks, enabling KASLR slide derivation.

查看仓库
426天前尚未审核

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-98937 — perf 内核调用栈权限绕过

English | 简体中文

Linux perf/core 权限检查绕过:非特权进程可以在设置 exclude_kernel=1 的 同时请求内核调用栈,跳过 perf_allow_kernel() 门禁,并通过 perf ring buffer 读取内核栈帧。本仓库包含分析与已验证的 PoC;该漏洞只构成信息泄露, 不提供直接提权原语。

状态

项目值
CVECVE-2026-98937
类型权限绕过 / 信息泄露(CWE-284/CWE-269)
目标Android arm64(已在 HONOR YLP-W00 与 Redmi K70 验证)
内核YLP-W00:6.12.38-android16-5-gfde7767f6ef6-abogki481467632-4k;K70:5.15.178-android13-8-00021-g6f2f96be86b9-ab13729987
SELinuxEnforcing(u:r:shell:s0)
补丁缺失;上游修复于 6.12.113 / 6.18.56 / 7.2.10 / 7.3+
状态PoC 已验证;6.12.38 与 5.15.178 上验证 KASLR slide oracle
pre-checksrc/vuln_precheck.h

影响范围

修复前的内核均受影响。上游修复提交为 a4b016d0a29038a5b7c96bf62c054bf7832451d9 ("perf/core: Check kernel access when kernel callchains are requested", Dapeng Mi,2026-06-30 合入),并有对应的稳定版回移。

根因

旧版 perf_event_open() 仅根据 !attr.exclude_kernel 决定是否调用 perf_allow_kernel():

if (!attr.exclude_kernel) {
        err = perf_allow_kernel(&attr);
        if (err)
                return err;
}

perf_allow_kernel() 同时承载 perf_event_paranoid > 1 检查与 SELinux perf_event { kernel } 钩子。进程可以设置 exclude_kernel=1,同时保留 PERF_SAMPLE_CALLCHAIN 且 exclude_callchain_kernel=0;perf_callchain() 对内核部分的采集不受采样过滤影响。只统计用户态的硬件 PMU 事件可能因 skid 在内核上下文投递溢出中断,perf_callchain_kernel() 随即展开内核栈, 把内核文本地址写入 ring buffer。

修复后,只要请求内核采样或内核调用栈,都必须经过 perf_allow_kernel():

if (!attr.exclude_kernel ||
    ((attr.sample_type & PERF_SAMPLE_CALLCHAIN) &&
     !attr.exclude_callchain_kernel)) {
        err = perf_allow_kernel();
        if (err)
                return err;
}

上面的修复片段是 6.12.113 稳定树形态(perf_allow_kernel() 已改为无参); 上游提交使用相同条件,调用形式为 perf_allow_kernel(&attr)。

完整的调用链、skid 机制、SELinux 审计证据和设备测量见 docs/analysis.md。

验证设计

POC 以非特权 shell 进程运行三组用例:

用例perf_event 属性漏洞内核上的预期
Aexclude_kernel=0EACCES(内核剖析门禁生效)
Bexclude_kernel=1, exclude_callchain_kernel=1允许打开,内核调用栈帧为 0
Cexclude_kernel=1, exclude_callchain_kernel=0允许打开,并泄露内核调用栈帧

在已验证的 YLP-W00(内核 6.12.38,SELinux Enforcing)上:

  • 用例 A:EACCES,审计日志出现 avc: denied { kernel } ... tclass=perf_event。
  • 用例 B:事件打开成功,内核 callchain 帧为 0。
  • 用例 C:事件打开成功,约 17.9 万个内核上下文样本、约 53.7 万个内核 callchain 地址(每样本 3 帧),全部位于 0xffffffde... 内核区间。

在已验证的 Redmi K70(内核 5.15.178,第三方 Android 17 ROM, SELinux Enforcing)上观察到同样的模式:

  • 用例 A:EACCES,同样的 SELinux { kernel } 审计行。
  • 用例 B:事件打开成功,内核 callchain 帧为 0。
  • 用例 C:事件打开成功;周期 1000 时 2432 个样本、14090 个内核 callchain 地址;周期 5000 时 876 个样本、5049 个地址,均位于 0xffffffdd... 内核区间。

在已验证设备上,修复后的内核会在 perf_event_open() 阶段对用例 C 返回 EACCES,因为内核调用栈请求现在会进入 perf_allow_kernel()。

KASLR slide 推导

持有匹配 vmlinux 时,泄漏的 callchain 帧可以变成每次启动的 KASLR slide oracle。arm64 虚拟 slide 按 2 MiB 对齐,且每个泄漏的文本地址必须满足 _stext <= addr - slide < _etext;对这些区间求交通常只剩一个 slide。

make slide \
  SLIDE_VMLINUX=/path/to/vmlinux-6.12.38.elf \
  SLIDE_LINK_BASE=0xffffffc080000000 \
  SLIDE_LOG=logs/poc-ylp-w00-20261027-020133-period1000.log

在已验证的 YLP-W00 6.12.38 启动上,三个帧给出唯一 slide=0x1DCFC00000(运行期 _text=0xffffffde4fc00000):

泄漏地址链接期地址符号
0xffffffde50748c780xffffffc080b48c78local_daif_restore+0x4(msr DAIF, x0; ret)
0xffffffde50d406e00xffffffc0811406e0el0t_64_sync_handler+0x70(bl el0_svc 之后)
0xffffffde4fc115880xffffffc080011588el0t_64_sync+0x1a8(bl el0t_64_sync_handler 之后)

这三帧是核心内核文本,不是模块:pending PMU 中断正好在 syscall 入口 local_daif_restore 执行 msr DAIF, x0 后的 ret 处投递。KASLR 下裸地址 不能直接符号化,必须先减 slide。若某帧是模块地址,没有任何 slide 能让所有 地址落在 [_stext, _etext),脚本会报错而不是猜一个值。slide 每次启动变化, 不能跨重启缓存。

Redmi K70(5.15.178)也已验证。匹配镜像来自 /sdcard/boot.img (boot v4;镜像内版本字符串与运行内核一致),vmlinux-to-elf 恢复出 158668 个符号。其中一次周期 1000 运行的 7 个唯一帧给出 slide=0x1D93800000(runtime _text=0xffffffdd9b800000),符号为 syscall_trace_enter、el0_svc_common、do_el0_svc、el0_svc、 el0t_64_sync_handler、el0t_64_sync、syscall_trace_exit。

链接基址与分支相关,不能把 6.12 的值用在 5.15 上:

内核分支KIMAGE_VADDR
Android 13-5.15(K70)0xffffffc008000000
Android 16-6.12(YLP-W00)0xffffffc080000000
torvalds v5.15(布局不同)0xffffffc010000000

vmlinux-to-elf 对 K70 镜像自动检测出的基址 0xffffffc008000000 与 AOSP android13-5.15 一致。若自动基址与分支的 KIMAGE_VADDR 不同,用 --link-base(或 SLIDE_LINK_BASE=)覆盖:符号化仍使用 ELF 相对偏移, slide 按真实链接基址报告,runtime _text 对常数基址偏移不变。把 K70 的 泄漏喂给 6.12.38 镜像仍是故意的负向测试,结果应为无候选。

构建

要求:

  • Android NDK r29,位于 /opt/android-ndk-r29(可用 NDK= 覆盖)
  • GNU make
  • adb
make                 # PoC,arm64,API 24
make ARCH=arm API=29 # 其他 ABI / API
make host            # qemu-aarch64 静态构建
make emu             # host 静态构建并运行
make help

产物写入 build/,已被 git 忽略。

用法

make check                         # push 并执行只读环境 pre-check
make run                           # push 并执行完整三组验证

# 直接运行
adb push build/poc /data/local/tmp/poc
adb shell chmod 755 /data/local/tmp/poc
adb shell /data/local/tmp/poc --check
adb shell /data/local/tmp/poc --duration 2 --period 1000

参数:

--check         只做 pre-check,不打开 perf 事件
--force         在未列出的内核 release 上强制运行
--duration N    每例采样秒数(默认 2)
--period N      采样周期(cycle,默认 1000)

退出码:

退出码含义
0漏洞存在:门禁被绕过且观测到内核调用栈帧
2pre-check 拒绝(未知内核 release 或环境门禁失败)
3不确定:事件已打开但未采到内核帧
4open 阶段被拒(已修复或策略强制)
5本机本来就允许内核剖析,无权限边界可绕过
6环境错误(无可用硬件 PMU 事件、异常 errno)

使用 --check 时,退出码 0 表示 profile 门禁允许继续,2 表示拒绝;不会打开 任何 perf 事件。

POC 只读取硬件采样数据,不写内核状态、不修改 sysctl、不重启设备。

要求与限制

  • 需要可用的硬件 PMU 事件(cycles/instructions)。exclude_kernel=1 的软件事件会在内核态被过滤,无法走 skid 路径。
  • 仅验证 shell 域(uid 2000)。untrusted_app 是否拥有 perf_event { open } 取决于厂商策略;本次未构建 APK 验证。
  • 两台已验证设备均为 kptr_restrict=2,无法在设备上符号化;泄漏地址 通过高半区范围和内核态标志交叉验证。
  • POC 不修改 perf_event_paranoid;两台设备实际生效的门禁都是 SELinux。 被跳过的函数同时包含 paranoid 检查,因此 perf_event_paranoid >= 2 时 同样可绕过。
  • K70 内核构建于 2025-07-02,早于修复;5.15 stable 分支的具体修复版本 未逐项核对。
  • slide 推导需要 python3、nm、该 release 的精确匹配 vmlinux,以及该 分支真实的 KIMAGE_VADDR;slide 每次启动变化。6.12.38 与 5.15.178 均 已验证。6.12.58 已按版本加入 pre-check,设备端运行时验证待升级后进行。

仓库结构

.
├── Makefile             # 构建入口(NDK 交叉编译)
├── README.md
├── README.zh-CN.md      # 中文版
├── LICENSE
├── src/
│   ├── poc.c            # 三组差分验证 POC
│   └── vuln_precheck.h  # 内核 release / 环境门禁
├── scripts/
│   └── slide-from-leak.py  # 从泄漏文本地址推导 KASLR slide
├── app/                 # 可选 Android App(本仓库未使用)
├── docs/
│   └── analysis.md      # 根因、补丁、测量记录
├── logs/                # 运行时日志(git 忽略)
├── dump/                # 拉取的 config/policy/二进制(git 忽略)
└── build/               # 构建产物(git 忽略)

相关环境状态

项目已验证设备状态
KASLR开启(CONFIG_RANDOMIZE_BASE=y,CONFIG_ARM64_VA_BITS=39);泄漏可作为每次启动的 slide oracle
帧指针开启(CONFIG_FRAME_POINTER=y);内核 callchain 展开使用帧指针
SELinuxEnforcing;shell 域 perf_event { kernel } 被拒
perf_event_paranoid-1(厂商设置);实际门禁是 SELinux
kptr_restrict2;无法在设备上符号化

免责声明

仅用于授权的安全研究和教育。不要对不拥有或未获明确许可的设备使用。

License

MIT,见 LICENSE。

下载工具