Dirty Cow:Linux 内核写时复制竞态条件提权漏洞

文档版本:v1.0 · 更新日期:2026-05-18 适用对象:安全研究员、系统管理员、渗透测试工程师


漏洞速览

属性详情
CVE 编号CVE-2016-5195
漏洞别名Dirty Cow(脏牛)
CVSS 评分7.8(HIGH)
CVSS 向量AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
漏洞类型CWE-362:竞态条件(Race Condition)
攻击向量本地(Local)
权限要求低权限(Low)
用户交互不需要(None)
公开日期2016-10-19
PoC 状态已公开,在野利用
补丁版本Linux Kernel >= 4.8.3 / 4.7.9 / 4.4.26
临时缓解不可行(需补丁修复)

关键时间线

2016-10-19 ── Phil Oester 公开披露漏洞(此前已内部报告给内核安全团队)
2016-10-20 ── Linux 内核主线合并修复补丁(commit 19be0eaffa3a)
2016-10-21 ── 首个公开 PoC(DirtyCow Root Exploit)发布
2016-10-22 ── Android 安全公告收录 CVE-2016-5195
2016-11-01 ── 各 Linux 发行版集中发布安全更新
2017-01-01 ── 在野利用广泛出现,尤其针对 Android 设备 Root

漏洞简介

Linux 内核的内存管理子系统(MM,Memory Management) 实现了写时复制(Copy-On-Write,COW)机制。COW 是一种内存优化策略:当多个进程映射同一只读文件时,内核共享同一份物理内存(Page Cache 页面);只有当某个进程需要修改该内存时,才真正复制一份私有副本。这种设计极大节省了内存开销。

CVE-2016-5195(Dirty Cow)正是 COW 机制中的一个竞态条件漏洞。攻击者通过 /proc/self/mem 接口与 madvise() 系统调用配合,在 “复制” 与 “写入” 之间制造竞态窗口,使内核错误地将写入操作作用于原始共享页面而非私有副本,从而实现对只读映射文件的篡改。

该漏洞的危险性在于:攻击者只需一个普通用户权限即可向任意只读文件写入数据——包括 /etc/passwd、SUID 二进制文件等系统关键文件。由于修改发生在 Page Cache 层面,磁盘上的文件 inode 时间戳和文件完整性监控(FIM)往往无法检测到篡改痕迹。Dirty Cow 在 2016 年被公开后,迅速成为 Linux 历史上最著名、利用最广泛的内核提权漏洞之一,并成为后来大量 “Dirty 系列” 漏洞(Dirty Pipe、Dirty Frag 等)的原型。


技术原理

利用链概述

低权限进程
    │
    ├── ① mmap() 映射只读文件(如 SUID 二进制)至内存
    │
    ├── ② 创建多线程竞态环境
    │       ├── 线程 A:通过 /proc/self/mem 向映射区写入恶意数据
    │       └── 线程 B:循环调用 madvise(MADV_DONTNEED) 丢弃映射页
    │
    ├── ③ 竞态窗口触发
    │       COW 处理流程中,内核检查页面引用计数 → 准备复制 →
    │       madvise 丢弃页面 → 新分配的页面被回收 →
    │       写入操作错误作用于原始 Page Cache 页面
    │
    └── ④ 只读文件被篡改 → SUID 二进制被注入恶意代码 → 获取 root

详细步骤

步骤一:建立只读映射

攻击者使用 mmap() 将目标文件(如 /usr/bin/passwd)以只读方式映射到进程地址空间。内核为该映射分配虚拟内存区域(VMA),并关联到文件的 Page Cache 页面。

int fd = open("/usr/bin/passwd", O_RDONLY);
void *map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);

MAP_PRIVATE 标志触发 COW 机制:初始时共享原始页面,写入时复制私有副本。

步骤二:构造竞态条件

攻击者创建两个线程,分别执行写入与丢弃操作:

  • 线程 A(写入线程):通过 /proc/self/mem 文件描述符,使用 pwrite()ptrace() 向映射内存地址写入恶意数据。/proc/self/mem 绕过常规的 mprotect 保护,即使映射为只读也能写入。
  • 线程 B(丢弃线程):循环调用 madvise(map, size, MADV_DONTNEED),通知内核该内存区域不再需要,内核会释放对应的物理页面。
// 线程 A:向只读映射写入
int mem_fd = open("/proc/self/mem", O_RDWR);
for (;;) {
    lseek(mem_fd, (off_t)map, SEEK_SET);
    write(mem_fd, payload, payload_size);
}
 
// 线程 B:丢弃页面
for (;;) {
    madvise(map, st.st_size, MADV_DONTNEED);
}

