1. 先搞清楚“破解”背后的机制:/etc/shadow与密码哈希算法
先泼一盆冷水:所谓Linux root密码和普通用户密码的“破解”,在绝大多数场景下不是暴力跑字典,也不是SQL注入绕过,而是找到一条系统本人提供的入口,把密码“重置”掉。这就像你钥匙丢了,不是去撬锁,而是直接找物业开备用钥匙——前提是你得证明这房子是你的。
搞懂这个区别很重要。网上搜“root密码破解”,一大堆教程上来就让你跑John the Ripper、hashcat,说是拿/etc/shadow里的哈希去撞库。说实话,除非用户密码真的弱到像“123456”,否则在你有系统文件读取权限的情况下,等哈希撞出来早就该下班了。更高效的思路是:哪个环节允许我们不验证旧密码直接改新密码?答案就在系统启动流程里。
先认识一下我们操作的靶子。/etc/shadow文件存的就是用户密码哈希和策略信息,它权限是000或者600,只有root能读。一行记录大概长这样:
bash复制root:$y$j9T$vQa0He...:19000:0:99999:7:::
用冒号拆开看,第1列是用户名,第2列是密码哈希,后面分别是最近修改日期、最短修改间隔、密码有效期、过期警告天数等。重点看第2列:
$y$j9T$...:这是yescrypt算法,RHEL 9/CentOS Stream 9等新系统默认。$6$...:SHA-512,RHEL/CentOS 6到8时代的默认值。$5$...:SHA-256,偶尔见。$1$...:MD5,很老很老。
算法变化直接影响一件事情:同样的密码,不同版本系统生成的哈希不能互相用。你从老服务器拷一个shadow里的root行到新系统,密码可能刷不进去,因为新系统验证时要算出对应哈希,算法标识对不上就永远不会匹配。所以跨版本重置密码时,最稳的做法不是手动编辑shadow,而是用passwd命令让它按当前系统默认算法重新生成哈希。
然后是/etc/passwd和/etc/shadow的分工。/etc/passwd所有人都能读,记录了用户名、UID、主目录、登录shell这些信息,密码位一律是x,真正的密码哈希被抽离到shadow中。这也是上世纪Unix为了配合影子密码(shadow password)机制做的安全改动。
在动手之前,记住一条底线:只有你自己拥有物理访问权限或管理权限的设备才能这么做。 操作别人的机器,未经允许重置密码,性质完全不同,这个边界大家要拎清楚。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 现代Systemd系统:rd.break在GRUB处重置root密码
先讲适用面最广的方案,因为现在主流发行版(RHEL 7/8/9、CentOS 7/8/9、Fedora)都是systemd时代,启动流程里有一个很适合我们做应急恢复的开关——rd.break。
rd.break是dracut(早期用户空间)提供的一个调试参数,作用是在initramfs处理到某个阶段时主动中断,丢给你一个shell。这个shell运行在内存文件系统里,真正的系统根目录还没挂载到/上,而是暂时放在/sysroot。听起来绕,但好处很明显:这个环境下没有用户认证,直接就是root权限的shell,属于“系统自己开的门”。
操作流程如下:
- 重启服务器,在GRUB菜单界面停住。如果是单系统默认直接进,就快速按方向键或Esc,把菜单按住别让它溜走。
- 光标移到要启动的内核条目上,按
e进入编辑模式。 - 找到以
linux开头的那一行(RHEL系列一般是linux16或linux),把光标移到行尾,在末尾加一个空格,然后输入rd.break。 - 按
Ctrl+x或F10启动,系统会进入initramfs的shell,提示符看起来像switch_root:/#。 - 此时根目录还是只读挂载,先把
/sysroot改为可读写:bash复制
mount -o remount,rw /sysroot - 切换到真正的系统环境:
bash复制chroot /sysroot - 这个时候你已经站在真实的根目录里了,直接重置root密码:
bash复制
跟平时改密码一样,输两次新密码,注意输入时不显示字符属于正常现象。passwd root - 退出chroot并重启:
bash复制或者直接按电源重启,因为此时initramfs状态并不完整,不能保证正常reboot流程走完。exit reboot -f
整个过程不超过两分钟。但这里面有几个坑,都是我自己踩过的。
第一个坑:SELinux的autorelabel问题。 在RHEL/CentOS这类默认开启SELinux的系统上,你用passwd改密码,修改的是/etc/shadow文件。正常情况下SELinux的文件上下文(context)是没变的,因为文件还是那个文件,只是内容变了。但如果你手贱用vi编辑shadow,或者用chmod动权限,再或者系统文件系统损坏后导致某些文件context丢失,重启后就可能出现登录时卡在SELinux拒绝或者权限验证失败。
最稳妥的做法:如果你改完密码后心里没底,就在chroot环境里执行:
bash复制touch /.autorelabel
这样重启后系统会自动重新给所有文件打上正确的SELinux标签,代价是重启时间会变长,大分区可能要等几分钟。如果不想全盘relabel,也可以只修复shadow文件:
bash复制restorecon -v /etc/shadow
第二个坑:SELinux处于Enforcing时,rd.break模式下chroot进去的shell可能没有正常的安全策略上下文,某些命令会被拒绝。 如果碰上passwd命令执行不了或报错,先看SELinux状态。在rd.break的shell里,系统还没完全进入SELinux enforcing,但/sysroot内的策略文件还在,chroot后可能会被加载部分策略。少数情况下,你需要先临时把SELinux设为permissive:
bash复制echo 0 > /sys/fs/selinux/enforce
然后改完密码,再确认一版autorelabel或restorecon。
第三个坑:千万别在rd.break里随便挂载或者卸载分区。 有些人一进去就想mount -o remount,rw /,然后抱怨找不到根目录。rd.break里真正的根是initramfs,不是硬盘上的根,所以必须操作的是/sysroot——这对新手是个很大的认知障碍。记住对应关系:/sysroot = 硬盘上的真实根目录。
还有个小细节:rd.break后面还可以加参数,比如rd.break=pre-plymouth、rd.break=pre-mount,会在更早或更晚的时机中断。默认加在行尾不带等号时,中断点是在switch_root之前,正好适合我们操作。一般不用纠结,默认就行。
那为什么不推荐旧式的single单用户模式?在RHEL 7以后,如果你只在内核行加single,系统还是会走完大部分早启动流程,然后在SELinux相关阶段可能会要求输入root密码,或者在multi-user.target之前直接让你登录——这就尴尬了,你忘的恰恰是root密码。所以rd.break更可靠,它是“在认证发生之前”直接给shell。
3. 老系统应急路:init=/bin/bash与单用户模式
如果是CentOS 6、RHEL 6,或者手头一台老掉牙的Ubuntu 14.04服务器,那套rd.break可能不好使,因为当年的initramfs和dracut体系跟现在不一样。这时候换一个同样经典的方法:给内核传init=/bin/bash。
思路是这样的:内核启动完成后本来要启动第一个用户态程序(init),我们直接把它换成/bin/bash,等于机器一开机就给你一个root shell,不加载任何服务,也不需要登录。配合一点挂载操作,就能改密码。
具体步骤:
- 同样在GRUB菜单按
e编辑内核启动行。 - 找到
kernel开头的那行(老系统是kernel,不是linux),行尾加空格,然后追加:bash复制
init=/bin/bash - 启动后你会直接掉进一个root shell,提示符一般是
bash-4.1#这种。 - 但此刻根文件系统是只读挂载的,先重新挂载为可写:
bash复制
注意这里是mount -o remount,rw //,不是/sysroot,因为老系统此时直接挂在硬盘根上了。 - 使用passwd重置root密码:
bash复制
passwd root - 如果系统用了SELinux,改完后建议执行:
bash复制touch /.autorelabel - 直接
reboot -f强制重启。
这个方案在RHEL 6/CentOS 6上几乎是100%成功的,而且比rd.break还少一层chroot。但有个致命问题:如果GRUB密码被设置了,你根本进不了编辑界面;就算进了,内核参数也可能被限制。
再说说Ubuntu/Debian的老派玩法。Ubuntu一直自带一个“恢复模式”(recovery mode),在GRUB菜单的Advanced options里能看到。选recovery mode启动,会弹出一个菜单,里面有root - Drop to root shell prompt选项。选它后会有一个只读的root shell,需要先执行:
bash复制mount -o remount,rw /
然后再passwd root或passwd 用户名。这个入口在Ubuntu上极其好用,因为很多Ubuntu系统根本没设置GRUB密码,恢复模式等于大白门敞开。
对比一下两个方案适用场景:
| 方案 | 适用系统 | 优点 | 缺点 |
|---|---|---|---|
| rd.break | RHEL 7+/CentOS 7+/Fedora | 流程统一,官方留的后门 | 要经过chroot,新手容易迷路 |
| init=/bin/bash | CentOS 6/RHEL 6及更老 | 直接进shell,少一层 | 老系统专属,新内核不推荐硬试 |
| Ubuntu恢复模式 | Ubuntu/Debian系 | 不用记参数,菜单操作 | 只读挂载,需要手动remount |
两个方案共通的潜在问题是:如果内核行被ro只读参数限制,且系统根文件系统是LVM或加密磁盘,那么在挂载前可能还需要激活卷组或解密。 比如用LVM的系统,进shell后ls /dev/mapper可能看不到逻辑卷,需要手动vgchange -ay激活。密文盘的话更麻烦,要提前准备好密钥文件。这个场景在企业里不少见。
4. 救援模式与嵌入式Linux:急救盘和厂商引导的密码恢复
不是所有密码丢失都发生在能接触到GRUB的服务器上。三种情况很常见:一是GRUB损坏或被密码保护;二是云主机/虚拟机只能通过控制台访问,但GRUB菜单秒过,来不及按键;三是嵌入式设备,压根没有标准GRUB菜单。
这时候用安装光盘或急救U盘进入救援模式(rescue mode)是标准答案。
以RHEL/CentOS安装镜像为例:
- 用同版本或相近版本的安装盘启动,选择
Troubleshooting,再选Rescue a CentOS system。 - 系统会提示选择语言、键盘布局,然后问你是否要挂载已有系统。选择
1(Continue)让它自动探测。 - 探测成功后它会提示根目录挂载到了
/mnt/sysimage,然后问是否要给shell。 - 得到shell后执行:
bash复制chroot /mnt/sysimage passwd root - 若系统有SELinux,改完后执行
touch /.autorelabel或restorecon -v /etc/shadow,然后退出重启。
这个流程比rd.break多一步,好处是不依赖GRUB是否完好——只要磁盘能被识别,就能进系统改密码。遇到LVM、RAID、加密磁盘,救援模式也会在挂载前自动尝试激活,比手动在initramfs里折腾省心太多。
如果把范围扩大到嵌入式Linux,思路就得变一变。嵌入式设备(路由器、开发板、ARM盒子)常用U-Boot引导,密码恢复套路完全不同。最常见的是在U-Boot倒计时阶段打断启动,进入U-Boot命令行,手动指定一个备用init:
bash复制setenv bootargs "${bootargs} init=/bin/sh"
boot
这样内核起来后直接进sh,根文件系统一般是只读,同样需要:
bash复制mount -o remount,rw /
然后再爱怎么改怎么改。有的设备更直接:把存储介质(SD卡、eMMC模块)拆下来,插到读卡器里挂载到正常Linux机器上,直接编辑shadow文件,把密码字段删掉或用已知哈希替换。这个方法粗暴有效,但需要设备支持拆卸存储。
嵌入式场景还有一个特殊点:很多设备根本没有多用户概念,root密码就是唯一入口,而且文件系统可能是只读的squashfs。那就要看是否有overlay层,把可写层挂出来改密码,或者干脆用出厂复位机制。所以嵌入式设备的“密码破解”往往不是改shadow,而是调整启动流程或恢复出厂配置。
对比一下思路的本质:密码恢复不过三个入口——启动参数注入(改内核cmdline)、外部介质挂载(拆盘/急救盘)、系统自身恢复机制(Ubuntu recovery mode/出厂复位)。 你手上有哪个入口,用哪个方案。
5. 普通用户密码重置与批量管理:passwd、chpasswd与脚本化
聊完root,再说普通用户。普通用户密码丢失的恢复方案比root简单,因为只要有root权限,随时可以重置任何账号的密码,不需要重启,不需要进单用户模式。
最简单的命令:
bash复制passwd zhangsan
输入两次新密码,搞定。但这不是说没有坑。第一个坑是:有些普通用户可能被锁定了,而不是单纯忘记密码。 判断方法:
bash复制passwd -S zhangsan
输出可能是zhangsan L(locked)、zhangsan P(可用密码)、zhangsan NP(无密码)。如果显示locked,别光改密码,还要解锁:
bash复制usermod -U zhangsan
第二个坑是:如果你重置密码时强制用户下次改密,命令是chage -d 0 zhangsan,这会把最近修改日期设为0,导致用户下次登录必须立即改密码。 这个在日常运维里很常用,但给用户交代不清楚的话,对方会以为系统出问题了。
再说批量环境。一个运维手里几十台机器,或者一个班级实验环境里有40个普通用户,逐条passwd会被累死。正确做法是用chpasswd。
给单个用户改:
bash复制echo 'zhangsan:NewPass2024' | chpasswd
给多个用户改,准备一个文件,每行格式用户名:密码:
bash复制chpasswd < users.txt
chpasswd还支持-e参数,表示密码字段已经是加密过的哈希,这在批量初始化账户时很有用,可以避免空密码或弱密码过渡期。结合openssl或mkpasswd生成哈希:
bash复制openssl passwd -6
然后拼进users.txt,用chpasswd -e导入。
还有一个企业里常见的需求:批量把一批新员工账号创建出来,统一初始密码,并且强制首次登录改密。可以串起来写一个简单的bash脚本:
bash复制#!/bin/bash
# 读取users.txt,每行一个用户名
while read user; do
# 创建用户,指定家目录和shell
useradd -m -s /bin/bash "$user"
# 设置初始密码
echo "${user}:Init@2024" | chpasswd
# 强制首次登录修改密码
chage -d 0 "$user"
done < users.txt
注意几个细节:useradd在有些发行版上不创建家目录,需要加-m;默认shell在部分精简系统上是/bin/sh,如果想给bash体验要显式指定;chpasswd不管用户是否存在,都会尝试设置密码。
再说一个容易忽略的运维习惯:忘记普通用户密码时,如果用ssh密钥登录还在生效,其实不用重启,直接ssh进去然后用sudo切root再重置。 这提醒我们,运维环境里一定不要把鸡蛋放一个篮子里,至少给root或某个管理员账号配置ssh密钥,留一条不依赖密码的高可用通道。我见过太多因为密码过期导致ssh登录全线崩溃的案例——密码认证失败不可怕,可怕的是没有备用通道。
6. 反方向思考:如何加固系统让单用户模式无法被滥用
既然单用户模式能重置密码,那是不是意味着只要摸到机器就能拿root?差不多就是这样。所以系统的“密码破解”本质上是个物理安全与引导安全的问题。为了让这台机器不至于被人随便敲几下键盘就沦陷,得做几件事。
第一道闸门:GRUB密码。
用工具一键生成:
bash复制grub2-setpassword
它会让你输入两次密码,然后把哈希写进/etc/grub.d/01_users,并在下次生成grub.cfg时生效。设置之后,想在GRUB菜单按e进入编辑,必须先验证GRUB用户和密码。这直接封死了rd.break和init=/bin/bash两条路——没密码连内核命令行都碰不到。
记得重新生成GRUB配置:
bash复制grub2-mkconfig -o /boot/grub2/grub.cfg
在Ubuntu/Debian上是update-grub。
第二道闸门:锁掉交互式启动参数。
光有GRUB密码还不够,有些人会在GRUB菜单直接按c进入命令行,或者选择不同内核条目。GRUB密码本身已经能拦住这些操作,但还需要把策略做得完整一点:GRUB_DISABLE_RECOVERY="true"这个选项在部分系统上可以隐藏恢复模式菜单。另外/etc/sysconfig/grub中如果有GRUB_CMDLINE_LINUX,别往里面塞什么single之类的后门参数,免得自己给自己留洞。
第三道闸门:BIOS/UEFI固件密码。
GRUB密码是软件层面的,如果攻击者能直接进BIOS,改启动顺序从U盘启动,GRUB密码就形同虚设。所以服务器级别的设备,必须设置BIOS/UEFI密码,同时关闭掉不需要的启动介质。物理机还要考虑机箱锁——运维圈有句话叫“能碰到电源按钮的人,原则上已经是半个管理员”。数据中心的机柜门禁、KVM/IPMI的访问控制,也都属于这一环。
第四道闸门:加固shadow文件本身。
一个偏门的方案是给shadow文件加不可变属性:
bash复制chattr +i /etc/shadow
加完之后,任何用户(包括root)都没法直接修改或者删除shadow文件,passwd命令也会报错。需要改密码时先去掉属性:
bash复制chattr -i /etc/shadow
这招能堵住一些“拿到root shell后直接改文件”的路径,但前提是你记得自己设置过这个属性,不然会在下一次改密码时卡半天。生产环境慎用,容易给自己挖坑。
第五道闸门:升级加密算法。
算法决定了暴力破解的成本。RHEL 9默认yescrypt,设计目标就是对抗GPU暴力破解,参数开销比SHA-512高了一个数量级。如果还在用老系统,可以把密码算法迁移到更健壮的版本。具体做法是修改/etc/pam.d/system-auth和/etc/pam.d/password-auth中的pam_unix.so行,加上rounds=65536之类的参数,或者干脆升级系统。密码学上有一个规律:你能设置的密码再复杂,也不如系统帮你把单次哈希算得慢一点——对于在线服务来说登录慢个几百毫秒无所谓,对攻击者来说跑一遍字典的时间则是天文数字。
做完这五件事,单用户模式重置密码这条路基本就被堵死了。代价是什么?代价是如果你自己忘了root密码,不好意思,得走完整的身份验证流程,比如找有权限的同事、走变更流程、用带外管理口登录。这很折腾,但安全本来就是在便利性和防护之间做取舍。
我个人的建议是:对于重要生产环境,GRUB密码和BIOS密码必开;对于虚拟机环境,至少设置GRUB密码,并保证有hypervisor层面的管理员能通过控制台介入;对于个人电脑和测试机,则不需要过度防护,毕竟自己忘了密码还能快速恢复才是真实需求。安全策略永远是场景驱动,不要为了秀操作把机器锁死。
