0%

Linux 忘记密码怎么办:从原理到实战

Linux 忘记密码怎么办:从原理到实战

这套操作的边界在哪

重置密码这件事,本质上是在绕过登录认证。所以在动手之前,有三个硬前提必须同时成立:

  1. 能接触到控制台。物理机前的显示器键盘,或者带外管理口(iDRAC、iLO、昆仑/泰山的 BMC、超聚变的 iBMC)提供的远程 KVM,虚拟机则是宿主机或云平台的 VNC 控制台。SSH 做不到这件事,因为所有方法都要求中断引导过程。
  2. 能进入 GRUB 菜单。如果 GRUB 设置了口令保护,需要先有 GRUB 口令;如果 GRUB_TIMEOUT=0 且菜单被隐藏,需要额外手段抢到按键时机。
  3. 根分区未加密,或者掌握 LUKS 口令。全盘加密的机器,没有解密口令时这套方法全部失效,这一点后面会再讲。

一、原理:为什么改一行内核参数就能改密码

第一,密码存的是哈希,改密码不需要知道原密码。/etc/shadow 里每个用户占一行,第二个字段是口令哈希。登录时由 PAM 把你输入的字符串按同样的算法算一遍,再和这个字段比对。既然比对的是哈希,重置密码就不必还原出原密码,用新密码的哈希覆盖这个字段就行,passwd 做的就是这件事。

第二,写这个文件需要 root,而拿到 root 又要先登录。/etc/shadow 属主是 root,权限为 000(RHEL 系)或 640(Ubuntu),普通用户改不了。要改密码得先是 root,要成为 root 得先通过登录认证,而登录正是过不去的那一关。在正常路径上,这是个死循环。

第三,开机过程中有一段现成的 root 权限。从加电到 login 打出提示符,内核、initramfs、systemd 都以 root 身份运行,这一整段不需要任何口令,认证只发生在最后的 login。所以在 login 之前把启动停住、落到一个 shell 上,这个 shell 就是 root,而且没有经过认证。

第四,停住启动的开关在内核命令行,GRUB 负责把它交到你手里。GRUB 是引导加载程序,开机时看到的内核选择菜单就是它,按 e 可以临时编辑内核命令行,改动只对本次启动生效,不写入磁盘。命令行里的 init= 指定由哪个程序担任 PID 1,默认是 systemd;改成 init=/bin/bash,systemd 就不会运行,login 不会被拉起,屏幕上出现的第一个提示符就是 root shell,此时执行 passwd 即可。

所以这行参数改的不是密码,是启动的终点。终点从 login 提前到 shell,认证就不在执行路径上了。开篇那三个硬前提也由此而来:编辑内核命令行要在控制台按键,所以 SSH 用不上;GRUB 是唯一的编辑入口,进不去就没有下手位置;根分区若被 LUKS 加密,内核挂载它之前就会索要解密口令,shell 落不下来。

可以停住启动的位置不止 init= 一处,凡在 login 之前都行。各发行版首选的位置不同,下一节说明这个差异。

二、断点:各家停在启动链的哪一步

RHEL 系首选停在 initramfs 里,Ubuntu 实际可用的位置在 systemd 之前,两者相差了大半条启动链。

搞清楚这个差异,第三章和第四章的操作步骤就不用死记。

下图标出了各个发行版的落点:

断点 A 由 rd.break 参数产生,它让 dracut 生成的 initramfs 在执行 switch_root 之前停住,此时真实根已挂到 /sysroot,但当前根仍是 initramfs 的内存文件系统,因此要 chroot 才能对目标系统操作。

断点 B 由 init= 产生,位置在挂载真实根之后、systemd 之前,当前根就是目标系统,不需要 chroot。

断点 C 是 Ubuntu 在 GRUB 菜单里预置的 recovery mode 条目,systemd 已经运行,只是停在了 rescue.target,菜单里有 root shell 选项。但这一条在重置口令的场景下走不通:Ubuntu 默认锁定 root 账户,那个 root shell 选项由 sulogin 把守,会索要 root 口令,而口令正是当前缺失的。

