适用于 OnePlus 15T 锁 Bootloader 设备的内核漏洞利用工具。利用 CVE-2026-43499 在不解锁 Bootloader、不修改 boot.img 的前提下获取 root 权限。
仅限授权的安全研究和教育用途。
本仓库修改自 GhostLock-for-OnePlus 源仓库,专门适配 OnePlus 15T (PLZ110 / SM8850 / 骁龙 8 Elite) 的物理内存布局和 CPU 时序。
| 项目 | 内容 |
|---|---|
| CVE | CVE-2026-43499 |
| 类型 | Futex PI(优先级继承)Use-After-Free |
| 影响范围 | Linux 内核 2.6.39 ~ 7.1 |
| 修复版本 | 主线内核 7.1(commit 3bfdc63936dd) |
| Android 状态 | GKI 6.12.x 仍未修复 |
pselect6 系统调用会将 fd_set 拷贝到内核栈上。当与 futex PI waiter 机制结合时,释放后的栈帧可以被重新分配为 rt_mutex_waiter 结构体。在 PI 链遍历过程中,红黑树(rb-tree)重平衡操作会向任意内核地址写入可控数据,从而实现任意内核地址写入原语。
futex PI UAF (CVE-2026-43499)
├─ 伪造 rt_mutex_waiter 对象
├─ 通过 pselect/select fd_set 布局控制内核栈
├─ 触发 rt_mutex PI 操作执行任意写入
├─ Write 1: selinux_state.enforcing = 0
└─ Write 2: cred → init_cred (uid=0, full capabilities)
| 设备 | 代号 | SoC | 内核版本 | 固件 | 状态 |
|---|---|---|---|---|---|
| 一加 15T | PLZ110 | SM8850 (骁龙 8 Elite) | 6.12.38-android16-5-g844001fb8721-ab14552068-4k | ColorOS 16.0.9.400 | ✅ 已验证 |
GhostLock 只负责提权。KernelSU 的安装依赖 ksud(内含各 KMI 版本的 kernelsu.ko):
| 获取方式 | 说明 |
|---|---|
| ReSukiSU APK(推荐) | 安装 ReSukiSU,APK 捆绑了 libksud.so |
| CI 发行版 | 从 下载 |
没有 ksud 时,利用仍可获得 uid=0 的 root shell,但 KernelSU 不会被安装,
su不会持久化。
ANDROID_NDK_HOME 或 ANDROID_NDK_ROOT# 默认编译 (API 35)
make
# 指定 API 级别
make API=34
# 指定 NDK 路径
NDK=/path/to/android-ndk make
编译后生成 ghostlock — 静态链接的 ARM64 ELF 可执行文件。
# 1. 启用 ADB TCP 模式
adb tcpip 5555
# 2. 推送 ADB 密钥(bootstrap 模式需要)
adb push ~/.android/adbkey /data/local/tmp/a/adbkey
# 3. 推送利用程序
adb push ghostlock /data/local/tmp/a/e
adb shell chmod 755 /data/local/tmp/a/e
首次成功后,
resetprop会自动设置persist.adb.tcp.port=5555,后续重启可全自动运行。
/data/local/tmp/a/e
task_struct 地址/data/local/tmp/a/e --bootstrap
setprop 启用 ADB TCP 5555127.0.0.1:5555 回连/data/local/tmp/a/e --write1
偏移量存储在 src/devices/offsets.h 的查找表中,以 uname -r 为键。程序启动时自动匹配,未知内核直接拒绝运行。
static const struct kernel_offsets known_offsets[] = {
OFFSETS_ENTRY("6.12.38-android16-5-...-ab14275539-4k", ...),
OFFSETS_ENTRY("6.12.38-android16-5-...-ab14552068-4k", ...),
OFFSETS_ENTRY("6.12.23-android16-5-...-ab14541642-4k", ...),
{ .uname_r = NULL } /* 哨兵 */
};
当内核指针被限制读取时(kptr_restrict),利用 boot_id 被内核地址覆写的特性泄露基址:
读取 /proc/sys/kernel/random/boot_id
└─ UUID 中被覆写为 nfulnl_logger 地址
└─ 计算 KASLR slide = leaked_addr - image_offset
└─ 得到 kaslr_base
当有 ashmem 设备访问权限时,通过 configfs 读写原语读取 ashmem 的 fops 表,从中提取函数指针计算 KASLR 偏移:
打开 ashmem 设备
└─ 读取 fops 表中的 open / ioctl / mmap 等函数指针
└─ 与 image 基址偏移对比 → 得到 kaslr_base
在 order-3(32KB)大页上布置伪造内核对象:
file_operations 表 — 劫持 ashmem 设备的 miscdevice fops 指针rt_mutex_waiter — 模拟 PI 链上的 waiter 节点task_struct — PI 链遍历中的 task 引用rt_mutex(锁) — 正确的锁等待者和所有者信息堆喷射通过 SKB(socket buffer) + KernelSnitch 实现:
mm_struct 地址,辅助堆风水sendmsg 填充内核堆获取 KASLR base 后,利用管道缓冲区实现物理地址级别读写:
1. 定位管道缓冲区在 physmap 中的位置
2. 伪造 pipe_buffer 操作表指向已知的 pipe_buf_ops
3. 劫持 pipe_buffer 的 page 字段指向目标物理地址
4. 通过 pipe read/write 实现任意物理地址读写
支持操作:pipe_read64、pipe_write64、pipe_phys_read_data、pipe_phys_write_data
目标: selinux_state.enforcing (offset 0x00)
方式: child-node PI 写入 → 伪造 waiter 的 __rb_parent_color
指向 selinux_enforcing - 8,rb-tree 重平衡时写入 0x00
SELinux 关闭后,setprop 等受 SELinux 限制的操作不再被阻止。
目标: 子进程的 cred 指针
方式: 1. fork 子进程 → perf_find_task() 定位 task_struct
2. 计算 cred 字段偏移
3. child-node PI 写入 → cred = init_cred (uid=0, full caps)
4. 清除 seccomp (TIF_SECCOMP + seccomp 结构体清零)
写完 cred 后还会进行 capability 回读验证,确保写入生效。
src/core/miniadb.c — 用于 bootstrap 模式的精简 ADB 协议客户端:
1. TCP 连接 127.0.0.1:5555
2. A_CNXN → 连接请求 (version + max payload + host::
3. A_AUTH → 收到 RSA token 挑战
4. dlopen("libcrypto.so") → PEM_read_bio_RSAPrivateKey → RSA_sign
5. A_AUTH (AUTH_SIGNATURE) → 签名响应
6. A_CNXN → 连接建立
7. A_OPEN "shell:/data/local/tmp/a/e" → 执行完整利用
支持 SHA-1 和 SHA-256 两种签名算法。
ghostlock-oneplus/
├── Makefile # 构建配置 (NDK 交叉编译)
├── README_CN.md # 说明文档
├── src/
│ ├── core/ # 核心利用代码
│ │ ├── main.c # 入口:两阶段写入 + root shell
│ │ ├── fops.c # FOPS/CFI 模式:pselect 路由、PI 写入、KASLR 泄露
│ │ ├── util.c # 工具函数:堆喷射、KASLR 地址计算、内核 R/W 原语
│ │ ├── slide.c # SLIDE 模式:boot_id KASLR 泄露 + pselect 路由
│ │ ├── pipe.c # 管道缓冲区物理内存读写 (physrw)
│ │ ├── root.c # cred 覆盖、seccomp 清除、root 子进程管理
│ │ ├── miniadb.c # 内置 ADB 客户端 (TCP + RSA 认证)
│ │ ├── common.h # 全局宏、结构体定义、函数声明、常量
│ │ ├── target.h # 目标设备内存布局 / 结构体偏移 / KASLR 参数
│ │ ├── offset.h # 编译时 target config 桥接 (#include TARGET_CONFIG_H)
│ │ └── kernelsnitch/ # KernelSnitch — mm_struct 地址泄露
│ │ ├── kernelsnitch.h # 核心算法:futex 哈希碰撞 + 暴力搜索
│ │ ├── futex_hash.h # futex 哈希函数
│ │ ├── timeutils.h # CPU 时间戳测量 (RDTSC)
│ │ └── utils.h # 辅助宏 (pr_info / SYSCHK / ASSERT 等)
│ └── devices/ # 设备偏移表
│ ├── offsets.h # 聚合所有设备偏移 (查找表 + 哨兵)
│ ├── ace6t/offsets.h # 一加 Ace 6T & 15T 偏移 (2 个内核版本)
│ └── op15/offsets.h # 一加 15 偏移 (1 个内核版本)
└── tools/ # 偏移提取工具链
├── extract_target.py # 从 kallsyms 提取全局符号偏移 (28 个)
└── extract_btf.py # 从 BTF 提取结构体字段偏移 (57 个)
该仓库进行了一定程度上的修改,具体请参见原仓库。
检查是否在 ADB shell 环境中运行。App 上下文应使用 --bootstrap 模式。
CORE 宏)PSELECT_ENTER_DELAY_USECperf_event_open(App 上下文应使用 --bootstrap)kaslr_baseksud 存在且可执行load_policy 修复)仅限授权安全研究和教育用途。
ksud-aarch64-linux-android.zip| 类型 | 数量 | 提取方式 |
|---|
| 全局符号偏移(kallsyms) | 28 | tools/extract_target.py |
| 结构体字段偏移(BTF) | 57 | tools/extract_btf.py |
| 推导值 | 9 | 自动计算 |
| 固定常量 | 12 | 无需提取 |
| 结构体 | 字段数 | 用途 |
|---|
task_struct | 17 | 进程描述符、cred、seccomp |
rt_mutex_waiter | 6 | UAF 伪造结构体 |
cred | 4 | 用户凭证、capabilities |
seccomp | 3 | seccomp 过滤状态 |
pipe_inode_info | 11 | 管道缓冲区操作 |
file_operations | 13 | 伪文件操作表 |
mm_struct | 1 | 内存描述符 owner |
| 模块 | 文件 | 职责 |
|---|
| 入口 | main.c | 命令行解析、W1/W2 调度、bootstrap 流程 |
| PI 路由 | fops.c / slide.c | pselect/select 栈布局、futex PI 链操控、竞争触发 |
| KASLR | util.c / fops.c / slide.c | 双模式绕过:boot_id 泄露 + fops 表泄露 |
| 堆喷射 | util.c | order-3 大页分配、SKB 喷射、伪造对象布局 |
| 物理 R/W | pipe.c | pipe_buffer 劫持、任意物理内存读写 |
| 提权 | root.c | cred 覆盖、capability 验证、seccomp 清除 |
| ADB | miniadb.c | 精简 ADB 协议客户端、RSA 认证 |
| 泄露引擎 | kernelsnitch/ | futex 哈希碰撞定位 mm_struct |