背景

前几天,我尝试在我的 VPS 上安装 Gitea, 然后配置 SSH 进行仓库的克隆和拉取等操作。但是直接使用 SSH 的时候会暴露我的 IP,出于安全的考虑,我需要隐藏我的 IP,同时保证外部访问。最后,我选择用 Cloudflare Tunnel 来实现我的要求。

刚开始,我按照 ChatGPT 和官方文档的步骤进行部署,就在我以为一切顺利的时候,第二天早上,我发现我无法用 SSH 连接上我的 VPS 了,并且 VPS 上的应用全部无法访问了。为了修复这个问题,我登录了 VPS 的提供商——绿云,并且尝试使用官方的后台终端登录 VPS。

当我尝试登录的时候,我发现绿云官方的终端不提供复制粘贴的功能。而我的密码又非常长,这就导致我只能手动输入,但是由于输入时间很长,TTY 终端会刷新并且要求重新输入用户名和密码。因此,我不得不寻找其他方法。在这个过程中,我发现了绕过密码认证并且以 root 身份登录 bash 的方法。

方法

虽然绿云不提供复制粘贴的功能,但是它提供 Send CtrlAltDel 的功能,这个功能是向 VPS 发送 Ctrl + Alt + Del 按键,在 Linux 服务器上的表现就是强制重启。因此,我们就可以使用 grub 进行提权。

当我们进入 grub 界面的时候,按下 e 进入编辑模式,这里可以编辑引导时的命令。默认情况下,以 linux 开头的命令可能长这样:

1
linux /boot/xxx root=UUID=xxx ro quiet

这个时候,我们在这段命令的末尾加上一个参数。

1
linux /boot/xxx root=UUID=xxx ro quiet init=/bin/bash

这样,在引导的过程中,我们就能以 root 身份运行 bash 了。此时,我们按下 Ctrl + X 退出编辑模式并继续引导。这个时候,屏幕上显示的内容大致如下:

以 root 身份运行 bash

可以看到,我们此时已经是 root 了。这就意味着,我们可以进行修改密码的操作。但是由于这个时候的硬盘处于只读模式,所以如果直接用 passwd 命令进行修改密码会发生错误,如下图:

passwd 错误

因此,在修改密码之前,我们需要一个准备工作,就是将硬盘以读写模式挂载。运行如下命令:

1
mount -o remount,rw /

这条命令将根目录挂载为读写模式。此时我们再运行 passwd 命令就可以成功修改密码了。

当我们成功修改密码之后,就要执行最后一步了。由于此时 VPS 还处于引导阶段,这就意味着它还没有真正地开机,所以用 reboot 进行重启是不合适的。当然,可以运行 reboot ,但结果就是 VPS 卡住,然后需要再一次重启,重新引导(无需重复这个过程)。合适的做法是让 VPS 继续引导的过程,这就要用到以下命令:

1
exec /sbin/init

之后,我们就能看到登录界面,输入用户名和新的密码,我们就能成功登录了。

预防

无论是服务器上的 Linux 还是桌面端的 Linux,都有办法来防止这种威胁发生。比如,我们可以加密硬盘或者加密 grub。这里,我介绍后者。

首先,运行以下命令,为 grub 引导创建一个密码。

1
grub-mkpasswd-pbkdf2

按照提示输完密码之后,它会返回一段哈希值,记住这段哈希值。打开文件 /etc/grub.d/40_custom,添加以下内容:

1
2
set superusers="root"
password_pbkdf2 root your_hash_string

这里,把 your_hash_string 替换成前面生成的哈希值,然后运行 grub-mkconfig -o /boot/grub/grub.cfg 使其生效。

配置之后,每次进行开机引导或者修改启动命令的时候,用户都会被要求输入密码。这就达到了防止提权的目的。


参考
ChatGPT