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(self): r = Requester.get('{}/console/j_security_check'.format(self.url)) if 'name="j_password"' in r.text: self.interface = 'weblogic-admin' self.interface_url = '{}/console/j_security_check'.format(self.url) logger.info('Weblogic administration console detected: {}'.format( self.interface_url)) logger.warning('Warning: By default, Weblogic has an account lockout ' \ 'feature (max 5 failures per 5 minutes, lockout duration of 30min)') return True logger.error('No Weblogic authentication interface detected') return False
def check(self): auth_type = Requester.get_http_auth_type('{}/manager/html'.format(self.url)) if auth_type is not AuthMode.UNKNOWN: self.interface = 'tomcat-manager' self.interface_url = '{}/manager/html'.format(self.url) self.http_auth_type = auth_type logger.info('Tomcat Manager interface detected: {}'.format( self.interface_url)) logger.warning('Warning: By default, Tomcat has an account lockout ' \ 'feature (max 5 failures, lockout duration of 300s)') return True logger.error('No Tomcat authentication interface detected') return False
def check(self): r = Requester.get(self.url) # Cookie potentially returned are kept to be sent in the auth request # because sometimes application might reject request if those cookies are not present self.cookies = r.cookies # Keep HTML source code of the page for diff calculation in heuristics checks # to determine if auth has failed/succeeded self.page_html = r.text soup = BeautifulSoup(r.text, 'html.parser') logger.warning('This module is based on heuristics and is prone to ' 'false negatives/positives') # Get all <form> on the page forms = soup.find_all('form') #print(forms) if not forms: logger.error('No standard web <form> found on the page') return False # Detect form with password field # 1. Check for standard <input type="password" ...> field # 2. Otherwise, check for <input type="text" ...> field with evocative name target_form = None is_input_password_type_text = False i = 0 for f in forms: input_password = f.find( 'input', type=lambda x: x and x.lower() == 'password', attrs={'name': True}) if not input_password: input_password = f.find( 'input', type=lambda x: x and x.lower() == 'text', attrs={ 'name': re.compile('.*(pass|pwd|pswd|pssw|pswrd).*', re.IGNORECASE) }) if input_password: is_input_password_type_text = True if input_password: target_form = f self.password_field = input_password.attrs['name'] self.form_number = i break i += 1 if target_form: logger.info( 'Standard web authentication <form> seems present on the page') logger.info('Detected password field name = {name}'.format( name=self.password_field)) else: logger.error( 'No standard web auth <form> with password field has been detected ' 'on the page') return False # Get action url (target) used when submitting form if target_form.has_attr('action'): form_action = target_form.attrs['action'] # Absolute URL if form_action.lower().startswith('http://') \ or form_action.lower().startswith('https://'): self.action_url = form_action # Relative path else: self.action_url = urljoin(self.url, form_action) else: self.action_url = r.url logger.info( 'Detected form action URL = {url}'.format(url=self.action_url)) # Get form method (default POST) try: self.method = target_form.attrs['method'].upper() except: self.method = 'POST' # Detect username field inputs_text = target_form.find_all('input', type=lambda x: x and x.lower() in ('text', 'email'), attrs={'name': True}) if is_input_password_type_text: try: inputs_text.remove( target_form.find('input', type=lambda x: x and x.lower() == 'text', attrs={'name': self.password_field})) except: pass if len(inputs_text) == 0: self.username_field = None elif len(inputs_text) == 1: # If only one input field type=text (except password field), take this one self.username_field = inputs_text[0].attrs['name'] else: # Take the one with the most explicit name if found, otherwise the first one self.username_field = self.__find_username_field_via_name( inputs_text) if not self.username_field: self.username_field = inputs_text[0].attrs['name'] # In rare case, username field can have no type if not self.username_field: inputs_no_type = target_form.find_all('input', type=False, attrs={'name': True}) self.username_field = self.__find_username_field_via_name( inputs_no_type) if self.username_field: logger.info('Detected username field name = {name}'.format( name=self.username_field)) else: logger.info( 'No username field detected, probably password-only authentication' ) # Heuristic check of anti-CSRF token self.has_csrftoken = target_form.find( 'input', type=lambda x: x and x.lower() == 'hidden') is not None if self.has_csrftoken: logger.info( 'Heuristic check determines form might have anti-CSRF token') # Get ordered list of all form parameters self.parameters = self.__extract_form_fields(target_form) return True
def run(self): # List supported modules if self.args.list: print('List of supported modules:') for mod in Utils.list_modules(): print('- {}'.format(mod)) return # Check if target is available logger.info( 'Check if target {url} is reachable...'.format(url=self.args.url)) try: r = Requester.get(self.args.url) except RequestException as e: logger.error('Target URL seems not reachable:') logger.error(e) sys.exit(0) logger.success('Connection to target OK. HTTP Status {}'.format( r.status_code)) # Handle potential <meta> refresh meta_refresh_url = Requester.get_meta_redirect_url( r.text, self.args.url) if meta_refresh_url: logger.info( 'Meta refresh mechanism has been detected. Following redirect...' ) self.args.url = meta_refresh_url try: r = Requester.get(self.args.url) except RequestException as e: logger.error('Redirected URL seems not reachable:') logger.error(e) sys.exit(0) logger.success( 'Connection to redirection OK. HTTP Status {}'.format( r.status_code)) # Create wordlist queue try: self.wordlist = Wordlist(self.args.username, self.args.userlist, self.args.password, self.args.passlist, self.args.combolist) logger.info('Number of creds that will be tested: {}'.format( self.wordlist.length)) except Exception as e: logger.error(e) sys.exit(0) # Initialize module try: mod = importlib.import_module('lib.modules.{}'.format( self.args.type.capitalize())) except Exception as e: logger.error('Error while importing module lib.modules.{}'.format( self.args.type.capitalize())) traceback.print_exc() return module = getattr(mod, self.args.type.capitalize())( self.args.url, verbose=self.args.verbose) # Detect authentication interface try: if not module.check(): return except RequestException as e: logger.warning(e) # Run bruteforce self.run_bruteforcer(module) self.output.newline('') logger.info('Bruteforce finished !') if self.args.verbose: if len(self.creds_found) > 0: logger.success('{} valid credentials found:'.format( len(self.creds_found))) for username, password in self.creds_found: logger.success('{}:{}'.format(username, password)) else: logger.error('No valid credentials found :\'(')
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