作为一个练习时长4年半的运维工程师,对于服务器的安全性一直有很高的意识。
虽然本人平常很懒不大更新博客,但是也记录过诸如《Linux登录的一些安全优化》、《Linux服务器启用两步验证方式登录》这样的文章,深刻意识到守好登录口这扇大门的重要性。
可就在昨天,凌晨吃完了Bilibili的瓜,万万没有想到自己的生产服务器也出现了故障🤡小丑居然是我自己。
发生肾么事了?
其实从登录到管理服务器过程都充满了各种不安全的因素,且让我慢慢梳理。
- 故障的发生
7月14日下午,本是平凡打工的一个下午,突然天降一封邮件,内容大概就是生产的一个API接口可用性于16:27发生告警,可用性降为0%。 吓得我一下精神集中提高100%,准备先分析一下这个接口部署在哪里,继而又收到了我刚部署好不久的zabbix发来的CPU利用率极高的告警,此时是16:29。
High CPU utilization (over 90% for 5m) CPU utilization is too high.The system might be slow to respond.
由于告警也带上了主机名,那么很明确快速锁定故障的节点了。
- 服务器上的分析
于是我连忙登上了那台服务器,这时用户开始报故障了,问题变得严重了起来。 不过,作为练习时长4年半的运维工程师,此刻非常的淡定。
先使用top
看看哪个进程在搞事情把cpu都抢了吧,超出我意料的java进程以外,是一个很陌生的进程占用几乎100%的cpu。
锁定了它的位置ls -l /usr/games/.../.miner/syst3md
-rwxr-xr-x 1 root root 6960840 8月 22 2020 /usr/games/…/.miner/syst3md
直觉告诉我,这个玩意不是我们的东西(后来觉得最应该使用stat+文件来查看,ls默认是上次修改时间)。
- 故障分析
询问过开发后开始杀掉它的进程。杀完之后再次查看,又起起来了。
暂时先把它移动到/tmpmv /usr/games/.../.miner/syst3md /tmp
将进程pid再次杀掉,发现不再起来了。
检测进程和资源占用情况都正常了,此时是16:32。
确认之前计划任务什么没有,怀疑是这个病毒文件起来时候建立了计划任务,后面的分析过程印证了这个想法。
所以使用last
查看这个时间有谁登录过服务器
|
|
好家伙,有一个j的家伙在下午16:06开始到16:24多频次多来源ip登录过服务器。
生产服务器不安全的点
这里说一下故障涉及的生产服务器不安全的几个因素:
- 我接手服务器时本想第一时间修改root密码,因为一些原因没有进行修改;
- 生产服务器环境连入其实有VPN的,但是我来的时候已经使用了nginx做了端口的反向代理(使得ssh端口暴露在互联网中,当时有提出疑问但是没有进行整改);
- mysql通过nginx做了端口的反向代理(使得数据库端口暴露在互联网中);
- Jenkins通过nginx做了端口的反向代理(使得Jenkins暴露在互联网中);
- 以上的反向代理都没有日志记录,后期排查时,找不到侵入者的公网ip(虽然这种情况找到ip意义也不大);
- 生产服务器进程使用root起停,Jenkins也一样,所以只要攻破了Jenkins,就可以拿到服务器得root权限;
- 生产服务器情况比较复杂,我没有做用户的筛选管理(有的用户和日志审核系统相关,没有人清楚情况,也不敢乱动);
- 出问题的服务器托管在机房,那边的服务团队没有将详细架构交予我这边,远程沟通效率低,终于无果;
- 日志审计、防毒墙硬件设备形同虚设。
这些不安全的因素大多为了图方便,还有一些复杂原因没有推动下去进行整改,当然有了这次的教训,这些点都是优先考虑整改的方向。
- 继续故障分析
16:36:34又收到了zabbix的告警信息
/etc/passwd has been changed
发现了/etc/passwd
内被新建了一个server的用户
使用userdel -r server
进行删除。
上面说到有不明用户登录了服务器,流程很明确先让它无法登录,修改j用户以及root用户的密码,如果j或root还保持登录应该将其强制登出。
临时排除不安全的因素不会从外部引入,此时,故障还没有得到处理。因为java项目的进程全部都不存在了,手动启动主要的java项目以及Jenkins。
API可用性于16:57恢复正常,可用探测点百分比为100%,持续时间33分钟,其中大部分时间是在排除j用户再次登录的可能性。
- 关于j用户
前面的syst3md可疑进程是root起的,但是发现使用visudo
命令(或查看/etc/sudoers
文件),j都不在其中,它是怎么提权的呢?
其实还有其它疑点,第一时间我其实是想删除j用户的。
使用root删除它userdel -r j
提示
userdel: user j is currently used by process 1
process 1 是什么我相信运维很清楚,这个j用户还不算简单呐,所以才曲线先修改了它的密码,让它不能再登录到服务器上操作。
再来分析这个用户为什么这么🐂🍺连root用户都删除不了它。使用cat /etc/passwd | grep ^j
j:x:0:0::/root:/bin/bash
它的uid,gid都是0,家目录为/root
,翻译成人话就是使用它登录成功就是root用户,我直呼妙啊!
再查看/etc/passwd
文件发现它还是一个老朋友了。
还有它登录服务器的地址有四个
- 192.168.10.100
这个就是本机内网ip地址,本机登录本机?
- 192.168.122.1
不在认知范围的内网地址,后来经过确认,给我们做网络服务团队也不知道这是什么地址。但是对方提到监管的线,所以使用ifconfig
查看到是本机的网卡virbr0地址,又使用本机的ip地址登录本机(正常人都干不出这事),唯一的解释就是木马程序扫描所有的网卡之后扫描网段在线的ip,再使用j账户密码登录(后面的的server1地址以及同网段的其它主机登录日志可佐证)。
- server1
ping server1
返回的IP是10.10.100.3 ,也是不在认知范围的内网地址,发现server1是写在了/etc/hosts
内。后来经过确认,给我们做网络服务团队也不知道这是什么地址,同理上面的ip地址,是本机的enp2s0f1网卡获取的地址,还是监管的线路吗?又进行了本机登录本机的操作,确认不是正常人(是正常机器人)的操作了。
- 192.168.11.100
前面隐患说到的,通过nginx端口转发到本机的地址,不论是直连这台服务器的外网ip还是从这台服务器ssh故障服务器都会显示来源为这个ip。
有害程序的分析
好在我第一时间不是删除了/usr/games/.../.miner/syst3md
这个文件,而是移动到了/tmp
下,让我空下来可以分析一下这个文件。
我将其从服务器上拉了下来,不出意外的它就是一个二进制文件。
file syst3md
syst3md: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux),statically linked, for GNU/Linux 2.6.18,BuildID[sha1]=abbd7cc45284dffd19b3e61e1f31b03e44addc00, stripped
文件更详细特征值为: 名称: syst3md 大小: 6960840 字节 (6797 KiB) CRC32: F504C8AF CRC64: A479CAC1E9F66F36 SHA256: EFA9CF5AD8EB73556E34F2CBF4FB71DF19E9956A4F0332A714BB6307395F3DCC SHA1: 732186C30BCC72F0A295284FC4593B200AA84779 BLAKE2sp: 5ECB796F79A58D3B8D4E9E333E08F320A153AA61F2D63AE2381C258DE1A30A95
通过搜索,果然发现有人早已中招过了。
上面的报告是在windows主机上跑的,但我们无法看到它到底是个啥,从火绒的扫描分析来看它是linux下的一个黑客工具。
只有另辟蹊径从/usr/games/
这个文件夹着手了,ls -la /usr/games/
,有一个...
的文件夹
drwxr-xr-x. 3 root root 36 7月 14 16:21 …
进一步查看
ls -la /usr/games/.../
drwxr-xr-x. 3 root root 123 7月 14 16:36 .miner -rw-r–r–. 1 root root 1985344 7月 14 16:21 x.tar.gz
ls -la /usr/games/.../.miner/
-rwxr-xr-x. 1 root root 922808 8月 21 2020 1 -rwxr-xr-x. 1 root root 923336 8月 21 2020 apachelogs -rwxr-xr-x. 1 root root 4350 5月 18 22:27 config.json -rwxr-xr-x. 1 root root 926112 8月 21 2020 run drwxr-xr-x. 2 root root 56 5月 18 19:41 .settings -rwxr-xr-x. 1 root root 926272 8月 21 2020 setup -rwxr-xr-x. 1 root root 575 9月 9 2020 status -rwxr-xr-x. 1 root root 182 5月 18 20:27 wget-log
这里有一个config.json还有一个wget-log文件上次修改时5月18日,好家伙,这么分析是有计划任务的呀!
查看config.json发现了一些信息。
|
|
看看是个啥网站
curl -k https://139.99.123.196
Mining Pool Online
好家伙是个矿场啊,侵入我们服务器来挖矿的。
切断j再次登录管道
增加了计划任务,代表有死灰复燃的可能性。
/etc/crontab
没有可疑内容然后查看单个用户的计划任务ls /var/spool/cron/ -lh
-rw——-. 1 root root 198 7月 14 16:34 root
使用root账户crontab -l
或cat /var/spool/cron/root
可以查看内容。
- /usr/games/…/.miner/1 > /dev/null <&1 2>&1 & disown @monthly /usr/games/…/.miner/1 > /dev/null <&1 2>&1 & disown @reboot /usr/games/…/.miner/apachelogs > /dev/null <&1 2>&1 & disown
嗯,临死之前还要留下个种子,有一个每分钟都运行和每个月,每次重启运行的计划任务。由于执行的脚本是二进制文件,也看不出什么,做一个文件夹备份拉到本地后先删除它吧,把计划任务也清空掉。
|
|
到此为止堵上了大部分的漏洞,而后对方还有一个骚操作也被我揪出来,那就是使用密钥登录了。 是此前在这个目录下看到的rsakey
ls -la /usr/games/.../.miner/.settings/
-rw-r–r–. 1 root root 399 7月 14 16:23 .rsakey -rw-r–r–. 1 root root 28 10月 18 2020 .usercreated -rw-r–r–. 1 root root 13 10月 18 2020 .worker
|
|
果不其然
cat /root/.ssh/authorized_keys
发现了这个ssh-key。
临死前还要摆这么多道,就算改了j的密码它还可以用密钥登录,妙啊!
直接清空或者删除/root/.ssh/authorized_keys
发现还没得权限,root没权限,果然又是那个把戏。
lsattr authorized_keys
—-i———– authorized_keys
chattr -i authorized_keys
lsattr authorized_keys
—————- authorized_keys
>/root/.ssh/authorized_keys
然后直接删除这个受信任的文件。
- 另一台服务器
前面分析到j用户首次的登录是从192.168.11.100这个ip地址登录的,我又尝试从这台服务器进行了分析。
使用last
果然发现了问题。
|
|
它也从server1也就是10.10.100.3进行了登录动作。
看看那个文件有没有出现。
ls /usr/games/ -la
drwxr-x— 2 root root 6 7月 14 16:16 …
文件夹有了也是昨天创建的,查看文件里面内容ls /usr/games/... -la
发现为空。
这台服务器没有发生的原因,唯一解释就是这台服务器访问不到外网,救了它一命。
至此完全杜绝了j用户的登录,当然为了安全也可以删除j用户了,我打算还是先留着作为证据了。
- j用户的逆天权限
前面说过j用户的uid和gid均为0,家目录为/root,这样登录j用户就等于直接登录了root,连sudo都不用输入直接提权。
那么这种权限是怎么实现的,其实非常的简单。
使用root权限执行useradd -o -u 0 -g 0 -d /root -s /bin/bash k
可以创建一个k的拥有root权限的用户。
拿掉他的权限可以使用vipw
修改gid和uid即可。
- 反向代理添加访问日志
这一块是可以优化的地方,端口转发这一块,之前是通过 stream { upstream xxx{ … } server { … } } 来实现的,没有添加日志,在stream内添加 log_format stream ‘$remote_addr [$time_local] $status $upstream_addr’; access_log /xxxx/xxxx/xxxx.log stream ; 可以记录到来源ip 时间 状态 反向代理服务信息。
故障总结
- 密码泄露
定义此次攻击为密码泄露,肉鸡⛏挖矿,从/var/log/secure
分析,来自192.168.11.100的未知用户登录失败次数达到了31096次(7月11日到16日)
使用root登录失败的次数也达5919次
外面在不断的尝试爆破服务器,但是判定用户j不是爆破的而是密码泄露的理由是它的登录轨迹
期间登录服务器只有两次失败的记录
Jul 13 23:19:22和Jul 14 17:04:22,在故障前一天晚上晚上(也就是bilibili出问题的时间点?),它尝试登录了服务器但是失败了,后面是故障当天,解决了故障后再次登录失败。
而故障前一天它也是在Jul 13 15:09:25第一次登录,但是在绝对可信的last
没有留下记录。
紧接着就是故障当天的登录,以及后续的我改完密码自己的尝试登录记录了。
因此判定j用户遭到了密码泄露的挖矿攻击。
- j用户由来
供应商解释是当时用来做等保的账户
- 攻击过程
使用泄露的j用户以及密码进行服务器登录,并连接外网下载挖矿程序并运行。
添加计划任务保持在线状态,添加密钥便于下次再次登录。
扫描服务器网卡,获取各个网段的主机,并进行登录,重复上面的步骤。
(由于备用的web服务器没有外网访问权限,只创建了/usr/games/...
文件夹,幸免遇难)
病毒样本分析:
https://www.joesandbox.com/analysis/438274/0/html
https://hybrid-analysis.com/sample/efa9cf5ad8eb73556e34f2cbf4fb71df19e9956a4f0332a714bb6307395f3dcc/60d17df7e81ec670746de450
https://maldun.com/analysis/YXNkZmRzZmFkc2Y2MTY0NTRkc2Zhc2RmYXNkZg==/
- 安全性改进
参见上方的 生产服务器不安全的点 ,逐一分析改进。
还有就是供应商给我们部署的防毒墙也没有任何反馈,让我看日志审计系统但是系统直接登录就是提示数据库异常,请联系管理员。 关键时刻硬件形同虚设。
问题分析到这里,真相已经逐渐明朗了。好在对方的手段显得比较拙劣,留下了这么多痕迹,不然我怎么死的都不知道。
最后要强调的是:
图方便和保安全是互斥的,这次故障很多地方都有图方便而忽略安全性的地方。
作为运维人员,如果你有绝对的保安全性的权利,绝对不要去图方便,最终受害的是自身,也会给业务造成无可挽回的损失。