当你通过ssh连接Linux系统时误删了/lib目录
首先我们不去讨论为什么会发生这种情况,但删除/lib、/usr/lib或其他关键运行时文件的情况确实经常发生(如这里、这里、这里和这里的案例所示)。本文只讨论在Linux上删除/lib后会发生什么,以及如何恢复。
最简单的解决方案是替换缺失的文件,但如果/lib被删除,这会很困难,因为我们将缺少运行任何动态可执行文件所需的ld-linux。当你删除/lib后,所有非静态可执行文件(如ls、cat等)都会输出:
|
|
你将无法通过ssh建立新连接,如果使用tmux也无法打开新窗口/窗格。因此你只能依赖当前shell的内置命令和系统上已有的静态可执行文件。
如果安装了静态版本的busybox,它将成为你的救星。可以使用busybox中的wget从干净系统下载库文件。需要注意的是:Debian默认安装了busybox,但默认版本不是静态版本。
最小化Debian安装 如果你担心未来可能遇到此类问题:请安装静态版本的busybox二进制文件,并确认它是正确的版本。
安装静态busybox
Bash救援方案 假设你现在没有静态busybox,甚至没有任何静态可执行文件(这是许多情况下的常态,如最小化Debian的默认安装)。我的解决方案是从另一台机器下载静态busybox。
同时假设你已安装bash(这是大多数系统的默认设置)。Bash有许多内置功能可供使用。这里有一个解决方案可以仅使用bash内置函数下载文件。该帖子的其他解决方案依赖外部命令(如cat)。请注意需要将环境变量LANG设置为C,否则此脚本无法正确处理Unicode字节。
当然,我们无法chmod目标文件为可执行,因此需要覆盖现有可执行文件。如果已安装busybox(即使是非静态版本),可以覆盖此文件。此时你可以开始救援任务:例如使用wget从其他系统下载完整的/lib。
请注意,busybox在名称不是busybox小程序时无法正常工作。因此如果覆盖了例如fmt二进制文件,它将无法工作(会显示:applet not found)。如果没有busybox,建议覆盖cp命令,然后使用cp创建busybox的副本(这将可执行)。
cp到busybox
没有bash?printf可以帮忙 如果你有更高级的shell(如zsh),它已经内置了TCP模块。可以轻松使用另一台机器的nc向目标机器发送文件。现在假设你只有非常基础的shell,例如dash。大多数shell(包括dash)都有printf内置命令,我们可以利用它来构建二进制文件。
大多数(全部?)shell的内置printf实现支持\ooo(其中ooo是3位八进制数)。第一种方法是直接转换busybox,但该文件较大(2MB)。复制粘贴大型printf命令既繁琐又容易出错。我们需要一个能帮助我们的静态小二进制文件。
这个printf技巧也适用于其他操作系统,只要你能为该操作系统创建小二进制文件。
创建Linux小型ELF文件 如果直接使用汇编语言,可以创建非常小的可执行文件,但让我们尝试用C语言实现,以便跨不同架构移植。我能想到的最小有用程序是从stdin复制到stdout,这样我们可以在机器上准备netcat:
|
|
然后从故障机器执行:
|
|
源代码可能如下:
|
|
如果使用标准C库编译(在AMD64机器上),结果为776KB。
|
|
Linux内核源代码包含我们可以使用的nolibc实现。使用以下编译选项:
|
|
我们得到4536字节的二进制文件。相当不错。如果添加-z max-page-size=0x04,还能得到更小尺寸。
|
|
现在为672字节。小到可以传输。我们可以使用Python进行转换:
|
|
然后我们可以复制粘贴到ssh会话中,再执行/dev/tcp重定向技巧。
输出示例
当然,我们也可以编写一个完整的程序来建立TCP连接,而不依赖bash重定向。
希望你永远不需要这些知识 几天前我在更新太阳能供电的Pi Zero时遇到了这个问题,不知何故/lib被删除了(不确定原因)。这不是非常重要的机器,本可以重新映像MicroSD卡了事,但我好奇是否能从错误中恢复。
希望你不会在生产/重要机器上遇到此错误,但如果未来遇到此问题,希望本文能帮助你恢复情况。