步骤三:竞态窗口触发

内核在 COW 路径中的处理流程存在竞态窗口:

  1. 线程 A 触发写操作时,内核检测到页面引用计数 > 1(被多个进程映射),触发 COW 流程
  2. 内核准备分配新物理页面,复制原始页面内容到新页面
  3. 在此间隙,线程 B 的 madvise(MADV_DONTNEED) 导致原始页面被释放
  4. 释放后的物理页面被回收并重新分配给其他用途(如页表)
  5. 进程的页表项(PTE)仍然指向该物理地址,但此时它已成为可写页面
  6. 线程 A 的写入操作被直接应用到原始 Page Cache 页面,而非私有副本

步骤四:达成提权

通过上述竞态条件,攻击者将恶意数据写入原始 Page Cache 中的文件内容。如果目标是 SUID 二进制文件(如 /usr/bin/passwd),攻击者可以注入 shellcode 或替换关键逻辑。当 root 用户(或其他高权限用户)执行该文件时,恶意代码以 root 权限运行,完成提权。

关键技术点

组件作用
/proc/self/mem允许进程直接读写自身内存,绕过 VMA 权限检查
madvise(MADV_DONTNEED)丢弃指定内存范围的物理页面,制造竞态窗口
MAP_PRIVATE触发 COW 机制,使私有写入本应作用于副本
Page Cache文件内容的缓存层,COW 共享的原始页面存储位置
PTE(页表项)虚拟地址到物理地址的映射,竞态导致 PTE 指向错误页面

受影响版本

组件受影响版本安全版本备注
Linux Kernel(主线)2.6.22 ~ 4.8.2>= 4.8.3漏洞自 2007 年引入(commit f5e2b1b0)
Linux Kernel(4.7 分支)4.7.0 ~ 4.7.8>= 4.7.9
Linux Kernel(4.4 LTS)4.4.0 ~ 4.4.25>= 4.4.26影响大量 LTS 发行版
Android(全版本)基于受影响内核的所有版本含 2016-10 安全补丁级别广泛用于 Android Root 工具
RHEL / CentOS 7kernel < 3.10.0-514>= 3.10.0-514
Ubuntu 16.04kernel < 4.4.0-45>= 4.4.0-45
Debian 8(Jessie)kernel < 3.16.36-1>= 3.16.36-1
内核 2.6.22 之前版本N/AN/A不受影响(/proc/self/mem 写支持在此版本引入)

漏洞影响场景

场景 1:单机本地提权

  • 前提条件:攻击者拥有目标系统的普通用户 shell 访问权限
  • 攻击过程:下载或编译 Dirty Cow 提权 EXP,执行后注入 SUID 二进制文件
  • 最坏影响:获取 root 权限,完全控制系统

场景 2:共享主机 / VPS 逃逸

  • 前提条件:攻击者在一个共享 Linux 主机上拥有低权限账号
  • 攻击过程:通过 Dirty Cow 修改 /etc/passwd 或 SUID 程序,突破用户隔离
  • 最坏影响:从受限用户提升至 root,访问其他用户的文件和数据

场景 3:Android 设备 Root

  • 前提条件:目标设备运行受影响的 Android 内核版本
  • 攻击过程:通过恶意 APK 或 ADB 执行 Dirty Cow EXP,获取 root 权限
  • 最坏影响:绕过 Android 安全模型,安装持久化后门、窃取敏感数据

场景 4:容器环境攻击

  • 前提条件:容器内拥有低权限进程,宿主机内核版本受影响
  • 攻击过程:在容器内执行 Dirty Cow EXP,污染宿主机 Page Cache
  • 最坏影响:从容器内提权至宿主机 root,实现容器逃逸

修复措施

推荐修复(根本解决)

升级内核至修复版本。 各大发行版均已发布包含补丁的内核更新。

# Ubuntu / Debian
sudo apt update && sudo apt upgrade -y linux-image-generic
sudo reboot
 
# RHEL / CentOS 7
sudo yum update kernel -y
sudo reboot
 
# 验证修复
uname -r
# 确认版本号 >= 对应安全版本
 
# 可选:验证补丁是否生效
grep -r "FOLL_COW" /boot/config-$(uname -r) 2>/dev/null

补丁核心逻辑:在 get_user_pages() 中引入 FOLL_COW 标志,当通过 /proc/self/mem 写入 MAP_PRIVATE 映射时,内核强制触发 COW 复制,避免直接修改共享页面。

临时缓解(无法立即升级时)

Dirty Cow 依赖于内核内存管理子系统(MM)的核心逻辑,没有可行的临时缓解措施。以下操作仅能降低部分风险:

