☰
VirtualBox Ubuntu忘记密码?三招GRUB救援法快速重置
2026/10/20 20:59:22 网站建设 项目流程

半年前我组装了一台VirtualBox里的Ubuntu虚拟机,专门用来跑一个内部演示环境,装完把密码抄在一张便利贴上,随手贴到屏幕边框。三个月后演示要用,我翻遍工位也没找到那张便利贴,试了十来个常用密码全部报错。当时第一反应是重装系统,半小时就能搞定,但机器里已经装了三个中间件和一整套初始化脚本,重装意味着所有配置推倒重来。最后我是通过GRUB的Recovery Mode进入root shell,一条passwd命令解决问题,全程五分钟,比重装省的不是一星半点。

这种"VirtualBox虚拟机Ubuntu忘记密码"的场景,在开发机、测试环境、交付镜像里都太常见了。很多人一忘了密码就急着重装,其实在虚拟机环境下,密码丢失后的救援路径比物理机宽得多。这篇文章我会把三套完整方案讲透:最常用的GRUB Recovery Mode方案、Recovery进不去时的GRUB启动参数注入方案,以及连系统引导都损坏时的磁盘级救援方案。每套方案都给出可复制的命令,同时把我在实际踩坑中遇到的边界情况和判断依据一并讲清楚。

1. 忘记密码不等于要重装:三条救援路径的底层逻辑

1.1 先搞明白Linux的密码到底存在哪里

很多人一遇到忘记密码就慌,是因为把"密码"想成了一个必须靠登录界面才能修改的东西。实际上,Linux系统里的用户密码并不是什么不可触碰的神秘数据,它只是/etc/shadow文件里的一串哈希值。

用户信息本身记录在/etc/passwd里,包括用户名、UID、主目录这些;而真正的密码哈希、密码最后修改时间、过期策略这些敏感内容,统一放在/etc/shadow里,普通用户没有读权限,只有root能改。当你在终端里执行passwd 用户名时,系统会自动生成新的加密哈希,并把这个哈希写回/etc/shadow。

搞清楚这一点,救援思路自然就清晰了:只要能拿到一个对根文件系统有写权限的root shell,再执行一次passwd,密码就能重置,跟原密码是什么、丢没丢、有多复杂,没有任何关系。

也正因为这个机制,Linux下救援密码的核心动作从来不是"找回旧密码",而是"构造一个能修改/etc/shadow的执行环境"。在VirtualBox虚拟机里,这种环境有三种来源:系统自带的Recovery Mode、内核启动参数注入、以及从宿主机侧直接操作虚拟磁盘。这三条路径,分别对应系统能半启动、GRUB还能用、系统彻底起不来这三级故障。

1.2 救援之前的第一动作:给虚拟机拍一次快照

理论归理论,实际操作中我要先说一个比改密码更优先的动作——先拍快照。

在VirtualBox主界面选中目标虚拟机,点击"拍摄快照",或者在命令行执行:

VBoxManage snapshot "你的虚拟机名" take "before-pw-reset"

这一步的性价比极高。不管接下来的操作多粗糙,哪怕我把GRUB参数改乱了、把分区挂载错了、或者手滑把密码改成了另一个人也记不住的值,都能通过快照一键回到操作前的状态,相当于给自己留了一颗后悔药。

快照本身不占用太多磁盘空间,它会生成一块差异盘,后续写入的数据才单独保存。所以不用担心快照会撑爆硬盘,反而应该在所有系统关键操作前都养成拍快照的习惯。对VirtualBox里长期跑着业务的Ubuntu虚拟机来说,这个习惯能挽回的损失远超那点磁盘开销。

1.3 哪些情况救不了,提前说清楚

既然标题是"解决方法",我也得诚实交代一下边界。以下三种情况,以下任何方案都救不了:

  • 虚拟机启用了LUKS全盘加密,而且连加密分区的密码也丢了。这种情况下,系统在引导阶段就无法解密根分区,根本没机会进入Recovery Mode,宿主机也只能看到一个加密后的数据块。
  • 虚拟磁盘文件本身已经损坏,连VirtualBox都无法挂载这块vdi。
  • 你之前开启了磁盘加密,或者根本没有任何备份和快照。

