OpenTSDB远程命令执行漏洞分析 -【CVE-2018-12972】
相关背景
Opentsdb是基于Hbase的分布式的,可伸缩的时间序列数据库。官方提供了一个web界面来提供对查询数据进行可视化分析,其背后的绘图由Gnuplot支持。其Github地址为: https://github.com/OpenTSDB/opentsdb 。在某些版本(比如2.3.0,以下分析以2.3.0版本为例)中,其提供的Web接口存在远程命令执行漏洞,一旦利用成功将以root权限执行。分析见下。
漏洞分析
在opentsdb中,默认情况下tsd.core.enable_ui
开启,允许通过http来进行rpc调用。当访问时/q?xx=xxx
时,对应的rpc接口即GraphHandler
。见 src/tsd/RpcManager.java:297:
在 src/tsd/GraphHandler.java:108 execute中
跟入 doGraph
其中接受参数在
src/tsd/GraphHandler.java:198 doGraph 中:
从请求中获取对应值并设置plot参数在setPlotParams(query, plot);
中完成:
为方便起见,整理一下http请求参数、java代码、plot参数的对应关系。有一些参数经过了stringify
,用于后续的JSON格式的转换。经过stringify
的参数都会被双引号包含(见下面的代码),难以后续逃逸使用。还有一些参数直接被设定为空值。这些参数对应如下:
http请求参数 | Java代码 | plot参数 |
---|---|---|
ylabel | put(“ylabel”, stringify(value)) | ylabel |
y2label | put(“y2label”, stringify(value)) | y2label |
yformat | put(“format y”, stringify(value)) | format y |
y2format | put(“format y2”, stringify(value)) | format y2 |
xformat | put(“format x”, stringify(value)) | format x |
ylog | put(“logscale y”, “”) | logscale y |
y2log | put(“logscale y2”, “”) | logscale y2 |
title | put(“title”, stringify(value)) | title |
stringify
定义在 src/tsd/GraphHandler.java:658 :
escapeJson
定义在 src/tsd/HttpQuery.java:471 中,主要对一些特殊字符进行转义:
还有一些参数并没有经过转义等,如下表
http请求参数 | Java代码 | plot参数 |
---|---|---|
yrange | put(“yrange”, value) | yrange |
y2range | put(“y2range”, value) | y2range |
key | put(“key”, value) | key |
bgcolor | put(“bgcolor”, value) | bgcolor |
fgcolor | put(“fgcolor”, value) | fgcolor |
smooth | put(“smooth”, value) | smooth |
style | put(“style”, value) | style |
在完成参数设置后,创建了一个RunGnuplot
对象,其中前面解析到的参数即对应的写入到了plot
属性中
|
|
在doGraph
的最后执行了execGnuplot(rungnuplot, query);
,即src/tsd/GraphHandler.java:256
这边RunGnuplot
实现了Runnable
接口,因此当线程开始执行时调用的是RunGnuplot
的run
方法:
跟入execute()
:
跟入runGnuplot
,位置在src/tsd/GraphHandler.java:758
dumpToFiles
方法定义在src/graph/Plot.java:196
:
跟入writeGnuplotScript(basepath, datafiles)
,这个方法会生成真正的Gnuplot脚本,方便起见我往里面加了注释
在完成了plot.dumpToFiles(basepath);
后,开启子进程运行生成的Gnuplot脚本:
而gnuplot中允许使用反引号来执行sh命令,
交互模式下:
脚本执行模式下:
因此我们可以通过远程控制特定的参数,使得Gnuplot在运行脚本时远程命令执行。支持远程命令执行的可控参数如下:
http请求参数 | Java代码 | plot参数 |
---|---|---|
y2range | put(“y2range”, value) | y2range |
key | put(“key”, value) | key |
bgcolor | put(“bgcolor”, value) | bgcolor |
fgcolor | put(“fgcolor”, value) | fgcolor |
smooth | put(“smooth”, value) | smooth |
style | put(“style”, value) | style |
o | 省略 | 省略 |
攻击流程
先查出可以使用的metrics
发包,在参数位置处填入payload。