2019年10月31日,一个Solr Velocity模板远程命令执行的POC被公开到Github。经过分析测试,该POC在Solr的多个版本测试成功,包含最新版本,所以该漏洞目前处于0day状态。由于Solr默认未开启登录认证,只需请求/节点名/config
,将配置项params.resource.loader.enabled
设置为true
,再构造链接即可让Solr中的Velocity
模版引擎渲染传入的恶意模版
,造成命令执行。下面我们来具体分析漏洞细节!
Velocity
是一个基于Java的模板引擎,简单来说就是可以将模版渲染成html页面。下面以一个小demo来演示使用Velocity
如何渲染出test by chixiao lab
,方便大家快速理解Velocity
的功能和使用。
如果我们的模版test.vm
内容改如下时,那么Velocity
将会执行id
命令,并显示执行结果。
所以某个应用以Velocity
作为模版渲染引擎,如果要渲染的模版内容用户可控的话,那就可以构造恶意模版来执行任意命令。本次Solr漏洞就是这种情况!
下面我们在Solr 8.2.0
上以公开的POC触发的漏洞链进行分析。
Solr在查询数据结束后,会通过wt
参数的值来确定数据返回的格式,可以是XML
、JSON
、CSV
,Velocity模版渲染
等等。本次漏洞正是出现在查询结果用Velocity模版渲染
。
从代码层面看,Solr会根据wt
值,创建对应的类型的QueryResponseWriter
来将查询数据处理成对应的格式,最后将数据write()
到客户端。
由于我们这里设置的是wt=velocity
,故QueryResponseWriter
类型为VelocityResponseWriter
。我们在solr-velocity-8.2.0.jar
包的VelocityResponseWriter.write()
方法打断点,作为漏洞分析的开始位置。
首先Solr会先创建一个Velocity模版引擎对象engine
,跟进createEngine()
方法。
发现当设置"params.resource.loader.enabled": "true"
时,属性this.paramsResourceLoaderEnabled
的值为true
,程序将创建一个参数资源加载器对象,也就是模版内容将从前端传来的参数中加载(PS:知识储备的案例是从文件加载)。
继续跟进SolrParamResourceLoader
类的构造方法,解析了前端传来的所有参数,并对v.template.
开头的参数进行处理。我们请求的参数为...&v.template=custom&v.template.custom=恶意模版内容
,所以put
进入templates
模版map
的key
是custom.vm
,value
就是我们指定的恶意模版内容
。
之后在获取模版对象时,将前端传入的参数v.template
值拼接.vm
,也就custom.vm
,作为要渲染的模版名。而custom.vm
正是我们上一步传入的恶意模版。
然后我们重新回到write()
方法,不管wrapResponse
变量为true
还是false
,恶意模版都被传入merge()
进行合并渲染,至此漏洞触发。