当你在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小程序名运行时无法工作。因此,如果你用busybox覆盖了例如fmt二进制文件,它将无法工作(会说:applet not found)。如果你没有busybox,建议覆盖cp,然后使用cp创建cp的副本作为busybox(这将可执行)。
cp到busybox
没有bash?printf可以帮忙
如果你有更高级的shell(如:zsh),它已经内置了TCP模块。你可以轻松使用另一台机器的nc发送文件到目标机器。现在,假设你有一个非常基本的shell,例如:dash。大多数shell(包括dash)都有printf作为内置命令,我们可以使用它来构造二进制文件。
大多数(全部?)shell的内置printf实现支持\ooo,其中ooo是3位八进制。第一种方法是直接转换busybox,但此文件相当大(2兆字节)。复制粘贴大型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卡并完成,但我好奇是否能从错误中恢复。
希望你在生产/重要机器上永远不会遇到此错误,但如果未来遇到此问题,希望本文能帮助你恢复情况。