几个月前帮朋友查一台 CentOS 7 机器,Nginx 日志里有个过期域名还在源源不断地产生流量,可解析记录早就删干净了。查到最后,在 /etc/grub2.cfg 里看到启动参数被偷偷塞了一条 rd.break。这手法说穿了不值钱,可一旦有人摸到物理或者 VNC 控制台,你的服务器就跟没锁门一样。
有人绕过防火墙,走到机器前按了个 e
攻击者要动手,前提要么能碰到机房里的机器,要么是通过带外管理口——比如 iLO、iDRAC 或者云服务的 VNC 控制台登上系统。只要拿到控制台,重启,在 GRUB 菜单上按 e 进入编辑模式,就这么简单。没密码拦着的话。
找到以 linux 开头那行,末尾加个 rd.break。这个参数让 systemd 在 initramfs 阶段停住,直接丢给你一个 root shell。这时候硬盘上的根文件系统还没完全挂载,但你已经有权限改它了。更狠一点的,直接加 init=/bin/bash,跳过所有服务进 shell。进去之后 就能读写真正的根分区。
接下来的操作就顺理成章了:改 /etc/resolv.conf 把 DNS 指到自己的服务器,加 iptables 规则做 DNAT 把 80 和 443 的流量转到竞品 IP,或者直接改 Nginx 配置返回一个 302 跳转。
某云厂商的客户没给 GRUB 设密码,攻击者直接从 VNC 控制台进了单用户模式,把指向自家产品的域名悄悄改到了一个仿冒竞品页上。结果呢?用户照旧访问那个老 URL,看到的全是别人家广告——一套操作下来,流量就这么被截走了。
最让人无奈的是,这种修改在操作系统层面几乎不留日志——GRUB 菜单编辑本身不会写 audit log。只有重启后翻 dmesg 才能看到内核启动参数被改过的痕迹。等你发现流量异常,劫持可能已经跑了好几个星期。
那案例里最扎心的不是手法高明,而是攻击者根本不需要黑进系统——他只需要比你更靠近机房。
域名抢注怎么跟启动菜单扯上关系的
很多人以为服务器安全靠防火墙和 WAF 就够了,结果人家直接走到机柜前插显示器。GRUB 菜单默认没密码,按 e 就能改内核行。加个 rd.break,系统停在 initramfs 阶段,根分区还没挂载呢,你已经有 root shell 了。这操作比 SSH 爆破快十倍,还不留痕迹。
改完 resolv.conf 指向恶意 DNS,或者用 iptables 做 DNAT 转发,这台机器就成了流量中转站。过期域名本来就有 SEO 权重,搜索引擎还在收录旧链接,用户一点进来,跳转到竞品页面。攻击者啥都不用管,坐等广告费进账。
更绝的是,这种攻击完全不触发常规监控系统的警报——它发生在启动流程里,不是网络层也不是应用层。等你发现异常流量,对方可能已经换了三波域名了。
防御从 GRUB 密码开始,但不能停在这里
看完前面那个案例,最让人后背发凉的不是攻击者有多聪明——而是他根本不需要聪明。你堆再多 WAF 规则、配再复杂的 iptables,人家走到机柜前按个 e 键,一切归零。GRUB 菜单默认就是裸奔的,这事在运维圈喊了十几年,但你去查云服务器后台,十台里有八台还是出厂配置。
那怎么补?不是让你去 BIOS 里设个密码就完事——那种密码用螺丝刀拆主板电池就能清。真正管用的是在 GRUB 层面做两层锁:一是加密菜单编辑权限,二是把单用户模式、rd.break、init=/bin/bash 这些危险入口全部封死。
生成 PBKDF2 加密口令
GRUB2 支持 PBKDF2 哈希,这东西比普通 SHA-512 抗暴力破解能力强得多。一行命令搞定:。
运行后会让你输两遍密码,然后吐出一长串类似 的字符串。把这串东西完整复制下来,别漏了末尾的等号。接下来编辑 /etc/grub.d/40_custom,在最顶部写入:
set superusers="admin"
password_pbkdf2 admin grub.pbkdf2.sha512.10000.8A2B...
这里 superusers 定义了哪个用户有编辑菜单的权限——你可以设多个,但生产环境建议只留一个,少一个入口少一分风险。编辑完别忘跑 ,不然配置不会生效。CentOS、Anolis OS、Ubuntu 都适用,只是 Ubuntu 上命令叫 (没有数字2),路径也可能在 /boot/grub/grub.cfg。
有个坑:很多人改完 40_custom 忘了执行 ,然后重启后发现密码没生效,还以为自己写错了。这文件不会自动触发重新生成主配置,必须手动走一遍。
锁定危险内核参数
密码只能拦住按 e 改菜单的人,但如果你自己配的内核启动参数里还允许 rd.break,那等于给攻击者留了后门。这个参数的作用是让系统在 initramfs 阶段停下来,给你一个 shell——此时磁盘还没挂载、LUKS 还没解密,但你已经有 root 权限了。
封堵方法:编辑 /etc/default/grub,在 这一行末尾加上两个参数:
GRUB_CMDLINE_LINUX="... rd.break=disabled systemd.unit=multi-user.target"
rd.break=disabled 直接告诉 dracut 不要进入急救 shell。systemd.unit=multi-user.target 则确保系统启动后进入多用户模式而非单用户。这里有个细节:有些人以为设了 systemd.unit=emergency.target 更安全,但 emergency 模式还是单用户 shell——攻击者拿到键盘照样能干坏事。multi-user.target 才是正常的无图形界面运行级别。
改完后同样执行 刷新配置。想验证是否生效?重启后按 e 看看内核行里有没有你加的参数——如果看不到,说明要么命令没跑成功,要么路径错了。
别忘了 BIOS/UEFI 这一层
GRUB 密码只防本地键盘操作。攻击者如果带着 Live USB 来,直接从 U 盘启动,你硬盘上的 GRUB 压根没被加载,密码形同虚设。所以这一步必须跟 UEFI Secure Boot、固件密码、LUKS 全盘加密配合着用。Secure Boot 能阻止未签名的启动介质,固件密码防别人改启动顺序,LUKS 加密保证即使硬盘被拔走也读不出数据。
之前看到一篇技术文章说得直白:GRUB2 密码能防的是“你同事趁你上厕所时溜到服务器前改内核参数”,但防不住“有人拿着螺丝刀拆了硬盘走人”。物理安全永远是一层层叠加的——少一层就有破绽。
这三步配下来,至少那些按个 e 键就能劫持流量的低级攻击就被挡在门外了。但别以为设完密码就高枕无忧——真正的硬仗还在后面:内核提权漏洞、残留的 audit 日志、还有你压根没注意到的 initramfs 钩子脚本。
在 CentOS 和 Anolis OS 上实操一把
理论说破天,不如直接敲键盘验证。两台机器走完流程——CentOS 7.9 一台,Anolis OS 8.6 另一台。踩坑的地方顺手记下来,下次你碰到能少绕点弯路。
CentOS 7:一条命令搞定,但有个小陷阱
CentOS 7 自带的 grub2-tools 版本够新,直接跑 就行。它会交互式让你输两遍密码,然后自动把加密哈希写进 /boot/grub2/user.cfg。完事记得 重新生成配置。
但我第一次重启后按 e 居然没弹密码框——排查发现 /etc/grub.d/01_users 文件里的 set superusers="root" 没写对。这文件是 自动生成的,但如果你之前手动改过 40_custom 或其他 grub.d 脚本,优先级冲突会导致 superusers 变量被覆盖。修复很简单:确认 01_users 里 set superusers="admin" 存在且唯一,然后在每个你想保护的 menuentry 块头部加 --users admin,比如:
menuentry 'CentOS Linux (3.10.0-1160.el7.x86_64) 7 (Core)' --users admin {
load_video
set gfxpayload=keep
insmod gzio
linux /vmlinuz-3.10.0-1160.el7.x86_64 root=/dev/mapper/cl-root ro crashkernel=auto
initrd /initramfs-3.10.0-1160.el7.x86_64.img
}
这样按 e 才认账。不加 --users 的话,superusers 设了也等于白设——GRUB 2.02 就是这么设计的,只锁菜单不锁条目。
Anolis OS 8:看似兼容,实则路径藏雷
Anolis OS 官方说跟 CentOS 8 完全兼容,但实际操作时 的目标路径得写成 /boot/grub2/grub.cfg,不是 /boot/efi/EFI/anolis/grub.cfg(后者是 UEFI 模式下的备份路径)。我一开始对着 CentOS 8 的文档用 -o /boot/efi/EFI/anolis/grub.cfg,结果重启后配置没生效——Anolis 的 UEFI 固件读的是 /boot/grub2/grub.cfg 这个符号链接指向的文件。正确的做法是:
# 生成密码哈希
grub2-mkpasswd-pbkdf2
# 输入密码,复制输出的 grub.pbkdf2.sha512.xxxx 字符串
# 编辑 /etc/grub.d/40_custom,追加:
set superusers="admin"
password_pbkdf2 admin grub.pbkdf2.sha512.10000.8A2...[你的哈希]
# 重新生成配置,目标路径一定是这个:
grub2-mkconfig -o /boot/grub2/grub.cfg
另外 Anolis 8 默认启用了 grub2-efi 和 shim,如果你之前配置过 Secure Boot, 会报 efibootmgr 相关的警告——不影响密码功能,但看着膈应。装个 efibootmgr 包就行。
验证:重启后按 e 才是真验收
配置完别信终端输出。重启,在 GRUB 菜单出现时狂按 e。如果弹出一个黑底白字的对话框,要求输入用户名和密码——恭喜,防御生效了。用户名填 admin(就是 superusers 设的那个),密码输你刚才设的。通过后才能看到内核启动参数编辑界面。
要是直接进了编辑界面没弹框,八成是 01_users 或 40_custom 里的 superusers 变量被后面的脚本覆盖了。排查方法:进系统后跑 grep -r 'superusers' /etc/grub.d/ 看有没有重复 superusers 记录,然后检查 /etc/grub.d/ 下所有脚本的 set superusers= 行——只保留一份。
CentOS 8 还有个坑:如果系统是 UEFI 模式但 /boot 挂载在独立分区, 可能把配置写到 /boot/efi/EFI/centos/grub.cfg 而非 /boot/grub2/grub.cfg。确认方法: 看看它是否指向 EFI 分区内的文件。指向对了才算完。
怎么知道 GRUB 有没有被动过
机房巡检时顺手跑一遍 并不费电,关键是要把输出固定下来当基线。一旦哪天比对发现 Modify 时间不对,立刻用 diff -u 看看到底谁动了手脚——通常黑客会塞进去一段 linuxefi 指向临时内核,或者在 initrd 后面补个 debug 开关。把这些差异记到值班手册里,下次碰见同类特征就能秒识别。
# 提取当前 grub.cfg 的 sha256sum
sha256sum /boot/grub2/grub.cfg > /var/log/grub_$(date +%Y%m%d).hash
# 跟上周的做比较
diff -u /var/log/grub_20261129.hash /var/log/grub_20261206.hash
光靠人工终究会漏,上 AIDE 才算稳妥。装完先改配置文件 /etc/aide/aide.conf,把 /boot/grub2/grub.cfg 单独拎出来设成 p+i+u+g——权限、 inode、用户、组全都校验。初始化数据库之后把 cron 塞进每夜任务,第二天早晨翻邮件,看见 ALERT 再深挖,误报率几乎为零。
若提示 ,八成是攻击者试图抹掉脚印;若看到 ,那就得考虑整台机器重建了。
服务器这东西,防得住防不住,说到底就看你愿不愿意在启动参数上多盯两眼。攻击者可不会嫌自己手脏,他只嫌你太好欺负。
评论