def _test_DNS(self, original_response, dns_wildcard_url): """ Check if http://www.domain.tld/ == http://domain.tld/ """ headers = Headers([('Host', dns_wildcard_url.get_domain())]) try: modified_response = self._uri_opener.GET( original_response.get_url(), cache=True, headers=headers) except BaseFrameworkException: return else: if relative_distance_lt(modified_response.get_body(), original_response.get_body(), 0.35): desc = 'The target site has NO DNS wildcard, and the contents' \ ' of "%s" differ from the contents of "%s".' desc = desc % (dns_wildcard_url, original_response.get_url()) i = Info('No DNS wildcard', desc, modified_response.id, self.get_name()) i.set_url(dns_wildcard_url) kb.kb.append(self, 'dns_wildcard', i) om.out.information(i.get_desc()) else: desc = 'The target site has a DNS wildcard configuration, the'\ ' contents of "%s" are equal to the ones of "%s".' desc = desc % (dns_wildcard_url, original_response.get_url()) i = Info('DNS wildcard', desc, modified_response.id, self.get_name()) i.set_url(original_response.get_url()) kb.kb.append(self, 'dns_wildcard', i) om.out.information(i.get_desc())
def _do_request(self, mutated_url, user): """ Perform the request and compare. :return: The HTTP response id if the mutated_url is a web user directory, None otherwise. """ response = self._uri_opener.GET(mutated_url, cache=True, headers=self._headers) path = mutated_url.get_path() response_body = response.get_body().replace(path, '') if relative_distance_lt(response_body, self._non_existent, 0.7): # Avoid duplicates if user not in [u['user'] for u in kb.kb.get('user_dir', 'users')]: desc = 'A user directory was found at: %s' desc = desc % response.get_url() i = Info('Web user home directory', desc, response.id, self.get_name()) i.set_url(response.get_url()) i['user'] = user kb.kb.append(self, 'users', i) for fr in self._create_fuzzable_requests(response): self.output_queue.put(fr) return response.id return None
def _test_DNS(self, original_response, dns_wildcard_url): """ Check if http://www.domain.tld/ == http://domain.tld/ """ headers = Headers([("Host", dns_wildcard_url.get_domain())]) try: modified_response = self._uri_opener.GET(original_response.get_url(), cache=True, headers=headers) except BaseFrameworkException: return else: if relative_distance_lt(modified_response.get_body(), original_response.get_body(), 0.35): desc = ( "The target site has NO DNS wildcard, and the contents" ' of "%s" differ from the contents of "%s".' ) desc = desc % (dns_wildcard_url, original_response.get_url()) i = Info("No DNS wildcard", desc, modified_response.id, self.get_name()) i.set_url(dns_wildcard_url) kb.kb.append(self, "dns_wildcard", i) om.out.information(i.get_desc()) else: desc = ( "The target site has a DNS wildcard configuration, the" ' contents of "%s" are equal to the ones of "%s".' ) desc = desc % (dns_wildcard_url, original_response.get_url()) i = Info("DNS wildcard", desc, modified_response.id, self.get_name()) i.set_url(original_response.get_url()) kb.kb.append(self, "dns_wildcard", i) om.out.information(i.get_desc())
def _check_existance(self, original_response, mutant): """ Actually check if the mutated URL exists. :return: None, all important data is put() to self.output_queue """ response = self._uri_opener.send_mutant(mutant) if not is_404(response) and relative_distance_lt(original_response.body, response.body, 0.85): # Verify against something random rand = rand_alpha() rand_mutant = mutant.copy() rand_mutant.set_mod_value(rand) rand_response = self._uri_opener.send_mutant(rand_mutant) if relative_distance_lt(response.body, rand_response.body, 0.85): for fr in self._create_fuzzable_requests(response): self.output_queue.put(fr)
def _check_existance(self, original_response, mutant): """ Actually check if the mutated URL exists. :return: None, all important data is put() to self.output_queue """ response = self._uri_opener.send_mutant(mutant) if not is_404(response) and \ relative_distance_lt(original_response.body, response.body, 0.85): # Verify against something random rand = rand_alpha() rand_mutant = mutant.copy() rand_mutant.set_mod_value(rand) rand_response = self._uri_opener.send_mutant(rand_mutant) if relative_distance_lt(response.body, rand_response.body, 0.85): for fr in self._create_fuzzable_requests(response): self.output_queue.put(fr)
def _do_request(self, fuzzable_request, original_resp, headers): """ Send the request. :param fuzzable_request: The modified fuzzable request :param original_resp: The response for the original request that was sent. """ response = self._uri_opener.GET(fuzzable_request.get_uri(), cache=True, headers=headers) add = False if not is_404(response): # We have different cases: # - If the URLs are different, then there is nothing to think # about, we simply found something new! if response.get_url() != original_resp.get_url(): add = True # - If the content type changed, then there is no doubt that # we've found something new! elif response.doc_type != original_resp.doc_type: add = True # - If we changed the query string parameters, we have to check # the content elif relative_distance_lt(response.get_clear_text_body(), original_resp.get_clear_text_body(), 0.8): # In this case what might happen is that the number we changed # is "out of range" and when requesting that it will trigger an # error in the web application, or show us a non-interesting # response that holds no content. # # We choose to return these to the core because they might help # with the code coverage efforts. Think about something like: # foo.aspx?id=OUT_OF_RANGE&foo=inject_here # vs. # foo.aspx?id=IN_RANGE&foo=inject_here # # This relates to the EXPECTED_URLS in test_digit_sum.py add = True if add: for fr in self._create_fuzzable_requests(response): self.output_queue.put(fr)
def _generic_vhosts(self, fuzzable_request): """ Test some generic virtual hosts, only do this once. """ # Get some responses to compare later base_url = fuzzable_request.get_url().base_url() original_response = self._uri_opener.GET(base_url, cache=True) orig_resp_body = original_response.get_body() non_existant_response = self._get_non_exist(fuzzable_request) nonexist_resp_body = non_existant_response.get_body() res = [] vhosts = self._get_common_virtualhosts(base_url) for vhost, vhost_response in self._send_in_threads(base_url, vhosts): vhost_resp_body = vhost_response.get_body() # If they are *really* different (not just different by some chars) if relative_distance_lt(vhost_resp_body, orig_resp_body, 0.35) and \ relative_distance_lt(vhost_resp_body, nonexist_resp_body, 0.35): res.append((vhost, vhost_response.id)) return res
def _analyze_response(self, original_resp, resp): """ :param original_resp: The HTTPResponse object that holds the ORIGINAL response. :param resp: The HTTPResponse object that holds the content of the response to analyze. """ if relative_distance_lt(original_resp.get_body(), resp.get_body(), 0.7): response_ids = [original_resp.id, resp.id] desc = '[Manual verification required] The response body for a ' \ 'request with a trailing dot in the domain, and the response ' \ 'body without a trailing dot in the domain differ. This could ' \ 'indicate a misconfiguration in the virtual host settings. In ' \ 'some cases, this misconfiguration permits the attacker to ' \ 'read the source code of the web application.' i = Info('Potential virtual host misconfiguration', desc, response_ids, self.get_name()) om.out.information(desc) kb.kb.append(self, 'domain_dot', i)
def _send_and_analyze(self, offending_string, offending_URL, original_resp_body, rnd_param): """ Actually send the HTTP request. :return: None, everything is saved to the self._filtered and self._not_filtered lists. """ try: resp_body = self._uri_opener.GET(offending_URL, cache=False).get_body() except BaseFrameworkException: # I get here when the remote end closes the connection self._filtered.append(offending_URL) else: # I get here when the remote end returns a 403 or something like # that... So I must analyze the response body resp_body = resp_body.replace(offending_string, '') resp_body = resp_body.replace(rnd_param, '') if relative_distance_lt(resp_body, original_resp_body, 0.15): self._filtered.append(offending_URL) else: self._not_filtered.append(offending_URL)
def _get_dead_links(self, fuzzable_request): """ Find every link on a HTML document verify if the domain is reachable or not; after that, verify if the web found a different name for the target site or if we found a new site that is linked. If the link points to a dead site then report it (it could be pointing to some private address or something...) """ # Get some responses to compare later base_url = fuzzable_request.get_url().base_url() original_response = self._uri_opener.GET(fuzzable_request.get_uri(), cache=True) base_response = self._uri_opener.GET(base_url, cache=True) base_resp_body = base_response.get_body() try: dp = parser_cache.dpc.get_document_parser_for(original_response) except BaseFrameworkException: # Failed to find a suitable parser for the document return [] # Set the non existant response non_existant_response = self._get_non_exist(fuzzable_request) nonexist_resp_body = non_existant_response.get_body() # Note: # - With parsed_references I'm 100% that it's really something in the HTML # that the developer intended to add. # # - The re_references are the result of regular expressions, which in some cases # are just false positives. # # In this case, and because I'm only going to use the domain name of the URL # I'm going to trust the re_references also. parsed_references, re_references = dp.get_references() parsed_references.extend(re_references) res = [] vhosts = self._verify_link_domain(parsed_references) for domain, vhost_response in self._send_in_threads(base_url, vhosts): vhost_resp_body = vhost_response.get_body() if relative_distance_lt(vhost_resp_body, base_resp_body, 0.35) and \ relative_distance_lt(vhost_resp_body, nonexist_resp_body, 0.35): res.append((domain, vhost_response.id)) else: desc = 'The content of "%s" references a non existant domain:'\ ' "%s". This can be a broken link, or an internal domain'\ ' name.' desc = desc % (fuzzable_request.get_url(), domain) i = Info('Internal hostname in HTML link', desc, original_response.id, self.get_name()) i.set_url(fuzzable_request.get_url()) kb.kb.append(self, 'find_vhosts', i) om.out.information(i.get_desc()) return res
def _get_dead_links(self, fuzzable_request): """ Find every link on a HTML document verify if the domain is reachable or not; after that, verify if the web found a different name for the target site or if we found a new site that is linked. If the link points to a dead site then report it (it could be pointing to some private address or something...) """ # Get some responses to compare later base_url = fuzzable_request.get_url().base_url() original_response = self._uri_opener.GET( fuzzable_request.get_uri(), cache=True) base_response = self._uri_opener.GET(base_url, cache=True) base_resp_body = base_response.get_body() try: dp = parser_cache.dpc.get_document_parser_for(original_response) except BaseFrameworkException: # Failed to find a suitable parser for the document return [] # Set the non existant response non_existant_response = self._get_non_exist(fuzzable_request) nonexist_resp_body = non_existant_response.get_body() # Note: # - With parsed_references I'm 100% that it's really something in the HTML # that the developer intended to add. # # - The re_references are the result of regular expressions, which in some cases # are just false positives. # # In this case, and because I'm only going to use the domain name of the URL # I'm going to trust the re_references also. parsed_references, re_references = dp.get_references() parsed_references.extend(re_references) res = [] vhosts = self._verify_link_domain(parsed_references) for domain, vhost_response in self._send_in_threads(base_url, vhosts): vhost_resp_body = vhost_response.get_body() if relative_distance_lt(vhost_resp_body, base_resp_body, 0.35) and \ relative_distance_lt(vhost_resp_body, nonexist_resp_body, 0.35): res.append((domain, vhost_response.id)) else: desc = 'The content of "%s" references a non existant domain:'\ ' "%s". This can be a broken link, or an internal domain'\ ' name.' desc = desc % (fuzzable_request.get_url(), domain) i = Info('Internal hostname in HTML link', desc, original_response.id, self.get_name()) i.set_url(fuzzable_request.get_url()) kb.kb.append(self, 'find_vhosts', i) om.out.information(i.get_desc()) return res
ip_address = socket.gethostbyname(domain) except: return url = original_response.get_url() ip_url = url.copy() ip_url.set_domain(ip_address) try: modified_response = self._uri_opener.GET(ip_url, cache=True) except BaseFrameworkException, w3: msg = 'An error occurred while fetching IP address URL in ' \ ' dns_wildcard plugin: "%s"' % w3 om.out.debug(msg) else: if relative_distance_lt(modified_response.get_body(), original_response.get_body(), 0.35): desc = 'The contents of %s and %s differ.' desc = desc % (modified_response.get_uri(), original_response.get_uri()) i = Info('Default virtual host', desc, modified_response.id, self.get_name()) i.set_url(modified_response.get_url()) kb.kb.append(self, 'dns_wildcard', i) om.out.information(i.get_desc()) def _test_DNS(self, original_response, dns_wildcard_url): """ Check if http://www.domain.tld/ == http://domain.tld/
try: ip_address = socket.gethostbyname(domain) except: return url = original_response.get_url() ip_url = url.copy() ip_url.set_domain(ip_address) try: modified_response = self._uri_opener.GET(ip_url, cache=True) except BaseFrameworkException, w3: msg = "An error occurred while fetching IP address URL in " ' dns_wildcard plugin: "%s"' % w3 om.out.debug(msg) else: if relative_distance_lt(modified_response.get_body(), original_response.get_body(), 0.35): desc = "The contents of %s and %s differ." desc = desc % (modified_response.get_uri(), original_response.get_uri()) i = Info("Default virtual host", desc, modified_response.id, self.get_name()) i.set_url(modified_response.get_url()) kb.kb.append(self, "dns_wildcard", i) om.out.information(i.get_desc()) def _test_DNS(self, original_response, dns_wildcard_url): """ Check if http://www.domain.tld/ == http://domain.tld/ """ headers = Headers([("Host", dns_wildcard_url.get_domain())])