def write_vuln_to_kb(vulnty, url, funcs): vulndata = php_sca.KB_DATA[vulnty] for f in funcs: vuln_sev = vulndata['severity'] desc = name = vulndata['name'] v = Vuln(name, desc, vuln_sev, 1, 'PHP Static Code Analyzer') v.set_uri(url) v.set_token((f.vulnsources[0], 0)) args = list(vulndata['kb_key']) + [v] # TODO: Extract the method from the PHP code # $_GET == GET # $_POST == POST # $_REQUEST == GET v.set_method('GET') # TODO: Extract all the other variables that are # present in the PHP file using the SCA v.set_dc(DataContainer()) # # TODO: This needs to be checked! OS Commanding specific # attributes. v['os'] = 'unix' v['separator'] = '' kb.kb.append(*args)
def _classic_worker(self, gh, search_term): """ Perform the searches and store the results in the kb. """ google_list = self._google_se.get_n_results(search_term, 9) for result in google_list: # I found a vuln in the site! response = self._uri_opener.GET(result.URL, cache=True) if not is_404(response): desc = 'ghdb plugin found a vulnerability at URL: "%s".' \ ' According to GHDB the vulnerability description'\ ' is "%s".' desc = desc % (response.get_url(), gh.desc) v = Vuln('Google hack database match', desc, severity.MEDIUM, response.id, self.get_name()) v.set_url(response.get_url()) v.set_method('GET') kb.kb.append(self, 'vuln', v) om.out.vulnerability(v.get_desc(), severity=severity.LOW) # Create the fuzzable requests for fr in self._create_fuzzable_requests(response): self.output_queue.put(fr)
def _PROPFIND(self, domain_path): """ Test PROPFIND method """ content = "<?xml version='1.0'?>\r\n" content += "<a:propfind xmlns:a='DAV:'>\r\n" content += "<a:prop>\r\n" content += "<a:displayname:/>\r\n" content += "</a:prop>\r\n" content += "</a:propfind>\r\n" headers = copy.deepcopy(self.CONTENT_TYPE) headers['Depth'] = '1' res = self._uri_opener.PROPFIND(domain_path, data=content, headers=headers) if "D:href" in res and res.get_code() in xrange(200, 300): msg = 'Directory listing with HTTP PROPFIND method was found at' \ ' directory: "%s".' % domain_path v = Vuln('Insecure DAV configuration', msg, severity.MEDIUM, res.id, self.get_name()) v.set_url(res.get_url()) v.set_method('PROPFIND') self.kb_append(self, 'dav', v)
def _SEARCH(self, domain_path): """ Test SEARCH method. """ content = "<?xml version='1.0'?>\r\n" content += "<g:searchrequest xmlns:g='DAV:'>\r\n" content += "<g:sql>\r\n" content += "Select 'DAV:displayname' from scope()\r\n" content += "</g:sql>\r\n" content += "</g:searchrequest>\r\n" res = self._uri_opener.SEARCH(domain_path, data=content, headers=self.CONTENT_TYPE) content_matches = '<a:response>' in res or '<a:status>' in res or \ 'xmlns:a="DAV:"' in res if content_matches and res.get_code() in xrange(200, 300): msg = 'Directory listing with HTTP SEARCH method was found at' \ 'directory: "%s".' % domain_path v = Vuln('Insecure DAV configuration', msg, severity.MEDIUM, res.id, self.get_name()) v.set_url(res.get_url()) v.set_method('SEARCH') self.kb_append(self, 'dav', v)
def _classic_worker(self, gh, search_term): """ Perform the searches and store the results in the kb. """ google_list = self._google_se.get_n_results(search_term, 9) for result in google_list: # I found a vuln in the site! response = self._uri_opener.GET(result.URL, cache=True) if not is_404(response): desc = ('ghdb plugin found a vulnerability at URL: "%s".' ' According to GHDB the vulnerability description' ' is "%s".') desc %= (response.get_url(), gh.desc) v = Vuln('Google hack database match', desc, severity.MEDIUM, response.id, self.get_name()) v.set_url(response.get_url()) v.set_method('GET') kb.kb.append(self, 'vuln', v) om.out.vulnerability(v.get_desc(), severity=severity.LOW) # Create the fuzzable requests fr = FuzzableRequest(response.get_url()) self.output_queue.put(fr)
def _analyze_crossdomain_clientaccesspolicy(self, url, response, file_name): # https://github.com/andresriancho/w3af/issues/14491 if file_name not in self.FILE_TAG_ATTR: return try: dom = xml.dom.minidom.parseString(response.get_body()) except Exception: # Report this, it may be interesting for the final user # not a vulnerability per-se... but... it's information after all if 'allow-access-from' in response.get_body() or \ 'cross-domain-policy' in response.get_body() or \ 'cross-domain-access' in response.get_body(): desc = 'The "%s" file at: "%s" is not a valid XML.' desc %= (file_name, response.get_url()) i = Info('Invalid RIA settings file', desc, response.id, self.get_name()) i.set_url(response.get_url()) kb.kb.append(self, 'info', i) om.out.information(i.get_desc()) return tag, attribute = self.FILE_TAG_ATTR.get(file_name) url_list = dom.getElementsByTagName(tag) for url in url_list: url = url.getAttribute(attribute) if url == '*': desc = 'The "%s" file at "%s" allows flash/silverlight'\ ' access from any site.' desc %= (file_name, response.get_url()) v = Vuln('Insecure RIA settings', desc, severity.LOW, response.id, self.get_name()) v.set_url(response.get_url()) v.set_method('GET') kb.kb.append(self, 'vuln', v) om.out.vulnerability(v.get_desc(), severity=v.get_severity()) else: desc = 'The "%s" file at "%s" allows flash/silverlight'\ ' access from "%s".' desc %= (file_name, response.get_url(), url) i = Info('Cross-domain allow ACL', desc, response.id, self.get_name()) i.set_url(response.get_url()) i.set_method('GET') kb.kb.append(self, 'info', i) om.out.information(i.get_desc())
def _PUT(self, domain_path): """ Tests PUT method. """ # upload url = domain_path.url_join(rand_alpha(5)) rnd_content = rand_alnum(6) headers = Headers([('content-type', 'text/plain')]) put_response = self._uri_opener.PUT(url, data=rnd_content, headers=headers) # check if uploaded res = self._uri_opener.GET(url, cache=True) if res.get_body() == rnd_content: msg = 'File upload with HTTP PUT method was found at resource:' \ ' "%s". A test file was uploaded to: "%s".' msg = msg % (domain_path, res.get_url()) v = Vuln('Insecure DAV configuration', msg, severity.HIGH, [put_response.id, res.id], self.get_name()) v.set_url(url) v.set_method('PUT') self.kb_append(self, 'dav', v) # Report some common errors elif put_response.get_code() == 500: msg = 'DAV seems to be incorrectly configured. The web server' \ ' answered with a 500 error code. In most cases, this means'\ ' that the DAV extension failed in some way. This error was'\ ' found at: "%s".' % put_response.get_url() i = Info('DAV incorrect configuration', msg, res.id, self.get_name()) i.set_url(url) i.set_method('PUT') self.kb_append(self, 'dav', i) # Report some common errors elif put_response.get_code() == 403: msg = 'DAV seems to be correctly configured and allowing you to'\ ' use the PUT method but the directory does not have the'\ ' correct permissions that would allow the web server to'\ ' write to it. This error was found at: "%s".' msg = msg % put_response.get_url() i = Info('DAV incorrect configuration', msg, [put_response.id, res.id], self.get_name()) i.set_url(url) i.set_method('PUT') self.kb_append(self, 'dav', i)
def _analyze_crossdomain_clientaccesspolicy(self, url, response, file_name): try: dom = xml.dom.minidom.parseString(response.get_body()) except Exception: # Report this, it may be interesting for the final user # not a vulnerability per-se... but... it's information after all if 'allow-access-from' in response.get_body() or \ 'cross-domain-policy' in response.get_body() or \ 'cross-domain-access' in response.get_body(): desc = 'The "%s" file at: "%s" is not a valid XML.' desc = desc % (file_name, response.get_url()) i = Info('Invalid RIA settings file', desc, response.id, self.get_name()) i.set_url(response.get_url()) kb.kb.append(self, 'info', i) om.out.information(i.get_desc()) else: if file_name == 'crossdomain.xml': url_list = dom.getElementsByTagName("allow-access-from") attribute = 'domain' if file_name == 'clientaccesspolicy.xml': url_list = dom.getElementsByTagName("domain") attribute = 'uri' for url in url_list: url = url.getAttribute(attribute) if url == '*': desc = 'The "%s" file at "%s" allows flash/silverlight'\ ' access from any site.' desc = desc % (file_name, response.get_url()) v = Vuln('Insecure RIA settings', desc, severity.LOW, response.id, self.get_name()) v.set_url(response.get_url()) v.set_method('GET') kb.kb.append(self, 'vuln', v) om.out.vulnerability(v.get_desc(), severity=v.get_severity()) else: desc = 'The "%s" file at "%s" allows flash/silverlight'\ ' access from "%s".' desc = desc % (file_name, response.get_url(), url) i = Info('Cross-domain allow ACL', desc, response.id, self.get_name()) i.set_url(response.get_url()) i.set_method('GET') kb.kb.append(self, 'info', i) om.out.information(i.get_desc())
def _send_and_check(self, nikto_test): """ This method sends the request to the server. :return: True if the requested URI responded as expected. """ # # Small performance improvement. If all we want to know is if the # file exists or not, lets use HEAD instead of GET. In 99% of the # cases this will work as expected and we'll have a significant # performance improvement. # if nikto_test.is_vulnerable.checks_only_response_code(): try: http_response = self._uri_opener.HEAD(nikto_test.uri) except Exception: return else: if not nikto_test.is_vulnerable.check(http_response): return False function_ptr = getattr(self._uri_opener, nikto_test.method) try: http_response = function_ptr(nikto_test.uri) except BaseFrameworkException as e: msg = ('An exception was raised while requesting "%s", the error' ' message is: "%s".') om.out.error(msg % (nikto_test.uri, e)) return False if nikto_test.is_vulnerable.check(http_response) and \ not is_404(http_response): vdesc = ('pykto plugin found a vulnerability at URL: "%s".' ' Vulnerability description: "%s".') vdesc = vdesc % (http_response.get_url(), nikto_test.message) v = Vuln('Insecure URL', vdesc, severity.LOW, http_response.id, self.get_name()) v.set_uri(http_response.get_uri()) v.set_method(nikto_test.method) kb.kb.append(self, 'vuln', v) om.out.vulnerability(v.get_desc(), severity=v.get_severity()) fr = FuzzableRequest.from_http_response(http_response) self.output_queue.put(fr)
def _from_csv_get_vulns(self): file_vulns = [] vuln_reader = csv.reader(open(self.OUTPUT_FILE, 'rb'), delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL) for name, method, uri, var, dc, _id, desc in vuln_reader: v = Vuln(name, desc, 'High', json.loads(_id), 'TestCase') v.set_method(method) v.set_uri(URL(uri)) v.set_var(var) v.set_dc(dc) file_vulns.append(v) return file_vulns
def _verify_upload(self, domain_path, rand_file, upload_id, debugging_id): """ Verify if the file was uploaded. :param domain_path: http://localhost/f00/ :param rand_file: The filename that was (potentially) uploaded :param upload_id: The id of the POST request to author.dll """ target_url = domain_path.url_join(rand_file) try: res = self._uri_opener.GET(target_url, cache=False, grep=False, debugging_id=debugging_id) except BaseFrameworkException as e: om.out.debug('Exception while verifying if the file that was uploaded' 'using author.dll was there: %s' % e) else: # The file we uploaded has the reversed filename as body if rand_file[::-1] not in res.get_body(): return desc = ('An insecure configuration in the frontpage extensions' ' allows unauthenticated users to upload files to the' ' remote web server.') response_ids = [upload_id, res.id] if upload_id is not None else [res.id] v = Vuln('Insecure Frontpage extensions configuration', desc, severity.HIGH, response_ids, self.get_name()) v.set_url(target_url) v.set_method('POST') om.out.vulnerability(v.get_desc(), severity=v.get_severity()) self.kb_append(self, 'frontpage', v)
def _PUT(self, domain_path): """ Tests PUT method. """ # upload url = domain_path.url_join(rand_alpha(5)) rnd_content = rand_alnum(6) headers = Headers([('content-type', 'text/plain')]) put_response = self._uri_opener.PUT(url, data=rnd_content, headers=headers) # check if uploaded res = self._uri_opener.GET(url, cache=True) if res.get_body() == rnd_content: msg = ('File upload with HTTP PUT method was found at resource:' ' "%s". A test file was uploaded to: "%s".') msg = msg % (domain_path, res.get_url()) v = Vuln('Publicly writable directory', msg, severity.HIGH, [put_response.id, res.id], self.get_name()) v.set_url(url) v.set_method('PUT') self.kb_append(self, 'dav', v) # Report some common errors elif put_response.get_code() == 500: msg = ('DAV seems to be incorrectly configured. The web server' ' answered with a 500 error code. In most cases, this means' ' that the DAV extension failed in some way. This error was' ' found at: "%s".' % put_response.get_url()) i = Info('DAV incorrect configuration', msg, res.id, self.get_name()) i.set_url(url) i.set_method('PUT') self.kb_append(self, 'dav', i) # Report some common errors elif put_response.get_code() == 403: # handle false positive when PUT method is not supported # https://github.com/andresriancho/w3af/pull/2724/files if 'supported' in put_response.get_body().lower(): return msg = ('DAV seems to be correctly configured and allowing you to' ' use the PUT method but the directory does not have the' ' right permissions that would allow the web server to' ' write to it. This error was found at: "%s".') msg = msg % put_response.get_url() i = Info('DAV incorrect configuration', msg, [put_response.id, res.id], self.get_name()) i.set_url(url) i.set_method('PUT') self.kb_append(self, 'dav', i)
# The file we uploaded has the reversed filename as body if rand_file[::-1] not in res.get_body(): return desc = ('An insecure configuration in the frontpage extensions' ' allows unauthenticated users to upload files to the' ' remote web server.') response_ids = [upload_id, res.id ] if upload_id is not None else [res.id] v = Vuln('Insecure Frontpage extensions configuration', desc, severity.HIGH, response_ids, self.get_name()) v.set_url(target_url) v.set_method('POST') om.out.vulnerability(v.get_desc(), severity=v.get_severity()) self.kb_append(self, 'frontpage', v) def get_plugin_deps(self): """ :return: A list with the names of the plugins that should be run before the current one. """ return ['infrastructure.frontpage_version'] def get_long_desc(self): """ :return: A DETAILED description of the plugin functions and features. """
except BaseFrameworkException, e: msg = 'Exception while verifying if the file that was uploaded'\ 'using author.dll was there: %s' % e om.out.debug(msg) else: # The file we uploaded has the reversed filename as body if res.get_body() == rand_file[::-1] and not is_404(res): desc = 'An insecure configuration in the frontpage extensions'\ ' allows unauthenticated users to upload files to the'\ ' remote web server.' v = Vuln('Insecure Frontpage extensions configuration', desc, severity.HIGH, [upload_id, res.id], self.get_name()) v.set_url(target_url) v.set_method('POST') om.out.vulnerability(v.get_desc(), severity=v.get_severity()) self.kb_append(self, 'frontpage', v) else: msg = 'The file that was uploaded using the POST method is'\ ' not present on the remote web server at "%s".' om.out.debug(msg % target_url) def get_plugin_deps(self): """ :return: A list with the names of the plugins that should be run before the current one. """ return ['infrastructure.frontpage_version']