Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

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

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

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-43499-S26 — Android GKI 6.12 内核漏洞利用程序,针对 CVE-2026-43499,将 rt_mutex 回滚漏洞与 pselect 栈覆盖串联,从而在三星和 Pixel 设备上获取 root 权限。 | Kitploit
工具/GitHubGitHub/sammyenigma/cve-2026-43499-s26
Android安全权限提升内存取证持久化机制漏洞利用逆向工程Shellcode后渗透利用移动安全Payload 开发二进制利用
GitHub
122天前尚未审核

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
sammyenigma/cve-2026-43499-s26

CVE-2026-43499-S26

Android GKI 6.12 内核漏洞利用程序,针对 CVE-2026-43499,将 rt_mutex 回滚漏洞与 pselect 栈覆盖串联,从而在三星和 Pixel 设备上获取 root 权限。

查看仓库

CVE-2026-43499 — Android GKI 6.12 pselect / configfs 内核漏洞利用

针对 Android GKI 6.12 系列(三星和 Pixel 设备)的 Linux 内核漏洞利用,目标是 CVE-2026-43499:rt_mutex_start_proxy_lock() 中 remove_waiter() 的回滚存在缺陷,它使用了 current 而不是 waiter::task,导致等待者的 pi_blocked_on 指向其(稍后被弹出的)内核栈上的 rt_mutex_waiter。结合 pselect() 的 fd_set 栈覆写以及由消费者 sched_setattr 驱动的伪造 rb_tree 遍历,可产生确定性的内核写入原语并获取完整 root 权限。

该漏洞利用以 LD_PRELOAD 共享库(preload.so)的形式运行,并在获取 root 后安装 root su 守护进程以及壁纸作为后置产物。

