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 路径中的处理流程存在竞态窗口:
- 线程 A 触发写操作时,内核检测到页面引用计数 > 1(被多个进程映射),触发 COW 流程
- 内核准备分配新物理页面,复制原始页面内容到新页面
- 在此间隙,线程 B 的
madvise(MADV_DONTNEED)导致原始页面被释放 - 释放后的物理页面被回收并重新分配给其他用途(如页表)
- 进程的页表项(PTE)仍然指向该物理地址,但此时它已成为可写页面
- 线程 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 7 | kernel < 3.10.0-514 | >= 3.10.0-514 | — |
| Ubuntu 16.04 | kernel < 4.4.0-45 | >= 4.4.0-45 | — |
| Debian 8(Jessie) | kernel < 3.16.36-1 | >= 3.16.36-1 | — |
| 内核 2.6.22 之前版本 | N/A | N/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-5195 | https://nvd.nist.gov/vuln/detail/CVE-2016-5195 | NVD |
| MITRE CVE-2016-5195 | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5195 | 官方 |
| DirtyCow 官方站点 | https://dirtycow.ninja/ | 官方 |
技术分析
| 标题 | URL | 类型标签 |
|---|---|---|
| Linux 内核主线修复 commit | https://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)PoC | https://github.com/FireFart/dirtycow | PoC |
| dirtyc0w(scumjr)PoC | https://github.com/scumjr/dirtyc0w | PoC |
| Android dirtycow PoC | https://github.com/timwr/CVE-2016-5195 | PoC |
Dirty Cow 是 Linux 内核安全史上的里程碑事件,它不仅是实际攻击中使用最广泛的提权漏洞之一,也开创了 “Dirty” 漏洞家族的研究方向。