class Exploit: def __init__(self, name, description, type_, rawcmd, success=''): self.name = name self.description = description self.type = type_ self.rawcmd = rawcmd self.success = success self.directory = TOOL_BASEPATH + '/exploits/' + self.name.lower() self.output = '' def run(self, target): try: self.command = Command(self.rawcmd, self.type) except CommandException as e: logger.error(e) return None # Build script to run if self.type == 'rce-blind': logger.warning('WARNING: This attack box must be reachable from the target !') logger.info('If target is vulnerable, exploit will try to ping local ' \ 'IP = {localip} from target'.format( localip=NetUtils.get_local_ip_address())) print(self.command.get_cmdline(target)) script = SCRIPT_RCE_BLIND.format( exploit_dir=self.directory, command=self.command.get_cmdline(target)) elif self.type == 'rce-standard': script = self.command.get_cmdline(target) else: logger.error('Unsupported exploit type') return None # Run subprocess try: logger.info('Exploit will be run from directory: {directory}'.format( directory=self.directory)) proc = subprocess.Popen(script, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # Agressivelly get the output while True: out = proc.stdout.read(1) # We put that inside try block to avoid utf8 decoding error try: out = out.decode(sys.stdout.encoding) sys.stdout.write(out) self.output += out except: pass # Break if process has finished if out == '' and proc.poll() != None: break except Exception as e: logger.error('Error when trying to run command: {exception}'.format( exception=e)) return None return self.output def check_success(self): if self.type == 'rce-blind': m = re.search(MATCHING_PATTERN_RCE_BLIND, self.output, re.IGNORECASE) elif self.type == 'rce-standard': m = re.search(self.success, self.output, re.IGNORECASE) return (m is not None)
class Exploit: def __init__(self, name, product, description, type_, detection_rawcmd, detection_success, exploit_rawcmd, exploit_rce_output, exploit_success): self.name = name self.product = product self.description = description self.type = type_ self.detection_rawcmd = detection_rawcmd self.detection_success = detection_success self.exploit_rawcmd = exploit_rawcmd self.exploit_rce_output = exploit_rce_output self.exploit_success = exploit_success self.directory = TOOL_BASEPATH + '/exploits/' + self.name.lower() self.output = '' def is_mode_supported(self, mode): """ Check is specified mode is supported (either "detect" or "exploit") :param str mode: Requested mode """ if mode == 'detect': return (self.detection_rawcmd is not None and len(self.detection_rawcmd) > 0) elif mode == 'exploit': return (self.exploit_rawcmd is not None and len(self.exploit_rawcmd) > 0) else: return False def run(self, target, mode, rce_command=''): """ :param Target targer: Target instance :param str mode: mode can be either "detect" or "exploit" :param str rce_command: RCE command to run when running exploit (requires mode=exploit) """ try: if mode == 'detect': self.command = Command(self.detection_rawcmd, self.type) elif mode == 'exploit': self.command = Command(self.exploit_rawcmd, self.type, self.exploit_rce_output) except CommandException as e: logger.error(e) return None # Build script to run if mode == 'exploit': if self.type == 'rce': if not self.exploit_rce_output: logger.warning('The exploit will attempt to execute command on remote system but no ' 'output will be available !') # For RCE exploit without command output in test mode (no rce_command provided): # Use script template that check for reverse connection with ICMP ping and HTTP requests if len(rce_command) == 0: logger.warning('WARNING: This attack box must be reachable from the target !') logger.info('No command supplied to run through RCE, automatic exploit test will be started...') logger.info('If target is vulnerable, exploit will try to ping (ICMP Echo request) and ' 'to send HTTP request to local IP = {localip} from target'.format( localip=NetUtils.get_local_ip_address())) cmdline = self.command.get_cmdline(target) print(cmdline) script = SCRIPT_RCE_BLIND.format( exploit_dir=self.directory, command=cmdline) else: cmdline = self.command.get_cmdline(target, rce_command) print(cmdline) script = 'cd {exploit_dir}; '.format(exploit_dir=self.directory) script += cmdline else: if len(rce_command) == 0: logger.info('No command supplied to run through RCE, automatic exploit test will be started...') logger.info('If target is vulnerable, exploit will try to run an echo command on target') cmdline = self.command.get_cmdline(target) print(cmdline) script = 'cd {exploit_dir}; '.format(exploit_dir=self.directory) script += cmdline else: cmdline = self.command.get_cmdline(target, rce_command) print(cmdline) script = 'cd {exploit_dir}; '.format(exploit_dir=self.directory) script += cmdline else: cmdline = self.command.get_cmdline(target) print(cmdline) script = 'cd {exploit_dir}; '.format(exploit_dir=self.directory) script += cmdline else: logger.warning('The script will attempt to detect if remote system is vulnerable without ' 'actually exploiting the vulnerability.') logger.warning('WARNING: False Positive is possible !') cmdline = self.command.get_cmdline(target) script = 'cd {exploit_dir}; '.format(exploit_dir=self.directory) script += cmdline # Run subprocess try: logger.info('{script} will be run from directory: {directory}'.format( script='Exploit' if mode == 'exploit' else 'Detection script', directory=self.directory)) proc = subprocess.Popen(script, shell=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # Agressivelly get the output while True: out = proc.stdout.read(1) # We put that inside try block to avoid utf8 decoding error try: out = out.decode(sys.stdout.encoding) sys.stdout.write(out) self.output += out except: pass # Break if process has finished if out == '' and proc.poll() != None: break except Exception as e: logger.error('Error when trying to run command: {exception}'.format( exception=e)) return None return self.output def check_success(self, mode): """ Check vuln detection success or exploit success when run in automatic test (i.e. no command provided via --cmd) :param str mode: mode can be either "detect" or "exploit" """ m = None if mode == 'detect': m = re.search(self.detection_success, self.output, re.IGNORECASE) if not m: if self.detection_success.lower() in self.output.lower(): m = self.detection_success elif mode == 'exploit': if self.type == 'rce': if self.exploit_rce_output: # RCE with command output: use success match string provided in settings m = re.search(self.exploit_success, self.output, re.IGNORECASE) if not m: if self.exploit_success.lower() in self.output.lower(): m = self.exploit_success else: # RCE without command output: use built-in match strings to detect either # ICMP echo reply or received HTTP request m = re.search(MATCHING_PATTERN_RCE_BLIND_ICMP, self.output, re.IGNORECASE) if not m: m = re.search(MATCHING_PATTERN_RCE_BLIND_HTTP, self.output, re.IGNORECASE) else: # Other exploit type (e.g. sqli) m = re.search(self.exploit_success, self.output, re.IGNORECASE) if not m: if self.exploit_success.lower() in self.output.lower(): m = self.exploit_success return (m is not None)