如何拯救一台glibc被干掉的Linux服务器

原文: 如何拯救一台glibc被干掉的Linux服务器?

首先如果 libc.so.6 没有被删除, 直接使用LD_PRELOAD就可以恢复
LD_PRELOAD=/lib64/libc-2.12.so ln -s libc-2.12.so libc.so.6

如果彻底被删除, 下面的方法可以一试

glibc被卸载,负责加载所有.so的ld.so也就没了,因此运行几乎所有外部命令时都会得到一句『找不到ld-linux-x-y-z.so.2』的出错提示。比如ls,比如cp,以及所有动态链接的命令。

这是一台放置于另外一个大洲的客户IDC的物理服务器。我说不行就光盘引导修复,但不知道什么原因他们又连不上服务器的HP iLO工具。

干着急也不是办法。万幸的是rpm --force的小伙子的ssh登录shell还连着。我说那不行就只能你自己一个byte一个byte先敲一个static linked的binary出来,这是可以运行的。

话说完,我就大概想到该怎么办了。

  1. 用bash的内部命令 printf '\xaa\xbb\xcc' > file 可以生成任意内容的文件
  2. 另外找台同配置的Linux,用xxd或hexdump配合一点点脚本,或者直接用python写个小脚本,把ld.so文件转储成若干条printf '...' >> file的命令(考虑到bash单行命令的长度限制,我没有尝试只生成一条命令)
  3. copy 2)中生成的命令,paste到出事的Linux shell中运行
  4. 这样至少ld.so能用,接下来可以按图索骥恢复其他.so
    Tada! 我感觉自己重新发明了scp。

然而这样行不通。printf重定向生成的文件不带可执行位,无法被执行,只是把出错信息变成了permission denied而已。

别忘了chmod也不能用哦。

所以往上面手动恢复glibc这条路看来是行不通了。

既然动态链接的命令都不能用,那就只能上静态链接了。到http://www.busybox.net下载了静态链接的1.16.0版(越旧的版本越好——因为越小)的busybox,不到900KB,用上面的办法,转存到出事的Linux上。

刚才不是说了没有可执行位吗?busybox又怎样?

这次,我是把busybox直接写入到

printf '...' > /bin/cp

覆盖系统原有的带x位的cp文件,用旧瓶装新酒,我终于获得了一个可执行的busybox!
别忘了,argv[0]为cp时,busybox就是在做cp的事情!

因此接下来再

cp cp ln
ln -s cp chmod
ln -s cp ls
ln -s cp wget
ln -s cp sh
...

printf和busybox拯救世界!

再传送一份静态连接的dropbear上去,起一个备用的ssh server(别忘了把账号的登录shell改成busybox版sh),总算可以松一口气,继续后面的灾难恢复了。

PS:
测试一个简单的hello world程序可以通过

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
#include

int main()
{
  printf("Hello World!\n")
}

gcc -o hello hello.c
'''

# only test,python3.6环境测试通过,在python2环境下会报错
result = []
outfile = 'out.sh'
fpath = '/home/opc/hello'

with open(fpath, 'rb') as f:
  bt = f.read()

diglist = list(bt)
for dig in diglist:
  if dig > 39 and dig < 127: #ascii码里面这些字符串可见
    s = str('\\') + oct(dig)[-3:].replace('o','0')
  else:
    s = str('\\x') + hex(dig)[-2:].replace('x','0')
  result.append(s)
with open(outfile,'w') as f:
  for i in range(0, len(result), 1000): #每次打印1000个字符1k大小,1M大小文件就需要1000次操作了-_-!!
    if i + 1000 > len(result):
      print('printf \'', ''.join(result[i:len(result)]), '\' >> recovery_file', sep='')
      f.write('printf \'' + ''.join(result[i:len(result)]) + '\' >> recovery_file\n')
    else:
      print('printf \'', ''.join(result[i:i+1000]), '\' >> recovery_file', sep='')
      f.write('printf \'' + ''.join(result[i:i+1000]) + '\' >> recovery_file\n')

你可能感兴趣的:(如何拯救一台glibc被干掉的Linux服务器)