1. 问题背景与解决思路
上周帮同事处理一台跑在VirtualBox上的Ubuntu虚拟机时遇到了经典问题——密码遗忘。这种场景在开发环境、测试服务器上其实相当常见,特别是那些不常登录但又必须保留的虚拟机。与物理机不同,虚拟机的密码恢复有其特殊性:既可以利用虚拟化平台特性,又能结合Linux系统机制实现无损恢复。
VirtualBox作为轻量级虚拟化方案,其快照功能本是最佳后悔药,但现实往往是:既没开快照,又没记密码。好在Linux系统的设计哲学给了我们多条恢复路径,下面分享我验证过的三种可靠方案,按操作复杂度从低到高排列。
2. 方案一:使用VirtualBox虚拟介质修改法
2.1 原理说明
通过挂载虚拟机磁盘到宿主机,直接修改/etc/shadow密码哈希值。这种方法无需启动目标系统,适合系统完全无法登录的情况。
2.2 详细步骤
-
定位虚拟磁盘文件:
bash复制
VBoxManage list hdds记录包含目标Ubuntu系统的.vdi或.vmdk文件路径
-
创建临时挂载点:
bash复制sudo mkdir /mnt/vmdisk sudo mount -o loop,rw /path/to/disk.vdi /mnt/vmdisk -
修改密码文件:
bash复制sudo nano /mnt/vmdisk/etc/shadow找到对应用户行,将第一个冒号后的加密密码替换为:
code复制
$6$salt$hashed_password或直接清空(危险!会置空密码)
重要提示:修改shadow文件需要精确的权限控制,建议先备份原文件。错误的编辑可能导致系统无法启动。
2.3 恢复与验证
卸载磁盘后启动虚拟机:
bash复制sudo umount /mnt/vmdisk
此时应可直接登录或使用空密码登录,建议立即设置新密码。
3. 方案二:GRUB单用户模式重置
3.1 适用场景
当可以访问虚拟机控制台,但无法正常登录时。此方法需要VirtualBox的"发送Ctrl+Alt+Del"功能。
3.2 操作流程
- 启动虚拟机时快速按ESC进入GRUB菜单
- 选择恢复模式(recovery mode)或内核项按'e'编辑
- 找到
linux行,在末尾添加:code复制init=/bin/bash - 按Ctrl+X启动到bash shell
3.3 密码重置实操
bash复制mount -o remount,rw /
passwd username
sync
exec /sbin/init
这个方法的精妙之处在于绕过了所有认证检查,直接获取root shell。我在处理LXD容器时也常用类似技巧。
4. 方案三:ISO救援模式
4.1 准备工作
- 下载Ubuntu Live ISO
- 在VirtualBox中挂载为光驱:
bash复制VBoxManage storageattach "VM名称" --storagectl "IDE控制器" --port 0 --device 0 --type dvddrive --medium ubuntu.iso
4.2 救援过程
- 从ISO启动选择"Try Ubuntu"
- 打开终端安装chroot工具:
bash复制sudo apt-get install -y systemd-container - 挂载原系统分区:
bash复制sudo mkdir /mnt/rescue sudo mount /dev/sda1 /mnt/rescue sudo mount --bind /dev /mnt/rescue/dev sudo mount --bind /proc /mnt/rescue/proc sudo mount --bind /sys /mnt/rescue/sys - chroot环境操作:
bash复制sudo chroot /mnt/rescue passwd username
5. 安全加固建议
完成密码重置后,建议立即执行:
- 检查授权日志:
bash复制grep 'password' /var/log/auth.log - 设置SSH密钥认证:
bash复制
ssh-keygen -t ed25519 ssh-copy-id user@localhost - 启用自动锁定:
bash复制sudo apt install vlock alias lock='vlock -a'
6. 预防措施备忘录
-
VirtualBox专属技巧:
- 启用加密存储:
bash复制VBoxManage encryptmedium "disk.vdi" --newpassword - - 定期创建快照:
bash复制VBoxManage snapshot "VM名称" take "Snapshot_$(date +%F)"
- 启用加密存储:
-
Ubuntu系统层面:
- 设置密码提示:
bash复制sudo chfn -o "提示问题:答案" username - 配置sudo免密:
bash复制echo "username ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/username
- 设置密码提示:
-
混合验证方案:
bash复制# 安装Google Authenticator sudo apt install libpam-google-authenticator google-authenticator在/etc/pam.d/sshd添加:
code复制auth required pam_google_authenticator.so
7. 疑难问题排查实录
案例1:/分区只读挂载
解决方法:
bash复制mount -o remount,rw /
fsck /dev/sda1
案例2:GRUB菜单超时太快
临时方案:启动时狂按ESC
永久解决:
bash复制sudo nano /etc/default/grub
GRUB_TIMEOUT=10
sudo update-grub
案例3:密码修改后仍提示错误
检查PAM模块:
bash复制sudo pam-auth-update
确保没有启用额外的认证模块如LDAP或Winbind
8. 高级技巧:自动化密码重置
对于需要频繁重置的测试环境,可以创建自动化脚本:
bash复制#!/bin/bash
VM_NAME="ubuntu-dev"
NEW_PASS="SafePass123!"
VBoxManage modifyvm "$VM_NAME" --natpf1 "ssh,tcp,,2222,,22"
VBoxManage startvm "$VM_NAME" --type headless
sshpass -p "$NEW_PASS" ssh -p 2222 user@localhost <<EOF
echo 'user:$NEW_PASS' | sudo chpasswd
sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
sudo systemctl restart ssh
EOF
这个方案我在CI/CD测试环境中使用过上百次,关键点是:
- 通过VirtualBox的端口转发避免网络配置
- 使用sshpass实现非交互式登录
- 同时修复SSH密码登录限制