状态:活跃开发中。m1q(ZF1)目标是当前的重点攻关对象。 pipei tmp_page-uname 引导是当前活跃的路线:该遍历已在设备上验证干净(build #33:每个子进程独立播种的 rt_mutex 区域),完整的 168 候选扫描正在进行中。configfs CFI 路线在 m1q 上是死路(Rust ashmem —— 没有可注入的 fops 槽位),但仍保留为 C-ashmem 目标的路线。各目标的偏移量因设备而异 —— 在信任它们之前,请对照实际内核二进制进行验证。

漏洞原语(CVE-2026-43499)

当 FUTEX_CMP_REQUEUE_PI 重新排队一个等待者,且重新排队的死锁检测链遍历返回 -EDEADLK 时,__rt_mutex_start_proxy_lock() 会通过 remove_waiter()(rtmutex.c:1535)进行回滚。回滚正确地将等待者从等待树中出队,但清除的是重新排队调用者的 pi_blocked_on,而不是 waiter->task->pi_blocked_on。等待者的 pi_blocked_on 仍然悬空指向其栈上的 rt_mutex_waiter,该结构在 futex 超时后被弹出。

超时后,等待者的内核栈区域被复用:core_sys_select() 将三个 fd_set 复制到该栈缓冲区中(ZF1 上的 nfds < 344 栈路径)。精心构造的 fd_set 字数组会重新物化一个伪造的 rt_mutex_waiter / 伪造任务 / 伪造 rt_mutex(其 rb_tree 根指针受控)。随后一个消费者线程调用 sched_setattr_tid(waiter) → rt_mutex_adjust_pi() → rb_erase_cached,从而产生对受控值的任意地址写入。

整个原语需要 PI 链环路:持有者持有 f_pi_target,同时又阻塞在 f_pi_chain(由等待者持有)上,因此链遍历会命中 owner → chain → waiter → target → owner 并以 -EDEADLK 失败。移除该环路会使重新排队返回成功且对内核零影响。

利用链

  1. Slide(KASLR) —— 泄露内核基址。两条路线:
    • tracefs sched_blocked_reason(m1q 主路线,设备上已验证):从环形缓冲区读取被阻塞 kworker 保存的返回 PC(stack_trace_save_tsk),并与编译内置的 worker_thread 偏移进行比较。在任何 boot_id 路线字被使用之前运行,以便数据别名写入目标(data_addr() = p0 别名 + slide_p0_offset)在非零 slide 下保持正确。
    • boot_id pselect 路线(回退,与 slide 无关):pselect 写入通过线性映射别名将 SLIDE_LOGGERS_0_1 植入 boot_id sysctl 数据中;泄露的值可重建 stext。在 m1q 上已搁置:其 W1 目标(SLIDE_RANDOM_BOOT_ID_DATA_OFF,低物理 RAM)的可写性依赖于页 —— slide 每次启动都会将目标移动跨页边界,因此约 6/7 次运行会出错。仅通过 SLIDE_FORCE_BOOTID(机制测试)显式执行,并将 tree_pc/tree_left 重定向到喷射页。
  2. KernelSnitch —— 喷射 mm_struct 大小的对象,并利用 futex 哈希碰撞在堆上定位一个 mm_struct,泄露一个内核堆页地址,用作伪造对象喷射基址。清理时等待者被分离(而非 join),以避免在 #26 之前的构建中导致崩溃的内核栈 OOM。
  3. 主路线 —— pipei tmp_page 引导(m1q,当前重点) —— 原始的 configfs CFI 路线在 m1q 上是死路:Rust ashmem 没有可注入的静态 槽位,且 堆对象是一个 KVec,其布局与 的 private_data 不匹配。m1q 转向 kmalloc 写入:将泄露的 mm order-3 块回收为 对象,并使用 pselect W1 写入()将候选者的 槽位(+0x90)覆写为 UTS 命名空间页()。扇出写入在 偏移处植入一个标记名称, 报告 "CatOS" —— 一种可验证的、不依赖静态对象的内核写入。C-ashmem 目标保留 configfs 路径。

遍历形态(m1q,设备上已验证)

pselect fd_set 字在等待者的内核栈上重新物化一个伪造的 rt_mutex_waiter;消费者线程的 sched_setattr_tid(waiter) 通过 rt_mutex_adjust_pi() 遍历它。ZF1 字映射(反汇编验证):PSELECT_WAITER_WORD_SHIFT = 0,word 12 = task(@+0x50),word 13 = lock(@+0x58),word 14 = wake_state(@+0x60 = 3)。在播种了伪造 rt_mutex 的情况下,遍历干净地完成:[7] 的 rb_erase W1 *(tree_left)=tree_pc / W2 *(tree_pc&~3+8)=tree_left 是唯一的内核写入;[11](setprio / dequeue_pi)和 [9] 唤醒均被跳过(prio 100 的本地伪造等待者使栈节点不进入 top-waiter)。自 build #19 以来,每次进入遍历的完成都在设备上存活;此前的确定性崩溃是 8 字节载荷放置错误(SKB_DATA_DELTA),而非遍历体故障。

Stage 3(pgd-swap 桥,仅静态/构建)

可选的 STAGE3=1 阶段,它 fork 一个桥子进程,将其 mm->pgd 交换为分阶段的伪造页表(3 级:PGD→L1→L2,RX 循环叶子 + RW 栈叶子),并让子进程运行一个仅使用寄存器的汇编 blob,通过 2MB 物理扫描窗口修补其自身的 cred —— 无需 configfs/pipe 原语即可实现全 RAM 物理读/写。目前仅接入 m1q 目标,且尚未在设备上运行。

支持的目标

src/targets/<codename>-<build>/ 中有 41 个目标,每个至少需要一个 target.h(内核符号偏移、KIMAGE_TEXT_BASE、直接映射基址、结构体偏移)。Pixel 目标(comet、tokay、tegu、caiman、komodo、frankel、mustang、rango、stallion、blazer)覆盖共享源;三星目标(m1q-*)添加设备特定逻辑。

root@kitploit:~
make list-projects   # full list

内核结构体布局因设备而异 —— 必须针对每个目标对照实际内核二进制 / kallsyms 验证偏移量。

构建

输出:build/<PROJECT>/bin/preload.so(通过 LD_PRELOAD 加载的共享库)。

root@kitploit:~
# Default project
CC=clang make

# Specific device target (default: blazer-CP2A.260605.012)
CC=clang make PROJECT=m1q-BP4A.251205.006

# Without CC=clang: uses NDK if found ($NDK_ROOT / $ANDROID_NDK_HOME /
# $ANDROID_NDK_ROOT), otherwise host clang + Android sysroot
make PROJECT=m1q-BP4A.251205.006

# Show build configuration
make info

# Clean
make clean

构建过程通过 src/su_blob.S / src/wallpaper_blob.S 将一个 PIE su_daemon 二进制(src/su_daemon.c,构建到 build/embed/su_daemon_aarch64_pie)和 assets/wallpaper.webp 嵌入到 preload.so 中。

在设备上运行

将构建输出推送到 /data/local/tmp,然后在 LD_PRELOAD 下运行漏洞利用。在活跃攻关目标上运行时不要使用 tee —— tee 会缓冲自己的 stdio,并在内核 panic 时丢失日志尾部(漏洞利用的 stdout 是无缓冲的,因此直接重定向到文件可保留每一行):

root@kitploit:~
adb push build/m1q-BP4A.251205.006/bin/preload.so /data/local/tmp/preload.so
adb push build/embed/su_daemon_aarch64_pie /data/local/tmp/su_daemon_aarch64_pie
adb shell "chmod 755 /data/local/tmp/preload.so /data/local/tmp/su_daemon_aarch64_pie"

adb shell "LD_PRELOAD=/data/local/tmp/preload.so \
  /data/local/tmp/su_daemon_aarch64_pie \
  > /data/local/tmp/output.log 2>&1"

成功后,守护进程监听 /data/local/tmp/temp_su.sock,且 su 被安装到 /apex/com.android.virt/bin 下。

m1q pipei 扫描(当前攻关)

tools/run_pipei.sh 推送二进制文件,在设备上对其进行 sha256 校验(过期的 preload.so 会产生静默不可读的判定 —— 该阶梯曾运行过 build < #22,其日志格式不同),然后以 3x56 分块运行完整的 168 候选扫描,这样一次 panic 最多丢失一个块(约 10 分钟)。漏洞利用的 stdout 直接流式传输通过 adb(无设备端重定向 —— 设备端 tee 在 panic 时会丢失尾部);每个块的主机端副本保存在 /tmp/m1q_pipei_chunk{1..3}_stream.log:

root@kitploit:~
sh tools/run_pipei.sh

PASS = 任一块显示 tmp_page uname changed + after uname='CatOS。 PIPEI_CHILD_REGIONS 必须设置为至少块大小,否则每个子进程的 rt_mutex 区域将保持未播种,扫描会在候选 0 处 panic。完整覆盖还需要 TMP_UNAME_PIPEI_SPLIT_ORDER_PAGES=1 —— 没有它,被释放的 8 页 mm 块中只有一页会被扫描。run_pipei_slim.sh 是单候选诊断变体;run_m1q_ladder.sh 是遍历/隔离测试组(B16-2 oracle、slide 机制、扫描步骤)。

运行时配置(环境变量)

项目布局

root@kitploit:~
exploit/
  Makefile
  assets/                     # wallpaper.webp (embedded post-root artifact)
  src/
    main.c                    # run_exploit() entry point (shared)
    preload.c                 # LD_PRELOAD constructor, su/wallpaper install
    util.c                    # addr translation, page prep, configfs helpers
    pipe.c                    # pipe-based physical read/write
    root.c                    # cred patching / task walk
    slide.c                   # KASLR slide (tracefs + boot_id routes)
    fops.c                    # pselect corruption + fops manipulation
    faketables.c              # stage-3 fake page-table builders (3-level)
    stage3.c                  # pgd-swap bridge child (no-op unless configured)
    stage3_loop.S, stage3_poll.S  # bridge blob + enter trampoline
    su_daemon.c               # root daemon (compiled as separate PIE)
    su_blob.S, wallpaper_blob.S   # embedded binaries
    offset.h                  # pulls per-target target.h via -DTARGET_CONFIG_H
    kernelsnitch/             # mm_struct futex-hash leak library
    targets/<codename>-<build>/    # per-device target.h + optional overrides
poc/poc.c                     # standalone POC (separate from the exploit)

目标通过 Makefile 的 pick_src 机制覆盖共享源:如果 src/targets/<PROJECT>/<file>.c 存在,则使用它而不是共享的 src/<file>.c;否则使用共享版本。

注意事项与陷阱

  • 永远不要移除 PI 链环路。 写入原语依赖于重新排队以 -EDEADLK(errno 35)失败。缺少环路会表现为 success=1 且对内核零影响。
  • 等待者必须在 pselect 期间持有 PI 链锁。 先释放它会让持有者唤醒并与伪造 rb_tree 遍历竞争 → panic。
  • m1q:PSELECT_WAITER_WORD_SHIFT 必须为 0(ZF1 栈深度从 ELF 验证)。其他目标仍默认为 1 —— 在信任它们之前请逐设备验证。
  • p0_data_alias() 使用 DIRECT_MAP_BASE(线性映射),在 ZF1 上与 P0_PAGE_OFFSET 不同。被解引用的内核对象的数据别名必须使用线性映射。
  • pr_error() 是致命的(exit(-1)),与警告/信息宏不同。
  • Slide 重建使用 SLIDE_LOGGERS_0_1,而非 SLIDE_NFULNL_LOGGER;该字是非随机化的线性映射别名,因此 boot_id 路线与 slide 无关(仅在 slide=0 时使用它 —— 先运行 tracefs 泄露)。
  • SKB_DATA_DELTA 为 -0xe78(设备上实测,build #19)—— 真实的 skb frag 头比反汇编推导的 -0xe80 少 8 字节;该 8 字节错误导致了 build #6-18 中每次确定性 pselect 崩溃(进入遍历 → 垃圾解引用)。GKI 6.12 共享值;每个目标的 util.c 副本带有 环境 A/B 旋钮。不要将 叠加在已烘焙的常量之上。

免责声明

这是针对 Android 设备的漏洞利用代码,旨在用于安全研究、授权漏洞测试以及您拥有或获得明确测试许可的硬件上的防御工作。在您不拥有的设备上滥用是违法的。作者不对变砖的设备、变砖的内核或失效的保修负责。

下载工具
write_iter
ASHMEM_SET_NAME
configfs_bin_write_iter
pipe_inode_info
*(tree_left) = tree_pc
tmp_page
init_uts_ns
sysname
uname()
  • Pipe physrw —— 在喷射的内核页中伪造管道缓冲区页,以实现物理读/写:cred 修补、SELinux 禁用以及直接内核内存操作。
  • Root —— 修补 root 子进程的 cred(uid/gid/caps/SELinux SID),然后 preload.c 安装内嵌的 su 守护进程(tmpfs 挂载到 /apex/com.android.virt/bin,外加 adbd 命名空间和本地变体)并替换壁纸。
  • 变量默认值用途
    PSELECT_ROUTE_SHIFT编译时主路线(m1q)的 A/B fd_set 字偏移
    SLIDE_SHIFT编译时slide 路线的 A/B fd_set 字偏移
    PSELECT_ROUTE_DELAY_USEC50000sched_setattr 之前的消费者延迟(必须 > 0)
    SLIDE_CONSUME_USEC, SLIDE_ENTER_DELAY_USEC, SLIDE_CONSUMER_CORE—slide 路线时序/绑核
    SKIP_SLIDE0使用直接映射回退(slide = 0)
    SLIDE_ONLY0仅运行 KASLR slide 然后退出
    SLIDE_P0_OFFSET, SLIDE_BOOTID_OFF—覆盖 slide p0 别名 / boot_id 偏移
    SLIDE_FORCE_BOOTID0在 tracefs slide 之后强制使用 boot_id pselect 路线(机制测试)
    KSNITCH_COLLISIONS4KernelSnitch 碰撞次数
    STAGE30启用 pgd-swap 桥子进程阶段(m1q)
    STAGE3_DRYRUN0分阶段/验证页表后在交换前中止
    PAGE_RECLAIM_SENDS, PSELECT_SIMPLE_LAYOUT—喷射/fd_set 布局调整
    TMP_PAGE_UNAME0运行 m1q pipei tmp_page-uname 引导
    TMP_UNAME_PIPEI_SWEEP, TMP_UNAME_PIPEI_ALIGN_ORDER, TMP_UNAME_PIPEI_SPLIT_ORDER_PAGES—扫描模式;split_order 扫描被释放 mm 块的全部 8 页
    TMP_UNAME_PIPEI_SLOT, TMP_UNAME_PIPEI_SLOT_CANDIDATES—扫描范围(块起始 / 数量)
    PIPEI_CHILD_REGIONS0每个子进程播种的 rt_mutex 区域;必须 >= 扫描块,否则未播种区域会在候选 0 处 panic
    PIPEI_RECLAIM_COUNT, PIPEI_DRAIN_COUNT—回收/排空管道对;在回收未命中时提高
    PIPEI_SPONGE_MB3072在回收期间保持的 order-0 洪泛海绵(build #29)
    PSELECT_W0_PRIO_OVERRIDE130top-waiter 优先级;在播种区域下无效(遗留陈旧树防护,仅 A/B)
    PSELECT_SKB_DELTA_OVERRIDE0A/B 载荷页内偏移(仅当某设备与 -0xe78 不同时)
    TMP_UNAME_NAME, TMP_UNAME_HOLD_SEC"CatOS", 5成功后标记名称 / 保持时间
    SKB_DATA_DELTA
    PSELECT_SKB_DELTA_OVERRIDE
  • 遍历体是干净的;放置才是 bug。 在建模偏移处播种载荷后,链遍历在设备上无故障完成。进入遍历的崩溃意味着 fd 字地址处的内存不是载荷(回收/放置竞争),而非模型错误。
  • m1q:configfs CFI 路线是死路(Rust ashmem) —— 没有可注入的静态 fops 槽位,且 ASHMEM_SET_NAME KVec 封装与 configfs_bin_write_iter 不匹配。使用 pipei tmp_page 引导。m1q target.h 中的 PSELECT_WRITE_RIGHT_SPRAYED / PSELECT_PI_TOP_TASK_SELF 防护将遍历的 [11] 写入重定向离开 RO 静态 fops。
  • 每个子进程的 rt_mutex 区域(build #33): 每个扫描子进程将其 fd 字 w13 重定向到回收页内自己播种的区域(payload+0x6000 + idx*0x40)。共享 fake_lock 扫描在候选约 9-12 处 panic(陈旧内核栈节点被回收),而 build #32 的空区域在候选 0 处 panic([9] 在 0x41 填充的 fake_task 上 owner==NULL 唤醒)。必须设置 PIPEI_CHILD_REGIONS,否则区域保持未播种。
  • m1q boot_id pselect slide 已搁置 —— 其 W1 目标是低 RAM,其页可写性每次启动都不同;tracefs 是主路线,每次运行都会测量 slide。