galoryber/CVE-2026-31431-cleaned

GitHub: galoryber/CVE-2026-31431-cleaned

对 CVE-2026-31431 Linux 内核 splice() 本地提权漏洞的完整注释分析,详尽拆解了从 socket 构造到内核内存破坏再到 setuid 二进制文件劫持的完整利用链。

Stars: 1 | Forks: 0

# copyFail.py — CVE 漏洞利用分析报告 ## 概述 `copyFail.py` 是一个概念验证PoC 漏洞利用程序,演示了 Linux 内核中的一个**本地权限提升**漏洞。通过滥用 `splice()` 系统调用并结合精心构造的 socket 选项,该漏洞利用程序获得了破坏任意内核内存的能力。它利用这种能力用自定义的 ELF 可执行文件覆盖磁盘上的任何 setuid 二进制文件,然后运行被篡改的二进制文件以获取提升的权限。 **攻击类型:** 本地权限提升 (LPE) **影响:** 获取完整的 root shell 访问权限(当针对 setuid-root 二进制文件时) **复杂度:** 低(单脚本,无外部依赖) **用法:** ``` ./copyFail_cleaned.py [target_binary] # default: /usr/bin/su ``` 原始 PoC 硬编码了 `/usr/bin/su`,但底层的内核漏洞适用于**任何文件**——攻击者可以覆盖他们选择的任何 setuid 二进制文件。清理后的版本接受一个可选的命令行参数来指定目标,使这种行为更加明确。 ## 漏洞是什么 Linux 内核提供了一个 `splice()` 系统调用,它完全在内核内部在两个文件描述符之间复制数据——而无需先将数据复制到用户空间。这被称为“零拷贝 I/O”,用于 Web 服务器和反向代理等高吞吐量应用程序以提高性能。 该漏洞的产生是因为当在配置了不受支持的协议级 socket 选项的 PACKET socket 上使用 `splice()` 时,内核没有正确验证某些 socket 结构的内部状态。通过精心构造这些选项,攻击者可以破坏内核指针,然后使用 `splice()` 将内核内存写入重定向到任意位置。 简单来说:内核在内部移动数据时使用了一个捷径,而这个漏洞利用程序欺骗该捷径将数据写入错误的位置——具体来说,是写入系统二进制文件的内存副本中。 ## 漏洞利用工作原理(高层视角) 该漏洞利用遵循以下清晰的步骤序列: ### 1. 设置格式错误的 Socket 该漏洞利用创建了一个原始的 PACKET socket(`AF_PACKET` / `SOCK_RAW`),并将其绑定到故意格式错误的地址。然后它使用 `SOL_PNIO`(协议级别 279)调用 `setsockopt()`,这是一个 Linux 无法识别的 Solaris 级别常量。 **为什么这很重要:** 当内核在 `setsockopt()` 中遇到不受支持的协议级别时,它会落入一个未正确验证数据的通用处理程序中。这使得内核内存处于不一致且可被利用的状态。 ### 2. 使用 sendmsg() 破坏内核指针 在通过 `accept()` 建立 socket 连接后,该漏洞利用使用 `sendmsg()` 发送精心构造的辅助(控制)消息。这些消息具有故意不匹配的长度头——有些声称比实际短,有些声称比实际长。 **为什么这很重要:** 内核的控制消息解析器使用这些长度进行指针算术运算。不匹配的长度会导致解析器在预期边界之外进行读取或写入,从而破坏相邻的内核结构——特别是 `splice()` 稍后将遵循的指针。 ### 3. 重定向 splice() 以覆盖任意内存 该漏洞利用创建了一个管道并调用了两次 `splice()`: - 首先,它将数据从 `/usr/bin/su` 拼接到管道中。 - 然后,它将数据从管道拼接到受损的 socket 中。 **为什么这很重要:** `splice()` 调用会遵循在步骤 2 中植入的被破坏的内核指针,导致它将数据写入攻击者选择的内核内存地址,而不是 socket 缓冲区。这为该漏洞利用提供了一个**任意内核内存写入**原语。 ### 4. 针对 Shellcode 的每个数据块重复操作 该漏洞利用的 payload 是一个 160 字节的 ELF 可执行文件(见下文)。每次调用漏洞利用函数都会精确写入 4 个字节。因此,主循环运行 40 次(160 / 4 = 40),每次都会: - 创建一个新的 socket - 破坏内核状态 - 写入 4 个字节的 shellcode - 清理 在所有 40 次迭代之后,`/usr/bin/su` 的前 160 个字节已被覆盖。 ### 5. 执行被篡改的二进制文件 最后,该漏洞利用运行 `os.system("su")`。内核从其页面缓存中加载修改后的 `/usr/bin/su`(现在包含攻击者的 shellcode,而不是真正的 `su` 二进制文件),然后执行该 shellcode。 ## Shellcode 载荷 嵌入的 payload 解压后是一个 **160 字节的 x86-64 ELF 可执行文件**,包含以下 shellcode: ``` ; Attempt syscall 105 (execveat) — may not be available on older kernels xor eax, eax xor edi, edi mov al, 0x69 ; syscall 105 syscall ; Fallback: syscall 59 (execve) — the reliable path lea rdi, [rip+0xf] ; RDI = pointer to "/bin/sh" xor esi, esi ; RSI = NULL (envp) push 0x3b ; syscall 59 number pop eax cdq ; RDX = NULL (argv) syscall ; Exit cleanly xor edi, edi push 0x3c ; syscall 60 (exit) pop eax syscall ; Data section: "/bin/sh\0\0\0" ``` **它的作用:** 生成一个不带参数的 `/bin/sh`,继承运行 `su` 的进程的权限。如果漏洞利用以 root 身份运行(或具有授予 `su` root 访问权限的 capabilities),则生成的 shell 就是 root shell。 **它不会做什么:** - 没有反向 shell 或网络回调 - 没有持久化机制(cron、systemd、SSH 密钥等) - 没有凭证窃取或数据渗出 - 没有进程隐藏或反取证 这是一个直接的一次性权限提升,与研究 PoC 一致。 ## 技术细节 ### 使用的主要 Linux 常量 | 常量 | 值 | 在漏洞利用中的用途 | |----------|-------|-------------------| | `AF_PACKET` | 17 | 原始数据包 socket 族 | | `SOCK_RAW` | 3 | 原始 socket 类型 | | `SOL_PNIO` | 279 | 不受支持的协议级别(Solaris) | | `MSG_DONTWAIT` | 0x400 | 非阻塞 sendmsg 标志 | ### 文件结构 ``` copyFail.py ├── hex_to_bytes() — hex string decoder ├── exploit_splice() — core exploit (socket setup + corruption + splice) │ ├── Phase 1: Create PACKET socket, bind, setsockopt (SOL_PNIO) │ ├── Phase 2: accept() connection │ ├── Phase 3: sendmsg() with crafted ancillary messages │ ├── Phase 4: pipe() + splice() to corrupt kernel memory │ └── Phase 5: recv() attempt (solidifies corruption) └── Main loop: ├── Open /usr/bin/su (read-only) ├── Decompress embedded payload (zlib → 160-byte ELF) ├── Loop: inject 4 bytes per iteration (40 iterations total) └── Execute tampered su → root shell ``` ### 为什么是只读的? 该漏洞利用以 `O_RDONLY`(只读)方式打开 `/usr/bin/su`。它不需要写访问权限,因为破坏是通过内核页面缓存发生的——这是内核在将更改刷新到磁盘之前使用的文件内存副本。基于 `splice()` 的写入完全绕过了正常的文件权限,直接进入内核内存。 ## 检测与缓解 ### 妥协指标 - `/usr/bin/su` 二进制文件被修改(将哈希值与包管理器中的进行比较) - 非特权用户(非 root)异常创建 PACKET socket - 带有未知协议级别的意外 `setsockopt()` 调用 - 在非正规文件描述符上调用 `splice()` 系统调用 ### 缓解措施 - 在可用时应用针对此 CVE 的内核补丁 - 使用 `sysctl` 限制非特权用户创建 `AF_PACKET` socket - 启用内核加固选项(CONFIG_FORTIFY_SOURCE、CONFIG_STACKPROTECTOR) - 监控关键二进制文件的文件完整性(AIDE、OSSEC、Tripwire) ## 参考 - 原始 PoC:`copyFail.py`(已分发) - 带注释的版本:`copyFail_cleaned.py`(同目录) - 相关内核子系统:`net/packet/`、`fs/splice.c`、`net/core/sock.c` *本报告仅供安全研究和防御分析之用。*
标签:0day挖掘, CVE, CVE-2026-31431, ELF文件分析, Linux内核漏洞, LPE, meg, PACKET套接字, PoC, SetUID, Socket选项, splice系统调用, Web报告查看器, 二进制文件分析, 任意内存覆盖, 信息安全, 内核安全, 内核态利用, 安全渗透, 提权, 数字签名, 数据展示, 暴力破解, 本地权限提升, 漏洞分析, 红队, 网络安全, 路径探测, 逆向工具, 隐私保护, 零拷贝