def try_auth(self, username, password): if self.interface == 'joomla-admin': r = Requester.get(self.interface_url) data = { 'username': username, 'passwd': password, #'lang': 'en-GB', 'option': self.option, 'task': 'login', self.token: '1', } r = Requester.post(self.interface_url, data, headers={ 'Cookie': self.cookie, }) if 'input name="passwd"' not in r.text: self.cookie = 'a=a' return True else: return False else: raise AuthException('No auth interface found during intialization')
def __init__(self, arguments, output): self.output = output self.random_agents = [] if arguments.random_agent: try: filename = os.path.dirname( os.path.realpath(__file__)) + '/../../db/agent.txt' with open(filename, 'r') as f: lines = f.readlines() for line in lines: line = line.strip() self.random_agents.append(line) except IOError as e: raise e self.recursive = arguments.recursive self.random_agent = arguments.random_agent self.dictionary = Dictionary(arguments.wordList, arguments.lowercase, arguments.uppercase, arguments.extension) self.output.header( open(os.path.dirname(__file__) + '/banner.txt', 'r').read()) self.output.configReport(arguments.extension, str(arguments.threads_count), str(len(self.dictionary)), str(self.recursive), str(arguments.delay), str(arguments.timeout)) self.urlList = arguments.urlList try: for url in self.urlList: self.url = url try: self.output.targetReport(url) try: self.requester = Requester( url, arguments.headers, arguments.user_agent, arguments.cookies, arguments.proxy, arguments.delay, arguments.timeout, arguments.random_agent, self.random_agents, arguments.max_retries) self.requester.request('/') except RequesterException as e: self.output.error(e.args[0]['message']) raise SkipTargetInterrupt self.scanner = Scanner( self.requester, self.dictionary, arguments.path_404, arguments.threads_count, self.matchCallBack, self.failCallBack, self.errorCallBack, arguments.sensor) self.wait(url) except SkipTargetInterrupt: continue finally: self.recursive -= 1 except KeyboardInterrupt: self.output.error('\nexit by user') exit(0) finally: self.output.warning( 'Scanning Over! Result stores in report folder')
def check(self): # Server Administration r = Requester.get('{}/railo-context/admin/server.cfm'.format(self.url)) if r.status_code == 200 and 'type="password"' in r.text: self.interface = 'railo-server-admin' self.interface_url = '{}/railo-context/admin/server.cfm'.format( self.url) logger.info( 'Railo Server administration console detected: {}'.format( self.interface_url)) return True # Web Administration r = Requester.get('{}/railo-context/admin/web.cfm'.format(self.url)) if r.status_code == 200 and 'type="password"' in r.text: self.interface = 'railo-server-admin' self.interface_url = '{}/railo-context/admin/web.cfm'.format( self.url) logger.info('Railo Web administration console detected: {}'.format( self.interface_url)) return True logger.error('No Railo authentication interface detected') return False
def try_auth(self, username, password): if self.interface == 'admin-console': # We need to retrieve ViewState value r = Requester.get(self.interface_url) m = re.search('<input type="hidden" name="javax\.faces\.ViewState" ' \ 'id="javax\.faces\.ViewState" value="(?P<viewstate>.*?)"', r.text) if not m: raise RequestException( 'Unable to retrieve ViewState from {}'.format( self.interface_url)) data = OrderedDict([ ("login_form", "login_form"), ("login_form:name", username), ("login_form:password", password), ("login_form:submit", "Login"), ("javax.faces.ViewState", m.group('viewstate')), ]) # We also need to retrieve JSESSIONID value m = re.search( r'JSESSIONID=(?P<jsessionid>.*); Path=\/admin-console', r.headers['Set-Cookie']) if not m: raise RequestException('Unable to retrieve JSESSIONID value ' \ 'from {}'.format(self.interface_url)) r = Requester.post(self.interface_url, data, headers={ 'Cookie': 'JSESSIONID={}'.format( m.group('jsessionid')) }, allow_redirects=False) status = ('name="login_form:password"' not in r.text \ and 'Not logged in' not in r.text) return status elif self.interface == 'jmx-console': r = Requester.http_auth(self.interface_url, self.http_auth_type, username, password) return (r.status_code != 401) elif self.interface == 'management': r = Requester.http_auth(self.interface_url, self.http_auth_type, username, password) return (r.status_code != 401) elif self.interface == 'web-console': r = Requester.http_auth(self.interface_url, self.http_auth_type, username, password) return (r.status_code != 401) else: raise AuthException( 'No auth interface found during initialization')
def check(self): r = Requester.get('{}/CFIDE/administrator/enter.cfm'.format(self.url)) if r.status_code == 200 and 'type="password"' in r.text.lower(): self.interface_url = '{}/CFIDE/administrator/enter.cfm'.format( self.url) # Version 6 if 'name="cfadminPassword"' in r.text \ and 'name="requestedURL"' in r.text \ and 'name="cfadminUserId"' not in r.text \ and 'name="salt"' not in r.text: self.interface = 'coldfusion-6-admin' logger.info( 'Coldfusion 6 administration console detected: {}'.format( self.interface_url)) return True # Versions 7/8/9 elif 'name="cfadminPassword"' in r.text \ and 'name="requestedURL"' in r.text \ and 'name="cfadminUserId"' in r.text \ and 'name="salt"' in r.text: self.interface = 'coldfusion-7-8-9-admin' logger.info( 'Coldfusion 7/8/9 administration console detected: {}'. format(self.interface_url)) return True # Versions 10/11 elif 'name="cfadminPassword"' in r.text \ and 'name="requestedURL"' in r.text \ and 'name="cfadminUserId"' in r.text \ and 'name="salt"' not in r.text: self.interface = 'coldfusion-10-11-admin' logger.info( 'Coldfusion 10/11 administration console detected: {}'. format(self.interface_url)) return True r = Requester.get('{}/CFIDE/administrator/index.cfm'.format(self.url)) if r.status_code == 200 and 'type="password"' in r.text.lower(): self.interface_url = '{}/CFIDE/administrator/index.cfm'.format( self.url) # Version 5 if 'name="PasswordProvided_required"' in r.text \ and 'name="PasswordProvided"' in r.text: self.interface = 'coldfusion-5-admin' logger.info( 'Coldfusion 5 administration console detected: {}'.format( self.interface_url)) return True logger.error('No Coldfusion authentication interface detected') return False
def try_auth(self, username, password): if self.interface == 'coldfusion-5-admin': data = { 'PasswordProvided_required': 'You+must+provide+a+password.', 'PasswordProvided': password, 'Submit': 'Password', } r = Requester.post(self.interface_url, data) return (r.status_code == 200 and 'name="PasswordProvided"' not in r.text) elif self.interface == 'coldfusion-6-admin': data = { 'cfadminPassword': password, 'requestedURL': '/CFIDE/administrator/index.cfm', 'submit': 'Login', } r = Requester.post(self.interface_url, data) return (r.status_code == 200 and 'name="cfadminPassword"' not in r.text) elif self.interface == 'coldfusion-7-8-9-admin': salt = self._get_salt(self.interface_url) hash_ = hmac.new( bytes(salt, 'ascii'), bytes( hashlib.sha1(password.encode('utf-8')).hexdigest().upper(), 'ascii'), hashlib.sha1).hexdigest().upper() data = { 'cfadminPassword': hash_, 'requestedURL': '/CFIDE/administrator/enter.cfm?', 'cfadminUserId': username, 'salt': salt, 'submit': 'Login', } r = Requester.post(self.interface_url, data) return (r.status_code == 200 and 'name="cfadminPassword"' not in r.text) elif self.interface == 'coldfusion-10-11-admin': hash_ = hashlib.sha1(password.encode('utf-8')).hexdigest().upper() data = { 'cfadminPassword': hash_, 'requestedURL': '/CFIDE/administrator/enter.cfm?', 'cfadminUserId': username, 'submit': 'Login', } r = Requester.post(self.interface_url, data) return (r.status_code == 200 and 'name="cfadminPassword"' not in r.text)
def try_auth(self, username, password): if self.interface == 'htaccess': r = Requester.http_auth(self.interface_url, self.http_auth_type, username, password) return (r.status_code != 401) else: raise AuthException('No auth interface found during initialization')
def _get_salt(self, url): r = Requester.get(url) m = re.search( '<input name="salt" type="hidden" value="(?P<salt>\S+?)">', r.text) if not m: raise RequestException( 'Unable to retrieve salt from {}'.format(url)) else: return m.group('salt')
def try_auth(self, username, password): # Note: In Railo, there is no username data = OrderedDict([("lang", "en"), ("rememberMe", "yyyy"), ("submit", "submit")]) if self.interface == 'railo-server-admin': data['login_passwordserver'] = password r = Requester.post(self.interface_url, data) return ('login.login_password' not in r.text) elif self.interface == 'railo-web-admin': data['login_passwordweb'] = password r = Requester.post(self.interface_url, data) return ('login.login_password' not in r.text) else: raise AuthException( 'No auth interface found during initialization')
def check(self): r = Requester.get('{}/axis2/axis2-admin/login'.format(self.url)) if r.status_code == 200 and 'name="password"' in r.text: self.interface = 'axis2-admin' self.interface_url = '{}/axis2/axis2-admin/login'.format(self.url) logger.info('Axis2 administration console detected: {}'.format( self.interface_url)) return True logger.error('No Axis2 authentication interface detected') return False
def try_auth(self, username, password): if self.interface == 'axis2-admin': data = { 'userName': username, 'password': password, 'submit': '+Login+', } r = Requester.post(self.interface_url, data) return (r.status_code == 200 and 'name="password"' not in r.text) else: raise AuthException('No auth interface found during initialization')
def try_auth(self, username, password): if self.interface == 'jenkins-admin': data = { 'j_username': username, 'j_password': password, 'Submit': 'Sign+in', } r = Requester.post(self.action_url, data) return ('name="j_password"' not in r.text) else: raise AuthException('No auth interface found during initialization')
def check(self): # Interface 1: admin-console r = Requester.get('{}/admin-console/login.seam'.format(self.url)) if r.status_code == 200: self.interface = 'admin-console' self.interface_url = '{}/admin-console/login.seam'.format(self.url) logger.info('Jboss authentication interface detected: {}'.format( self.interface_url)) return True # Interface 2: jmx-console auth_type = Requester.get_http_auth_type('{}/jmx-console/'.format( self.url)) if auth_type is not AuthMode.UNKNOWN: self.interface = 'jmx-console' self.interface_url = '{}/jmx-console/'.format(self.url) self.http_auth_type = auth_type logger.info('Jboss jmx-console interface detected: {}'.format( self.interface_url)) return True # Interface 3: web-console auth_type = Requester.get_http_auth_type('{}/web-console/'.format( self.url)) if auth_type is not AuthMode.UNKNOWN: self.interface = 'web-console' self.interface_url = '{}/web-console/'.format(self.url) self.http_auth_type = auth_type logger.info('Jboss web-console interface detected: {}'.format( self.interface_url)) return True # Interface 4: management auth_type = Requester.get_http_auth_type('{}/management/'.format( self.url)) if auth_type is not AuthMode.UNKNOWN: self.interface = 'management' self.interface_url = '{}/management/'.format(self.url) self.http_auth_type = auth_type logger.info('Jboss management interface detected: {}'.format( self.interface_url)) return True # Interface 5: management 2 r = Requester.get('{}/console'.format(self.url)) if r.status_code == 200: tmp = r.url[:r.url.rindex('/')] self.interface_url = '{0}/management'.format(tmp[:tmp.rindex('/')]) auth_type = Requester.get_http_auth_type(self.interface_url) if auth_type is not AuthMode.UNKNOWN: self.interface = 'management' self.http_auth_type = auth_type logger.info('Jboss management interface detected: {}'.format( self.interface_url)) return True logger.error('No Jboss authentication interface detected') return False
def check(self): auth_type = Requester.get_http_auth_type('{}/'.format(self.url)) if auth_type is not AuthMode.UNKNOWN: self.interface = 'htaccess' self.interface_url = '{}/'.format(self.url) self.http_auth_type = auth_type logger.info('HTTP Authentication detected: {}'.format( self.interface_url)) return True logger.error('No HTTP authentication interface detected') return False
def try_auth(self, username, password): if self.interface == 'weblogic-admin': data = { 'j_username': username, 'j_password': password, 'j_character_encoding': 'UTF-8', } r = Requester.post(self.interface_url, data) return ('name="j_password"' not in r.text) else: raise AuthException( 'No auth interface found during initialization')
def check(self): r = Requester.get('{}/ibm/console/logon.jsp'.format(self.url)) if 'name="j_password"' in r.text: self.interface = 'websphere-admin' self.interface_url = '{}/ibm/console/logon.jsp'.format(self.url) self.action_url = '{}/ibm/console/j_security_check'.format(self.url) logger.info('Websphere administration console detected: {}'.format( self.interface_url)) return True logger.error('No Websphere authentication interface detected') return False
def check(self): auth_type = Requester.get_http_auth_type('{}/management/domain'.format( self.url)) if auth_type is not AuthMode.UNKNOWN: self.interface = 'glassfish-admin' self.interface_url = '{}/management/domain'.format(self.url) self.http_auth_type = auth_type logger.info('Glassfish admin interface detected: {}'.format( self.interface_url)) return True logger.error('No Glassfish authentication interface detected') return False
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): """ <form method="post" name="login" action="j_acegi_security_check" style="text-size:smaller"> <table><tr><td>User:</td><td><input type="text" name="j_username" id="j_username" autocorrect="off" autocapitalize="off" /> </td></tr><tr><td>Password:</td><td><input type="password" name="j_password" /></td></tr><tr><td align="right"> <input id="remember_me" type="checkbox" name="remember_me" /></td><td><label for="remember_me">Remember me on this computer</label> </td></tr></table><input name="from" type="hidden" value="/" /> <input name="Submit" type="submit" value="log in" class="submit-button primary" /><script> $('j_username').focus(); </script></form> """ r = Requester.get('{}/login'.format(self.url)) if r.status_code == 200 and 'name="j_password"' in r.text: self.interface = 'jenkins-admin' self.interface_url = '{}/login'.format(self.url) self.action_url = '{}/j_acegi_security_check'.format(self.url) logger.info('Jenkins administration console detected: {}'.format( self.interface_url)) return True logger.error('No Jenkins authentication interface detected') return False
def check(self): r = Requester.get('{}/administrator/index.php'.format(self.url)) #print(r.headers) if 'form action="/administrator/index.php"' in r.text: self.interface = 'joomla-admin' self.interface_url = '{}/administrator/index.php'.format(self.url) logger.info('Joomla administration page detected: {}'.format( self.interface_url)) # Extract session cookie try: self.cookie = r.headers['Set-Cookie'].split(';')[0] logger.info('Extracted session cookie: {}'.format(self.cookie)) except: logger.error('Unable to extract session cookie') return False # Extract token m = re.search('type="hidden" name="(.*)" value="1"', r.text) try: self.token = m.group(1) logger.info('Extracted token value: {}'.format(self.token)) except: logger.error('Unable to extract token from page !') return False # Extract option m = re.search('type="hidden" name="option" value="(.*)"', r.text) try: self.option = m.group(1) except: # Default option value self.option = 'com_login' return True logger.error('No Joomla administration interface detected') return False
class Controller(object): def __init__(self, arguments, output): self.output = output self.random_agents = [] if arguments.random_agent: try: filename = os.path.dirname( os.path.realpath(__file__)) + '/../../db/agent.txt' with open(filename, 'r') as f: lines = f.readlines() for line in lines: line = line.strip() self.random_agents.append(line) except IOError as e: raise e self.recursive = arguments.recursive self.random_agent = arguments.random_agent self.dictionary = Dictionary(arguments.wordList, arguments.lowercase, arguments.uppercase, arguments.extension) self.output.header( open(os.path.dirname(__file__) + '/banner.txt', 'r').read()) self.output.configReport(arguments.extension, str(arguments.threads_count), str(len(self.dictionary)), str(self.recursive), str(arguments.delay), str(arguments.timeout)) self.urlList = arguments.urlList try: for url in self.urlList: self.url = url try: self.output.targetReport(url) try: self.requester = Requester( url, arguments.headers, arguments.user_agent, arguments.cookies, arguments.proxy, arguments.delay, arguments.timeout, arguments.random_agent, self.random_agents, arguments.max_retries) self.requester.request('/') except RequesterException as e: self.output.error(e.args[0]['message']) raise SkipTargetInterrupt self.scanner = Scanner( self.requester, self.dictionary, arguments.path_404, arguments.threads_count, self.matchCallBack, self.failCallBack, self.errorCallBack, arguments.sensor) self.wait(url) except SkipTargetInterrupt: continue finally: self.recursive -= 1 except KeyboardInterrupt: self.output.error('\nexit by user') exit(0) finally: self.output.warning( 'Scanning Over! Result stores in report folder') def recursive_path(self, url): if self.recursive >= 1: if url.endswith('/'): if url not in self.urlList: self.urlList.append(url) def matchCallBack(self, path, response): self.output.statusReport(path, response, self.url) self.recursive_path(response.url) self.index += 1 def failCallBack(self, path, length): self.index += 1 self.output.lastPath(path, self.index, length) def errorCallBack(self, reason): self.output.error(reason) def handleInterrupt(self): self.output.warning('\ncatch out ctrl+c, process suspend') self.scanner.threadSuspend() while True: msg = '[e]xit | [c]ontinue' if len(self.urlList) > 1: msg += ' | [s]kipt' self.output.inLine(msg + ': ') option = input() if option.lower() == 'e': self.scanner.threadStop() raise KeyboardInterrupt elif option.lower() == 'c': self.scanner.threadResume() break elif option.lower() == 's': raise SkipTargetInterrupt else: continue def wait(self, url): self.index = 0 self.output.warning('\n{0} start at {1}'.format( url, time.strftime('%H:%M:%S'))) self.scanner.start() while True: try: while not self.scanner.over(): continue break except (KeyboardInterrupt, SystemExit): self.handleInterrupt()
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 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 try_auth(self, username, password): # If anti-CSRF token might be present, reload the page before every attempt # and re-extract form fields if self.has_csrftoken: r = Requester.get(self.url) self.cookies = r.cookies soup = BeautifulSoup(r.text, 'html.parser') try: target_form = soup.find_all('form')[self.form_number] except: raise AuthException( 'Problem occured when reloading page. Maybe some WAF/Protection ' 'is blocking us ?') self.parameters = self.__extract_form_fields(target_form) if self.password_field not in self.parameters.keys() \ or (self.username_field and self.username_field not in self.parameters.keys()): raise AuthException( 'Problem occured when reloading page. Maybe some WAF/Protection ' 'is blocking us ?') # Send authentication request if self.username_field: self.parameters[self.username_field] = username self.parameters[self.password_field] = password if self.method == 'GET': r = Requester.get(self.action_url, params=self.parameters, cookies=self.cookies) else: r = Requester.post(self.action_url, data=self.parameters, cookies=self.cookies) if self.verbose: logger.info('Raw HTTP Request/Response:') data = dump.dump_all(r) print(data.decode('utf-8')) # Check authentication status # HTTP response code check if r.status_code >= 400: return False # Check if response page contains password field soup = BeautifulSoup(r.text, 'html.parser') input_password = soup.find('input', attrs={'name': self.password_field}) if input_password: return False # Heuristic check of failed attemps based on possible error messages if re.search( '(username\s+or\s+password|cannot\s+log\s*in|unauthorized' '|auth(entication)?\s+fail|(invalid|wrong)\s+(cred|user|login|mail|email|e-mail|pass)' '|error\s+during\s+(login|auth))', r.text, re.IGNORECASE): return False # Heuristic check of successful attempt based on page content if re.search('(log\s*out|log\s*off|deconn?e|disconn?ec)', r.text, re.IGNORECASE): return True # Heuristic check of account lockout based on possible error messages if re.search( '(too\s+many\s+(failed)?\s*(attempt|try|tri)|account\s+(lock|block))', r.text, re.IGNORECASE): return False # Heuristic check based on source code difference with original page s = difflib.SequenceMatcher(None, self.page_html, r.text) return (s.quick_ratio() < 0.60)