所以本文第三章的 Ubuntu 流程走的是断点 B。

三个断点的取舍:越靠前,环境越干净、受目标系统配置的影响越小,但可用命令越少、需要手工补的前置条件越多;越靠后,环境越完整,但目标系统的安全策略、服务状态也一并生效,可能形成新的阻碍。断点 C 被 sulogin 挡住,就是这条规律的一个实例。

各家的落点与随之而来的差异,汇总如下:

RHEL 系 Ubuntu
首选断点 initramfs 内(rd.break systemd 之前(init=/bin/bash
真实根挂载点 /sysroot,只读 /,只读
是否需要 chroot 需要 不需要
是否需修安全上下文 需要,SELinux 标签 不需要,AppArmor 按路径管控
initramfs 工具 dracut initramfs-tools
initramfs 断点参数 rd.break break=bottom
通用备选 init=/bin/bash,须在 passwd 前执行 load_policy -i recovery mode,但被 sulogin 拦截,实际用不了

停下之后要补的前置条件主要是两项,都源自启动流程被截断。

其一,根文件系统在启动早期以只读方式挂载,便于先行执行 fsck,改挂读写是正常流程稍后才做的动作,被截停跳过了,所以要手动执行 mount -o remount,rw。漏掉这一步,passwd 会报 authentication token manipulation error。

其二,RHEL 系默认启用 SELinux,passwd 的写入方式是删除旧文件再写入新文件,在策略尚未加载的环境里,新建的 /etc/shadow 得不到正确的安全上下文,标签变成 unlabeled_t,重启后 login 读不到该文件,表现为密码改了却仍登不进去,必须单独修复。Ubuntu 用的是按路径管控的 AppArmor,不给文件打安全标签,没有这一步。

截停、remount,rwpasswd、按需修安全上下文,这四步构成后续所有发行版流程的公共部分,各章的差异只在断点位置和补充步骤上。

三、Ubuntu Server 22.04 / 24.04

3.1 进入 GRUB 菜单

在开机自检后,持续按住 Shift 键(Legacy BIOS 引导),或者反复点按 Esc 键(UEFI 引导),进入 GNU GRUB 菜单。

image-20260710085244697

如果是 Ubuntu 24.04 的话,菜单外观略有差异:GRUB 版本从 22.04 的 2.06 升到了 24.04 的 2.12,按 e 编辑参数的操作两版一致。

几个实操经验:

  • 带外 KVM(iDRAC / iLO / iBMC)的键盘转发有延迟,按键要提前、要密集,宁可多按;
  • 虚拟机上如果始终抢不到菜单,可以先给虚拟机加大引导延迟,或者直接挂载安装 ISO 走救援模式;
  • 服务器版默认安装通常会显示菜单,桌面版单系统安装会隐藏,这是 GRUB_TIMEOUT_STYLE 的差异,不是故障。

3.2 方法 A:修改内核引导参数进入单用户 Shell

第一步:编辑内核引导参数

在 GRUB 菜单高亮默认条目,按 e 进入编辑,找到以 linux 开头的那一行(内容里含 vmlinuz),做两处修改:

  • 把该行中的 ro 改成 rw
  • 在行尾追加 init=/bin/bash

改完按 Ctrl + XF10 启动。这些修改只对本次启动生效,不写入磁盘。

第二步:在root shell 中改密码

启动后会直接落到一个 bash 提示符,此时 systemd 根本没有运行:

1
2
3
4
mount -o remount,rw /   # 保险起见再挂一次,有些内核参数组合下 rw 不生效
id # 确认当前登录身份
passwd 用户名 # 换成要重置的账户名;不带参数时改的是 root
sync # 落盘

典型的操作详见下图:

第三步:正确退出

退出方式是这里最容易出事的一步。因为 1 号进程是 bash 而不是 systemd,rebootshutdownsystemctl 全部无效或行为异常,直接断电又可能损坏文件系统。例如直接 reboot,系统会提示错误:

正确做法是把控制权交还给 systemd,让它继续完成正常启动:

1
exec /sbin/init

如果只想重启,也可以先 sync 落盘、再 mount -o remount,ro / 把根挂回只读,最后 echo b > /proc/sysrq-trigger 交由内核直接重启。

几个 Ubuntu 特有的注意点:

  • Ubuntu 默认不启用 root 账户,日常提权靠 sudo。所以绝大多数场景下,你要重置的是那个属于 sudo 组的普通用户,而不是 root。
  • 确实需要 root 直接登录时,执行 passwd root 设置口令即可。新哈希会整体覆盖 /etc/shadow 第二字段,原有的锁定标记随之消失,不需要再执行 passwd -u。若还要允许 root 通过 SSH 登录,需另行修改 /etc/ssh/sshd_config 中的 PermitRootLogin,Ubuntu 默认值是 prohibit-password
  • 如果那个用户被移出了 sudo 组,改完密码也拿不到管理员权限,在同一个 root shell 里补一句 usermod -aG sudo ethan

3.3 方法 B:Live 挂载 chroot(兜底)

当 GRUB 本身进不去、或者 /boot 已损坏时,用 Ubuntu Live 介质启动。选 Try Ubuntu 后打开终端:

在安装界面按 F2 进入 shell:

第一步:识别根分区

lsblk -f 列出分区和文件系统类型:

在输出里挑那个大容量、FSTYPE 为 ext4(或 xfs)、且不是 /boot 的分区,下面以 /dev/sda2 为例。如果根分区建在 LVM 上,lsblk -f 会多出一层缩进,真正要挂的是最里层的逻辑卷,形如 /dev/mapper/ubuntu--vg-ubuntu--lv,此时需先 vgchange -ay 激活卷组。

第二步:挂载根分区并确认

1
2
mount /dev/sda2 /mnt
mount | grep ' /mnt ' # 正常情况应当看到 rw

挂载后,原系统磁盘上的 /etc/shadow 在 Live 环境里的路径就是 /mnt/etc/shadow,可以直接读写。

这一步先别急着改密码。如果此时直接运行 passwd(还没 chroot),改的是 Live 系统自己的 root,不是目标系统。即便屏幕提示 password updated successfully,也只是改了临时 Live 系统的 root 口令,重启后目标系统的密码原封不动。下图就是未 chroot 时 passwd 提示成功的典型场景截图。

要让 passwd 作用到目标系统上,必须先把根切换过去,这就是下面第三、四步在做的事。

第三步:把 /dev 绑定挂载进来

1
2
3
mount --rbind /dev /mnt/dev
↑ ↑
源目录 第二个入口

--rbind 里,bind 表示绑定挂载,相当于给一个已有目录开第二个入口,两条路径指向同一批文件,不发生复制;r 表示递归,/dev/pts/dev/shm 这些子挂载点会一并带过去,只用 --bind 则不会。passwd 生成哈希时要读 /dev/urandom,所以这一步不能省。若后续命令报缺 /proc/sys,同样处理:mount --rbind /proc /mnt/procmount --rbind /sys /mnt/sys

为什么要多开这个入口:chroot /mnt 之后,/mnt 变成新的根,原来的 /dev 这条路径在新视野里不存在了,能看到的只有 /mnt 下面的东西(在 chroot 内部它显示为 /dev)。所以要在 chroot 之前,把设备节点从 /dev 这个位置也接到 /mnt/dev 这个位置,换根后才够得着。

第四步:chroot 切换根

1
2
3
4
chroot /mnt /bin/bash
↑ ↑
│ └─ 换根之后要运行的程序
└────── 把哪个目录当作新的根

执行 chroot /mnt 之后,对这个 shell 及其之后启动的所有程序来说,内核解析路径时不再从真正的 / 开始,而是从 /mnt 开始。

第三、四步顺序不能颠倒:rbind 负责把设备节点准备好,chroot 负责把视野切过去,先切视野再挂设备就晚了。

第五步:修改密码

1
passwd root

第六步:退出并重启

不要在 chroot 里直接 reboot。chroot 环境没有自己的 init,systemd 会给出警告,这条不是错误,但重启动作不会按预期完成:

正确顺序是先退出 chroot,再刷缓存落盘,最后在 Live 环境里重启:

1
2
3
4
exit          # 退出 chroot,回到 Live 环境
sync # 刷缓存落盘
umount -R /mnt # 用了 --rbind,必须带 -R 递归卸载,否则报 device is busy
reboot # 在 Live 环境里正常重启,记得取出安装介质

3.4 一个特例:云镜像

各家云厂商提供的 Ubuntu cloud image,root 和默认用户(ubuntu都没有设置口令哈希,登录完全依赖 SSH 密钥。这种机器”忘记密码”的正确解法不是重置口令,而是恢复密钥:在上述任一 root shell 中改写 /home/ubuntu/.ssh/authorized_keys,注意保持属主为该用户、权限为 700(目录)和 600(文件)。

当然,先用 passwd ubuntu 设个口令再从控制台登录也可行,但要确认 /etc/ssh/sshd_config 是否允许口令认证,云镜像默认多为 PasswordAuthentication no

四、RHEL 系:RHEL / CentOS / Rocky / AlmaLinux

RHEL 7及以上系列与 Ubuntu 的最大差别是 SELinux 默认处于 enforcing 状态,这带来了一个额外必做步骤。

4.1 RHEL 7 / 8 / 9:官方推荐的 rd.break 方法

Red Hat 官方给出的路径是在 initramfs 阶段打断启动。

第一步:进入 initramfs 断点

重启系统,在 GRUB2 引导界面按 e 键中断启动,随即显示出内核引导参数。

找到内核引导行,做两件事:

  1. 在行尾追加 rd.break
  2. 建议同时删掉 rhgbquiet,这样启动过程可见,出问题好排查。

这一行的开头在不同版本上不一样。

RHEL 7 分两种情况:BIOS 引导的机器是 linux16,UEFI 引导的机器是 linuxefi

RHEL 8 起统一为 linux。在 RHEL 7 上按 linux 去找会找不到,往下看 linux16linuxefi 那一行。不必记版本对应关系,那一行里带 /vmlinuz- 路径的就是它。

Ctrl + x 以修改后的参数启动,随后会出现 switch_root 提示符。

此时的状态需要理解清楚:initramfs 已经加载完毕,真实的根文件系统已经被挂载到 /sysroot,但是只读,而且系统还没有执行 switch_root。也就是说,你现在处于 initramfs 的最小环境里,能用的命令有限。

想确认自己确实停在了这个位置,可以执行 findmnt /sysroot 看挂载选项里是不是 ro,再 cat /proc/mounts | head 看当前根是不是 rootfstmpfs。确认是否停在断点,看提示符就够了,cat /proc/cmdline 只能证明参数传给了内核,证明不了参数生效。

RHEL 9.0 上有一个已知缺陷会让这一步直接失效:进去之后不给 shell,而是要求输入 root 口令。根因是 root 账户被锁时 systemd 会调用 sulogin,9.1 已修复。遇到时在内核命令行上一并追加 SYSTEMD_SULOGIN_FORCE=1 再试,或改走 4.3 的安装介质救援模式。

第二步:把真实根重新挂载为可写

1
mount -o remount,rw /sysroot

remount 与下一步的 chroot 先后皆可,区别只在路径写法:未 chroot 时写 /sysroot,已经 chroot 之后则写 /。但两者必须都做完再执行 passwd,漏掉 remount 会报 passwd: Authentication token manipulation error,这个报错不提只读,很容易被误判成 PAM 配置问题。

第三步:chroot 进入真正的系统

1
chroot /sysroot

第四步:改 root 密码

1
passwd root

第五步:处理 SELinux 上下文(本节重点)

在 initramfs 环境里 SELinux 策略没有加载,passwd 重写 /etc/shadow 时新文件拿不到正确的安全上下文,标签会变成 unlabeled_t。结果就是密码确实改了,但重启后 login 读不到 shadow 文件,登录依然失败,且报错信息毫无指向性。

应当执行:

1
touch /.autorelabel

这是 Red Hat 官方文档给的做法,代价是下次启动要遍历整个文件系统。

官方还给了一条省时间的路径:在第一步追加 rd.break 时一并加上 enforcing=0,改完口令执行 restorecon /etc/shadow,系统起来后再 setenforce 1 并用 getenforce 确认。两条路径二选一,不要混用。不加 enforcing=0 就在 chroot 里直接跑 restorecon,常因策略文件读不到而失败,标签仍是错的。

第六步:退出,继续启动

1
2
3
exit                          # 退出 chroot,回到 initramfs
mount -o remount,ro /sysroot # 把根挂回只读,可选但更干净
exit # 退出 initramfs shell,系统继续启动

两个 exit 分别退出 chroot 和 initramfs,退完之后启动流程会自行继续,不需要手工 reboot

重启后系统会自动遍历整个文件系统重打标签,大容量磁盘可能耗时数分钟到数十分钟,完成后会再自动重启一次。这一步是 touch /.autorelabel 的后果,不是需要你操作的步骤。

4.2 RHEL 6 及更早

这一代是 SysVinit 加 GRUB Legacy(0.97)的组合,不是 GRUB 2,操作方式与前面完全不同:在 GRUB 菜单按 e

选中 kernel 开头的行(不是 linux)再按 e 编辑

行尾加一个 single 或数字 1

回车确认后按 b 启动

启动后直接落到 root shell,passwd 改完 reboot 即可。

GRUB Legacy 还支持在菜单上直接按 a 追加参数,这个快捷方式在 GRUB 2 上没有。

单用户模式下 init 已经运行、根已按 /etc/fstab 挂载为读写,所以既不需要 remount,也不需要 chroot;SELinux 策略在 rc.sysinit 阶段已加载,通常也不需要 touch /.autorelabel

等保加固过的机器常会给单用户模式加上口令,配置点有两处:/etc/sysconfig/init 里的 SINGLE=/sbin/sulogin,以及 /etc/inittab 里的 su:S:wait:/sbin/sulogin。任一处生效,进单用户就会索要 root 口令。此时改用 init=/bin/bash(同样加在 kernel 行尾,并把 ro 改成 rw),启动后仍然可以用 passwd 改密码。

RHEL 6 的 ELS 已经结束,遇到这类机器时优先谈升级,而不是继续维持。

4.3 救援模式:安装介质兜底

GRUB 被口令保护、/boot 损坏、或者根本进不去引导菜单时,用安装 ISO 启动:

从 RHEL / Rocky / AlmaLinux 安装介质引导;

第一步:选择 Troubleshooting

第二步:选择 Rescue a Red Hat Enterprise Linux system

第三步:选择 1) Continue,救援环境会自动探测并挂载已安装系统。RHEL 7 及以上挂载点是 /mnt/sysroot,RHEL 6 是 /mnt/sysimage,进入前先看屏幕提示;

第四步:执行 chroot /mnt/sysroot

第五步:passwd root

第六步【关键步骤别忘记】:touch /.autorelabel

第七步:连续 exit,取出介质并重启。

4.4 RHEL 系的常见故障对照

现象 原因 处理
密码改成功,重启后仍登录失败 /etc/shadow 的 SELinux 标签丢失 重做一遍并补 touch /.autorelabel;用 restorecon 时须配合 enforcing=0
输入正确新密码提示账户被锁 pam_faillock 累计失败次数已触发锁定 faillock --user root --reset,Ubuntu 22.04 及以上同样用 faillock
passwd 报 token manipulation error 没有 remount,rw 补执行 remount,已 chroot 时路径写 /
提示密码过于简单被拒 pam_pwquality 复杂度策略 以 root 身份通常只警告不阻断;被硬性阻断时换用符合策略的复杂口令
e 后要求输入用户名口令 GRUB 已启用口令保护 国产化系统的默认口令见 5.1、5.2,修改方法见 5.3
启动过程要求输入解密口令 根分区启用了 LUKS 全盘加密 没有该口令则本文所有方法均无效
rd.break 进去后被索要 root 口令 RHEL 9.0 的已知缺陷,sulogin 拦截 追加 SYSTEMD_SULOGIN_FORCE=1,或升级到 9.1 及以上

五、国产化系统:openEuler 与银河麒麟 V10

这两个系统在党政军和行业信创项目里出现频率很高,且都做了一处默认加固,不知道的人会卡在第一步。

5.1 openEuler

第一步:过 GRUB 口令

多数 openEuler 版本默认为 GRUB2 启用了口令保护,按 e 之后会要求输入用户名和口令,默认用户名为 root,默认口令为 openEuler#12。这一步是与 RHEL 系最明显的差异,不知道这个口令的人在第一步就走不下去。

第二步:编辑内核引导参数

找到以 linux 开头的行,做两处修改:

  • 把该行中的 ro 改为 rw,使内核可以读写硬盘;
  • 在行尾追加 init=/bin/sh

这里为什么写 /bin/sh 而不是 /bin/bash?执行 ls -l /bin/sh 可以看到它是指向 bash 的软链接,两者在 RHEL 系上是同一个程序。

Ctrl + X 启动,进入单用户 shell。

image-20260814155346686

第三步:修改口令

1
passwd root

第四步:重打 SELinux 标签

openEuler 官方文档明确写明,系统默认启用 SELinux 且默认模式为 enforcing。因此在默认安装的机器上这一步必做,理由与第四章 RHEL 系相同:init=/bin/sh 环境下策略未加载,passwd 重写的 /etc/shadow 拿不到 shadow_t 标签,重启后 login 读不到该文件,表现为口令改了却登不进去。

1
touch /.autorelabel

只有在确认该机器已被改为 disabledpermissive 时才可跳过。判断方法是查配置文件,不要用 getenforce

1
grep ^SELINUX= /etc/selinux/config

init=/bin/sh 环境下 systemd 未运行、SELinux 策略未加载,getenforce 的输出反映的是当前这个残缺环境,不是目标系统的配置值。

第五步:退出

1
exec /sbin/init

1 号进程是 sh 而不是 systemd,rebootsystemctl 在这里无效或行为异常,把控制权交还给 systemd 继续正常启动是社区资料一致给出的做法。若执行了 touch /.autorelabel,重启后会有一次全盘重打标签,完成后系统自动再重启一次。

补充一点:openEuler 的 initramfs 同样由 dracut 生成,rd.break 从机制上看可用,但社区与厂商资料通行的写法是 init=/bin/sh,样本更多,本文以后者为准。另外 init=/bin/sh 与麒麟那边写的 init=/bin/bash,在 RHEL 系上执行的是同一个程序,因为 /bin/sh 是指向 bash 的符号链接,差别仅在于 bash 以 sh 名字调用时会进入 POSIX 兼容模式,对本文用到的命令没有影响。Ubuntu 不同,它的 /bin/sh 指向 dash,所以那边只能写 init=/bin/bash

5.2 银河麒麟高级服务器操作系统 V10

第一步:过 GRUB 口令

麒麟 V10 服务器版同样默认启用了 GRUB 口令,默认用户名为 root,口令为 Kylin123123

第二步:编辑内核引导参数

进入编辑界面后,在 linux 开头的行末追加 rw init=/bin/bash

开启了图形登录的机型,再追加 console=tty0,把 shell 输出定向到当前控制台。

第三步:修改口令

1
passwd root

第四步:退出重启

单用户环境下直接执行 reboot 往往无效,需要指定完整路径,虚拟机环境建议加 -f 强制重启:

1
/usr/sbin/reboot -f

也可以用 exec /sbin/init 把控制权交还给 systemd 继续正常启动。

关于 SELinux:实测该机器不需要重打标签,getenforce 返回 Disabled/etc/selinux/configSELINUX=disabled。麒麟不同 SP 版本的默认值未必一致,动手前建议先查一次这两项再决定是否执行 touch /.autorelabel

5.3 交付前必须改掉默认 GRUB 口令

openEuler#12Kylin123123 属于公开的出厂默认口令,任何拿到过设备说明的人都知道。系统交付上线时应当立即修改,这一条在等保测评和验收检查中属于常规检查项,实际项目中被查出来的概率不低。

最省事的方式是交互式修改,部分版本命令名为 grub2-setpassword

1
2
3
4
grub2-set-password
# Enter Current password: 输入当前口令,如 openEuler#12
# Enter password: 输入新口令
# Confirm password: 再输一遍

六、云主机与虚拟化环境

云上的差别不在命令,而在能不能拿到控制台。

  • 控制台入口:各家云厂商都提供 VNC 控制台或串口控制台(Serial Console),用它替代物理显示器。串口控制台需要系统侧启用 console=ttyS0,多数官方镜像已默认启用。
  • GRUB 菜单一闪而过:云镜像常把 GRUB_TIMEOUT 设为 0 或 1。处理办法是在控制台连上后立即重启并持续点按 Esc;或者挂载救援盘启动;或者把系统盘卸载后挂到另一台同区实例上,chroot 进去改。
  • 厂商自带的重置密码功能:阿里云、华为云、腾讯云控制台都有”重置实例密码”按钮,依赖镜像内的 cloud-init 或云助手 agent。前提是这些组件仍在正常运行,自定义镜像里被裁剪掉的情况很常见,用之前先确认。
  • KVM 宿主机上离线改libguestfs-tools 提供了直接改磁盘镜像的能力,虚拟机需处于关机状态:
1
2
3
4
5
virsh shutdown vm                      # 必须先关机
export LIBGUESTFS_BACKEND=direct # 非 root 执行时避免 qemu:///session 连接报错
virt-customize -a /var/lib/libvirt/images/vm.qcow2 \
--root-password password:新密码
virsh start vm

七、速查表

系统 首选路径 关键命令序列 特别注意
Ubuntu Server 22.04 / 24.04 GRUB 编辑,rorw 并加 init=/bin/bash mount -o remount,rw /passwd 用户名exec /sbin/init root 默认锁定,一般改的是 sudo 用户;不能用 reboot 退出
Ubuntu(recovery mode) 不可用于重置口令 菜单里的 root shell 由 sulogin 把守 会索要 root 口令,改走上一行
RHEL 7 / 8 / 9 GRUB 行尾加 rd.break mount -o remount,rw /sysrootchroot /sysrootpasswd roottouch /.autorelabelexit exit RHEL 7 找 linux16
RHEL 6 及更早 GRUB Legacy,kernel 行尾加 single 直接root shell → passwdreboot 也可以改为增加 init=/bin/bash rw的方式
openEuler GRUB 口令 root / openEuler#12,走 init=/bin/sh rorwinit=/bin/shpasswd roottouch /.autorelabelexec /sbin/init 默认 SELinux 为 enforcing,标签必须处理;不需要 chroot
银河麒麟 V10 服务器版 GRUB 口令 root / Kylin123123 行尾加 rw init=/bin/bashpasswd root/usr/sbin/reboot -f 图形登录机型加 console=tty0;SELinux 默认关闭
云主机 控制台 + 上述对应方法,或厂商重置功能 关机后 virt-customize --root-password 离线改 厂商功能依赖 cloud-init 或 agent 仍在运行
以上全部走不通 安装介质救援模式 / Live USB 挂载根分区 → --rbind/dev /proc /syschrootpasswd RHEL 系别忘 touch /.autorelabel

总结

重置密码的所有分支,都可以归结为同一个动作:在认证发生之前抢到一个能写根文件系统的 shell

Ubuntu 走 init=/bin/bash,RHEL 系走 rd.break 加 chroot,国产化系统先过 GRUB 默认口令这一关,最后还有安装介质救援模式做兜底。remount,rw 是所有路径都要做的;

SELinux 标签处理只在 RHEL 系和 openEuler 上需要,Ubuntu 用 AppArmor、麒麟实测默认关闭 SELinux,都不涉及。

漏掉这两项中该做的那项,都会表现为”看起来成功了但登不进去”。

而这套方法之所以成立,恰恰说明登录口令保护不了物理接触到的机器。真要防,方向是 GRUB 口令、BIOS 口令、带外管理口隔离,以及全盘加密。