全盘加密的虚拟机一旦连解密密钥都丢掉,唯一的出路就是重装加上恢复备份。所以如果你们的系统有合规要求必须开加密,请务必把恢复密钥单独保存在某个可靠的地方,不要和系统密码混在一起。

2. 最推荐的做法:GRUB Recovery Mode改密码,五分钟完成

2.1 进入Recovery Mode的两种姿势

Ubuntu发行版内置了Recovery Mode,这是官方预设的救援入口。在GRUB引导菜单里,它对应的是"Advanced options for Ubuntu"下面的一个特殊内核条目。

但问题来了:现在的Ubuntu默认为了启动提速,GRUB菜单是被隐藏的,开机画面一闪就进系统了。要让GRUB菜单乖乖出现,有几种操作方式:

  • 在虚拟机窗口上先点击一下,确保键盘焦点已经进入虚拟机内部,然后立刻按住键盘左下角的左Shift键不放,直到GRUB菜单出现。
  • 如果Shift不奏效,换成连续快速点按Esc键,同样可以达到强制显示GRUB菜单的目的。
  • 在UEFI模式下,部分版本需要用Esc键而不是Shift,建议两种都试一下。

还有一个容易被忽略的点:VirtualBox默认在系统启动时并不会等用户,虚拟机内一旦检测到引导项就直接开始加载,留给按Shift的时间窗口很短。我自己的习惯是:在VirtualBox工具栏里先让虚拟机"关机",再重新点击"启动",然后在启动的一瞬间把鼠标点进虚拟机窗口、键盘放在Shift键上。多试一次就能摸准那个节奏,不需要什么高深技巧。

GRUB菜单出现后,选择"Advanced options for Ubuntu"这一项,进入子菜单后你会看到各个内核版本,挑一个名字后面带"(recovery mode)"的条目回车,就会进入一个蓝底白字的恢复模式菜单。

2.2 重置密码的完整命令链

在恢复模式菜单里,你会看到几个选项:resume、clean、dpkg、network、root等。我们需要的不是网络也不是修复软件包,而是最下面那个"root"——进入root shell提示符。

选择后,系统会挂载一个只读的根文件系统并进入root shell。这里有个坑:此时根目录是只读挂载的。你直接执行passwd,大概率会得到类似passwd: cannot lock /etc/passwd的报错。所以第一步是先手动重新挂载为可写:

mount -o remount,rw /

接着查看当前系统里的用户,确认你要重置的是谁:

ls /home

如果有多个用户目录,可以用名字判断。确认用户后直接重置密码:

passwd 用户名

输入两遍新密码,命令没有任何“旧密码验证”,直接完成。如果是想给root账号设密码,那就在root shell里执行passwd root。

改完后,在shell里输入exit退出,回到恢复模式菜单,选择"resume"继续正常启动即可。等系统进入登录界面,用刚设置的新密码登录,一切正常。

2.3 Recovery模式进不去时的常见原因

这条路大多数情况能走通,但也有翻车的时候。我遇到过的几个典型情况:

一是虚拟机显示器分辨率太低、屏幕显示不全,恢复菜单看起来像是卡住了。这种时候别急,按几下回车键或者方向键,把焦点拉回来一般就好。

二是GRUB菜单死活不出来。这时候可以先在正常启动的系统里修改GRUB配置文件让菜单永久显示。具体的做法我会在后面的善后章节细讲,但思路就是把隐藏菜单改成显示菜单,这样以后每次开机都能直接看到GRUB。

三是用户创建时勾选了加密主目录(ecryptfs)。老版本Ubuntu里创建用户时有一个"encrypt my home folder"的选项,如果当初勾选了这个,重置密码后登录时会因为无法解锁主目录而出现诡异的现象。现代Ubuntu默认不加密主目录,一般不受影响,但如果你管理的是多年前建立的虚拟环境,改完密码后请留意主目录是否正常。

3. Recovery进不去时的备选:修改GRUB启动参数直接注入root shell

3.1 为什么会有这条通道,它和Recovery有什么区别