方案说明局限性
限制 /proc/self/mem 访问理论上可通过 SELinux/AppArmor 限制极度影响系统功能,不可行
移除 SUID 位对不必要程序执行 chmod -s仅降低利用目标的可用性,不修复漏洞
最小权限原则确保服务运行在非特权用户下无法防止已有本地账号的攻击者

一键检查与执行临时修复脚本

检查脚本

#!/bin/bash
# Dirty Cow (CVE-2016-5195) 漏洞检查脚本
# 用途:检查当前系统内核版本是否在受影响范围内
# 限制:仅通过版本号判断,不执行实际利用验证
 
echo "=== Dirty Cow (CVE-2016-5195) 漏洞检查 ==="
echo ""
 
KERNEL_VER=$(uname -r | cut -d'-' -f1)
echo "当前内核版本:$(uname -r)"
 
# 提取主版本号
MAJOR=$(echo "$KERNEL_VER" | cut -d'.' -f1)
MINOR=$(echo "$KERNEL_VER" | cut -d'.' -f2)
PATCH=$(echo "$KERNEL_VER" | cut -d'.' -f3 | sed 's/[^0-9].*//')
 
echo ""
 
# 判断逻辑:2.6.22 <= ver < 安全版本 则受影响
# 安全版本:4.8.3 / 4.7.9 / 4.4.26
check_affected() {
    # 非常旧的版本
    if [ "$MAJOR" -lt 2 ]; then
        return 1  # < 2.0,不受影响
    fi
    if [ "$MAJOR" -eq 2 ] && [ "$MINOR" -lt 6 ]; then
        return 1  # < 2.6,不受影响
    fi
    if [ "$MAJOR" -eq 2 ] && [ "$MINOR" -eq 6 ] && [ "$PATCH" -lt 22 ]; then
        return 1  # < 2.6.22,不受影响
    fi
 
    # 检测安全版本
    if [ "$MAJOR" -gt 4 ]; then
        return 1  # >= 5.0,通常已修复(需确认发行版)
    fi
    if [ "$MAJOR" -eq 4 ] && [ "$MINOR" -ge 9 ]; then
        return 1  # >= 4.9,主线已修复
    fi
    if [ "$MAJOR" -eq 4 ] && [ "$MINOR" -eq 8 ] && [ "$PATCH" -ge 3 ]; then
        return 1  # >= 4.8.3,已修复
    fi
    if [ "$MAJOR" -eq 4 ] && [ "$MINOR" -eq 7 ] && [ "$PATCH" -ge 9 ]; then
        return 1  # >= 4.7.9,已修复
    fi
    if [ "$MAJOR" -eq 4 ] && [ "$MINOR" -eq 4 ] && [ "$PATCH" -ge 26 ]; then
        return 1  # >= 4.4.26,已修复
    fi
 
    # 长生命周期的 3.x / 2.6.x 通常由发行版 backport
    # 建议检查发行版安全公告
    return 0  # 可能受影响
}
 
if check_affected; then
    echo "⚠️  当前内核可能受 Dirty Cow (CVE-2016-5195) 影响"
    echo "   建议检查发行版安全公告或升级内核"
else
    echo "✅ 当前内核版本不在已知受影响范围"
fi
 
echo ""
echo "=== 检查完成 ==="

注意:Dirty Cow 没有有效的临时缓解措施。如果检查发现受影响,唯一的安全方案是升级内核并重启。


参考资源

官方与 NVD

标题URL类型标签
NVD - CVE-2016-5195https://nvd.nist.gov/vuln/detail/CVE-2016-5195NVD
MITRE CVE-2016-5195https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5195官方
DirtyCow 官方站点https://dirtycow.ninja/官方

技术分析

标题URL类型标签
Linux 内核主线修复 commithttps://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=19be0eaffa3a修复指南
Red Hat 漏洞分析(CVE-2016-5195)https://access.redhat.com/security/cve/cve-2016-5195技术分析
Android Security Bulletin(2016-10)https://source.android.com/docs/security/bulletin/2016-10-01厂商公告

PoC 与工具

标题URL类型标签
dirtycow(FireFart)PoChttps://github.com/FireFart/dirtycowPoC
dirtyc0w(scumjr)PoChttps://github.com/scumjr/dirtyc0wPoC
Android dirtycow PoChttps://github.com/timwr/CVE-2016-5195PoC

Dirty Cow 是 Linux 内核安全史上的里程碑事件,它不仅是实际攻击中使用最广泛的提权漏洞之一,也开创了 “Dirty” 漏洞家族的研究方向。