Recovery Mode本质上是一个预先配置好的救援内核,它会加载一系列辅助脚本然后弹出菜单。但如果这个内核本身出了问题、或者你在恢复模式下无论怎么操作都黑屏,那就需要绕开Recovery,直接在GRUB层面做手脚。

GRUB在加载Linux内核之前,会把内存中的linux命令行参数传给内核。这些参数里包含根分区位置、只读还是可写、是否显示启动日志等信息。如果我们在这个参数里追加一句init=/bin/bash,内核启动时就直接用bash替换掉正常的init程序,系统会以root身份运行一个bash shell,全程不会经过登录认证。

这个方案的特别之处在于:它不依赖Recovery Mode的菜单脚本,只要GRUB菜单能打开、内核能加载,就能拿到一个root shell,所以适用面比Recovery Mode更广。代价是它要求你稍微懂一点GRUB编辑器操作,并且要小心别把别的启动参数改坏。

3.2 具体步骤:在GRUB菜单里按下e键

整个过程和Recovery Mode一样,第一步还是先把GRUB菜单调出来。出现菜单后,不要按回车,而是直接按下字母e,进入GRUB启动项编辑界面。

在编辑界面里,你会看到两行比较关键的内容,一行以linux开头,写法差不多是这个样子:

linux /boot/vmlinuz-5.15.0-91-generic root=UUID=xxxx ro quiet splash

把它修改成:

linux /boot/vmlinuz-5.15.0-91-generic root=UUID=xxxx rw init=/bin/bash

这里我做两个改动:把ro改成rw,让根分区直接以可写方式挂载;把quiet splash删掉,替换成init=/bin/bash,禁止图形启动,并指定bash作为init程序。quiet splash会隐藏启动日志,在这种救援场景下反而妨碍排查,删掉是对的。

改完后按Ctrl+X或者F10启动。内核加载完成后,你会直接落在一个bash prompt里。此时不需要登录,不需要密码,你已经是root身份了。

接下来就和Recovery模式一样,先确认根目录是否可写:

mount | grep " / "

如果显示的是rw,直接执行passwd 用户名;如果还是ro,先执行mount -o remount,rw /再改密码。

改完之后,不能简单重启了事,因为当前这个bash进程比较特殊,直接关闭虚拟机也不是不行,但更稳妥的做法是让init程序接管后续启动流程:

exec /sbin/init

这条命令会把当前进程替换成正常的init/sbin/init,系统继续完成启动流程,最终进入登录界面。

3.3 这方案的两个坑

第一个坑是LUKS加密分区。根分区如果是全盘加密的,启动过程中根本没有挂载真实文件系统,你加再多参数也没用。init=/bin/bash这条途径会卡在解密阶段,shell里看不到正常的/etc/shadow。所以在动手前先想想:这个虚拟机当时创建时有没有选择全盘加密。有的话,还是去用Recovery模式,或者走下一节的宿主机挂载方案。

第二个坑是改了参数之后忘了按Ctrl+X。GRUB的编辑界面比较朴素,没有明显的"保存并启动"按钮,很多人以为按Esc能保存修改再启动,实际上按Esc只会放弃修改回到GRUB菜单。参数编辑完成后必须按Ctrl+X或F10启动,这点别搞混。

还有一个更隐蔽的坑:改完参数启动后,bash已经被拿来当init进程用了,此时系统里很多服务都没起来,网络也可能没有。所以在bash里做密码重置以外的事情,比如更新软件包、重启服务,都可能因为环境不完整而出问题。这个方案只适合做救援,不要顺手干别的。

4. 连GRUB都出不来时的终局手段:从宿主机侧挂载虚拟磁盘改密码

4.1 什么情况才需要走这条路

Recovery Mode和GRUB注入都要求你能进入GRUB菜单,但有时候系统不是"忘记密码"这么简单,而是引导链整个断裂了:GRUB配置文件被改动、内核文件损坏、分区表异常,虚拟机一开机就是黑屏或者直接跳到EFI shell。

这种时候别急着重装,VirtualBox还有最后一张牌:虚拟机本质上就是一个文件,我们完全可以绕过虚拟机,直接在宿主机侧打开它的硬盘文件修改内容。

思路也简单:Linux的密码数据在/etc/shadow里,而/etc/shadow在那个vdi虚拟硬盘的分区里。只要你能让宿主机读到这个分区的内容,然后用chroot的方式进入到这个系统环境里,就能执行passwd改掉密码。soda这正是"救援"与"重装"的根本区别:虚拟化给了我们一个物理机难以提供的优势,磁盘文件可以从系统里抽出来单独操作。

4.2 把磁盘拆下来挂到另一台虚拟机上改(适合所有人)

这个方法不挑宿主机系统,只要你的电脑上装了VirtualBox就能做。

第一步,先把忘记密码的这台虚拟机关机。然后在VirtualBox里新建一台临时虚拟机,系统也选Ubuntu,挂载一个Ubuntu桌面版安装ISO镜像。这样做的好处是这个ISO自带"试用Ubuntu"模式,等于给你准备了一个完整的救援环境。

第二步,在临时虚拟机的"设置→存储"里,找到控制器SATA,点击添加一块现有磁盘,把原来那台问题虚拟机的vdi文件加进去。注意一定要选"现有磁盘",别添加成新建磁盘。

第三步,启动临时虚拟机,在安装界面选择"试用Ubuntu"(Try Ubuntu),进入桌面环境后打开终端,先看看硬盘情况:

lsblk

问题系统的那块vdi会显示成/dev/sdb之类的设备。如果没有LVM,直接挂载它对应的根分区:

sudo mount /dev/sdb1 /mnt

如果当初安装系统时选了LVM,lsblk里看到的可能是/dev/sdb3这样的PV。先激活逻辑卷再挂载:

sudo vgscan sudo vgchange -ay ls /dev/mapper sudo mount /dev/mapper/ubuntu--vg-root /mnt

第四步,在挂载好的目录里做bind挂载,把设备、进程和内核文件系统同步进去,然后进入chroot环境:

sudo mount --rbind /dev /mnt/dev sudo mount --rbind /proc /mnt/proc sudo mount --rbind /sys /mnt/sys sudo chroot /mnt

此时你已经出现在原系统的文件系统里面了,直接执行:

passwd 用户名 exit

改完密码后退出chroot,依次卸载挂载点,然后关闭临时虚拟机。在设置里分离刚才添加的那块vdi时,一定选"移除"而不是"删除文件",否则你删掉的可能是整个虚拟硬盘。

再次启动原来的虚拟机,用新密码登录即可。

4.3 在Linux宿主机上直接挂载vdi的进阶操作

如果你的宿主机本身就是Linux,那还有更直接的玩法,不需要再开一个临时虚拟机。

VirtualBox的vdi格式虽然不能直接被mount命令识别,但可以先用qemu-img把它转换成通用的raw镜像格式。前提是虚拟机关机状态。宿主机上安装qemu-utils后执行:

qemu-img convert -f vdi -O raw 原来的磁盘.vdi 输出文件.img

如果没装qemu-img,也可以用VirtualBox自带的命令转:

VBoxManage clonehd 原来的磁盘.vdi 输出文件.img --format RAW

转换完成后,把镜像挂载为loop设备:

sudo losetup -fP 输出文件.img

此时lsblk可以看到loop0以及对应的分区,比如loop0p1。把根分区挂载到/mnt:

sudo mount /dev/loop0p1 /mnt

同样,如果有LVM就先用vgscan、vgchange -ay激活再挂载。挂载号之后,直接chroot进入系统改密码:

sudo chroot /mnt passwd 用户名 exit

最后卸载并清理loop设备:

sudo umount /mnt sudo losetup -D

这个方法省去了开临时虚拟机的开销,但有一个前提:raw镜像会占用跟vdi实际大小差不多的磁盘空间,转换大磁盘时要提前确认宿主机磁盘剩余量。另外转换和挂载期间,原虚拟机千万不要启动,否则磁盘文件被占用,报错都是轻的,更危险的是两边同时写文件搞坏元数据。

5. 密码救回来之后的善后清单:快照、免密登录和过期策略

5.1 登录后立刻做的事

密码改回来只是治标,登录进系统后先别急着庆祝,用几分钟做一轮检查:

last -15 journalctl -xe who

看登录记录有没有异常IP、异常时间,确认这次密码丢失不是被什么人改动过。虚拟机的安全边界通常比较宽松,但基本的警觉不能丢。接着检查一下全盘文件系统挂载是否正常:

df -h mount | grep " / "

如果之前的救援过程中对分区做过强制挂载或remount,确认现在系统是正常启动、根分区以正确方式挂载。这样能避免一些“密码改好了,但数据已经偷偷损坏”的隐性风险。

5.2 给虚拟机打一个"成功救援"快照

确认系统一切正常后,马上给虚拟机拍一个新的快照,起名的时候写清楚状态,比如"after-password-reset-可用状态"。这个快照的价值在于:以后如果再发生密码问题,你不需要再从原始状态一步步去搞救援,直接恢复到这个已验证可用的快照就行。

同时可以把之前的"before-pw-reset"快照删掉,减少磁盘占用。快照虽然不立即占满空间,但长期挂着会留下不少差异数据,该清理时要清理。

5.3 从根源上降低再次忘记密码的概率

走过一次救援流程,你就会明白:真正的问题不是密码忘了,而是密码管理没有一个可依赖的体系。我自己的做法是几件事同时做:

第一,把GRUB菜单从隐藏改成可见。编辑系统里的/etc/default/grub:

sudo nano /etc/default/grub

找到GRUB_TIMEOUT_STYLE=hidden或注释掉它,修改成:

GRUB_TIMEOUT_STYLE=menu GRUB_TIMEOUT=5

保存后执行:

sudo update-grub

这样每次开机GRUB菜单会停留5秒,万一又忘了密码,按Shift按Esc那套操作就根本不需要了。

第二,开发用途的虚拟机直接开启桌面自动登录。在GNOME设置里选中当前用户,打开自动登录;或者编辑/etc/gdm3/custom.conf,取消注释AutomaticLoginEnable=true并指定AutomaticLogin=用户名。开发机丢了登录密码本来就是浪费时间,自动登录配合虚拟机快照体系,能把这层风险彻底摘掉。

第三,服务器用途的虚拟机配置SSH密钥登录。在宿主机上生成密钥对,把公钥放进Ubuntu用户的~/.ssh/authorized_keys,设置好VirtualBox的端口转发或Host-Only网络,以后直接SSH进系统,完全不需要密码。密钥文件本身存在密码管理器里,比手输密码可靠得多。

第四,用密码管理器统一记录。KeePassXC、Bitwarden这类工具都很成熟,把初始密码、root密码、服务账号密码、LUKS恢复密钥统一存进去,并且定期验证一次能不能打开。项目交接的时候,直接把密码库导给接手人,比便利贴、聊天记录传密码靠谱一百倍。

5.4 别忽视密码过期策略

还有一个小坑容易被忽略:有时候系统并不是密码被盗改,而是密码策略让密码到期失效。Ubuntu默认的密码有效期策略在/etc/login.defs里,如果之前的运维刻意设置了PASS_MAX_DAYS,到期后系统会要求强制改密,而你又恰恰几个月没登录,就会出现"明明记得密码却进不去"的尴尬。

对长期不登录的虚拟机,把单个用户的密码过期策略取消掉:

sudo chage -M -1 用户名

这个-M -1表示密码永不过期。如果想让整个系统的默认策略都放宽,可以编辑/etc/login.defs里的PASS_MAX_DAYS,改成99999再执行sudo update-grub无关,但需要重新初始化用户时才会用新默认值,所以对已有用户最直接的办法还是单独chage。

救完密码那几天,我把这台虚拟机的登录方式从纯密码改成了SSH密钥和自动登录双保险,还把GRUB菜单调成永久显示。从此以后,"忘记密码"这类问题在这台机器上基本不会再发生了。

最后再分享一个实操习惯:重置密码,尤其是帮别人重置密码之后,顺手在虚拟机描述里加一行备注,写清楚"上次恢复日期+当前密码存放位置"。VirtualBox的虚拟机描述字段虽然不起眼,但当你同时管理十几台Ubuntu虚拟环境时,它就是一张最简单的资产清单。我见过太多人花二十分钟搞定了密码,结果第二天又忘了自己把新密码记在哪儿。工具再高效,也接不住"不记录"这个坏习惯。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询