def audit(self, freq ): ''' Tests an URL for xsrf vulnerabilities. @param freq: A fuzzableRequest ''' om.out.debug( 'xsrf plugin is testing: ' + freq.getURL() ) # Vulnerable by definition if freq.getMethod() == 'GET' and freq.getURI().hasQueryString(): # Now check if we already added this target URL to the list already_added = [ v.getURL() for v in self._vuln_simple ] if freq.getURL() not in already_added: # Vulnerable and not in list, add: v = vuln.vuln() v.setPluginName(self.getName()) v.setURL( freq.getURL() ) v.setDc( freq.getDc() ) v.setName( 'Cross site request forgery vulnerability' ) v.setSeverity(severity.LOW) v.setMethod( freq.getMethod() ) desc = 'The URL: ' + freq.getURL() + ' is vulnerable to cross-' desc += 'site request forgery.' v.setDesc( desc ) self._vuln_simple.append( v ) # This is a POST request that can be sent using a GET and querystring # Vulnerable by definition elif freq.getMethod() =='POST' and len ( freq.getDc() ) and \ isExchangable( self._uri_opener, freq ): # Now check if we already added this target URL to the list already_added = [ v.getURL() for v in self._vuln_complex ] if freq.getURL() not in already_added: # Vulnerable and not in list, add: v = vuln.vuln() v.setPluginName(self.getName()) v.setURL( freq.getURL() ) v.setSeverity(severity.LOW) v.setDc( freq.getDc() ) v.setName( 'Cross site request forgery vulnerability' ) v.setMethod( freq.getMethod() ) msg = 'The URL: ' + freq.getURL() + ' is vulnerable to cross-' msg += 'site request forgery. It allows the attacker to exchange' msg += ' the method from POST to GET when sendin data to the' msg += ' server.' v.setDesc( msg ) self._vuln_complex.append( v )
def _analyze_result(self, mutant, response): ''' Analyze results of the _send_mutant method. ''' with self._plugin_lock: if self._has_no_bug(mutant): sql_error_list = self._findsql_error(response) orig_resp_body = mutant.getOriginalResponseBody() for sql_regex, sql_error_string, dbms_type in sql_error_list: if not sql_regex.search(orig_resp_body): # Create the vuln, v = vuln.vuln(mutant) v.setPluginName(self.getName()) v.setId(response.id) v.setName('SQL injection vulnerability') v.setSeverity(severity.HIGH) v.addToHighlight(sql_error_string) v['error'] = sql_error_string v['db'] = dbms_type v.setDesc('SQL injection in a %s was found at: %s' % (v['db'], mutant.foundAt())) kb.kb.append(self, 'sqli', v) break
def _analyzeResult(self, mutant, mutant_response): ''' Analyze results of the _sendMutant method. In this case, check if the file was uploaded to any of the known directories, or one of the "default" ones like "upload" or "files". ''' # Generate a list of directories where I can search for the uploaded file domain_path_list = [urlParser.getDomainPath(i) for i in \ kb.kb.getData('urls' , 'urlList')] domain_path_list = set(domain_path_list) # Try to find the file! for url in domain_path_list: for path in self._generate_paths(url, mutant.uploaded_file_name): get_response = self._urlOpener.GET(path, useCache=False) if not is_404(get_response): # This is necesary, if I dont do this, the session saver will break cause # REAL file objects can't be picked mutant.setModValue('<file_object>') v = vuln.vuln(mutant) v.setPluginName(self.getName()) v.setId([mutant_response.id, get_response.id]) v.setSeverity(severity.HIGH) v.setName('Insecure file upload') v['fileDest'] = get_response.getURL() v['fileVars'] = mutant.getFileVariables() msg = 'A file upload to a directory inside the webroot was found at: ' msg += mutant.foundAt() v.setDesc(msg) kb.kb.append(self, 'fileUpload', v) return
def _analyze_result( self, mutant, response ): ''' Analyze results of the _send_mutant method. ''' with self._plugin_lock: # # I will only report the vulnerability once. # if self._has_no_bug(mutant): for error in self.ERROR_STRINGS: # Check if the error string is in the response if error in response.body and \ error not in mutant.getOriginalResponseBody(): # vuln, vuln! v = vuln.vuln( mutant ) v.setPluginName(self.getName()) v.setId( response.id ) v.setSeverity(severity.MEDIUM) v.setName( 'Format string vulnerability' ) msg = 'A possible (detection is really hard...) format' msg += ' string vulnerability was found at: ' msg += mutant.foundAt() v.setDesc( msg ) v.addToHighlight( error ) kb.kb.append( self, 'formatString', v )
def is_injectable( self, mutant ): ''' Check if this mutant is delay injectable or not. @mutant: The mutant object that I have to inject to @return: A vulnerability object or None if nothing is found ''' for delay_obj in self._get_delays(): ed = exact_delay(mutant, delay_obj, self._uri_opener) success, responses = ed.delay_is_controlled() if success: # Now I can be sure that I found a vuln, we control the response # time with the delay v = vuln.vuln( mutant ) v.setName( 'Blind SQL injection vulnerability' ) v.setSeverity(severity.HIGH) desc = 'Blind SQL injection using time delays was found at: %s' desc = desc % mutant.foundAt() v.setDesc( desc ) v.setDc( mutant.getDc() ) v.setId( [r.id for r in responses ] ) v.setURI( r.getURI() ) om.out.debug( v.getDesc() ) return v return None
def write_vuln_to_kb(vulnty, url, funcs): vulndata = php_sca.KB_DATA[vulnty] for f in funcs: v = vuln.vuln() v.setSeverity(vulndata['severity']) v.setName(vulndata['name']) v.setURL(url) v.setURI(url) v.setVar(f.vulnsources[0]) v.setDesc(vulndata['name']) args = list(vulndata['kb_key']) + [v] # TODO: Extract the method from the PHP code # $_GET == GET # $_POST == POST # $_REQUEST == GET v.setMethod('GET') # TODO: Extract all the other variables that are # present in the PHP file using the SCA v.setDc(dataContainer()) # ## TODO: This needs to be checked! OS Commanding specific ### parameters v['os'] = 'unix' v['separator'] = '' ### ## # kb.kb.append(*args)
def _analyzeResult( self, mutant, response ): ''' Analyze results of the _sendMutant method. ''' # # Only one thread at the time can enter here. This is because I want to report each # vulnerability only once, and by only adding the "if self._hasNoBug" statement, that # could not be done. # with self._plugin_lock: # # I will only report the vulnerability once. # if self._hasNoBug( 'sqli' , 'sqli' , mutant.getURL() , mutant.getVar() ): sql_error_list = self._findsql_error( response ) for sql_regex, sql_error_string, dbms_type in sql_error_list: if not sql_regex.search( mutant.getOriginalResponseBody() ): # Create the vuln, v = vuln.vuln( mutant ) v.setPluginName(self.getName()) v.setId( response.id ) v.setName( 'SQL injection vulnerability' ) v.setSeverity(severity.HIGH) v.addToHighlight( sql_error_string ) v['error'] = sql_error_string v['db'] = dbms_type v.setDesc( 'SQL injection in a '+ v['db'] +' was found at: ' + mutant.foundAt() ) kb.kb.append( self, 'sqli', v ) break
def _checkResponse(self, response, file_name): """ Analyze XML files. """ om.out.debug("Checking XML response in ria_enumerator.") try: dom = xml.dom.minidom.parseString(response.getBody()) 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.getBody() or "cross-domain-policy" in response.getBody() or "cross-domain-access" in response.getBody() ): i = info.info() i.setPluginName(self.getName()) i.setName("Invalid " + file_name) i.setURL(response.getURL()) i.setMethod("GET") msg = 'The "' + file_name + '" file at: "' + response.getURL() msg += '" is not a valid XML.' i.setDesc(msg) i.setId(response.id) kb.kb.append(self, "info", i) om.out.information(i.getDesc()) 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 == "*": v = vuln.vuln() v.setPluginName(self.getName()) v.setURL(response.getURL()) v.setMethod("GET") v.setName('Insecure "' + file_name + '" settings') v.setSeverity(severity.LOW) msg = 'The "' + file_name + '" file at "' + response.getURL() + '" allows' msg += " flash/silverlight access from any site." v.setDesc(msg) v.setId(response.id) kb.kb.append(self, "vuln", v) om.out.vulnerability(v.getDesc(), severity=v.getSeverity()) else: i = info.info() i.setPluginName(self.getName()) i.setName("Crossdomain allow ACL") i.setURL(response.getURL()) i.setMethod("GET") i.setDesc(file_name + '" file allows access from: "' + url + '".') i.setId(response.id) kb.kb.append(self, "info", i) om.out.information(i.getDesc())
def _analyzeResult( self, mutant, response ): ''' Analyze results of the _sendMutant method. ''' # # Only one thread at the time can enter here. This is because I want to report each # vulnerability only once, and by only adding the "if self._hasNoBug" statement, that # could not be done. # with self._plugin_lock: # # I will only report the vulnerability once. # if self._hasNoBug( 'xpath' , 'xpath' , mutant.getURL() , mutant.getVar() ): xpath_error_list = self._find_xpath_error( response ) for xpath_error_re, xpath_error in xpath_error_list: if not xpath_error_re.search( mutant.getOriginalResponseBody() ): v = vuln.vuln( mutant ) v.setPluginName(self.getName()) v.setName( 'XPATH injection vulnerability' ) v.setSeverity(severity.MEDIUM) v.setDesc( 'XPATH injection was found at: ' + mutant.foundAt() ) v.setId( response.id ) v.addToHighlight( xpath_error ) kb.kb.append( self, 'xpath', v )
def _with_time_delay(self, freq): ''' Tests an URL for OS Commanding vulnerabilities using time delays. @param freq: A fuzzableRequest ''' fake_mutants = createMutants(freq, ['',]) for mutant in fake_mutants: if self._has_bug(mutant): continue for delay_obj in self._get_wait_commands(): ed = exact_delay(mutant, delay_obj, self._uri_opener) success, responses = ed.delay_is_controlled() if success: v = vuln.vuln( mutant ) v.setPluginName(self.getName()) v.setName( 'OS commanding vulnerability' ) v.setSeverity(severity.HIGH) v['os'] = delay_obj.get_OS() v['separator'] = delay_obj.get_separator() v.setDesc( 'OS Commanding was found at: ' + mutant.foundAt() ) v.setDc( mutant.getDc() ) v.setId( [r.id for r in responses] ) v.setURI( r.getURI() ) kb.kb.append( self, 'osCommanding', v ) break
def discover(self, fuzzableRequest): """ Checks if JBoss Interesting Directories exist in the target server. Also verifies some vulnerabilities. """ base_url = fuzzableRequest.getURL().baseUrl() for vuln_db_instance in findJBoss._jboss_vulns: vuln_url = base_url.urlJoin(vuln_db_instance["url"]) response = self._uri_opener.GET(vuln_url) if response.getCode() == 200: if vuln_db_instance["type"] == "info": i = info.info() i.setPluginName(self.getName()) i.setName(vuln_db_instance["name"]) i.setURL(vuln_url) i.setId(response.id) i.setDesc(vuln_db_instance["desc"]) kb.kb.append(self, vuln_db_instance["name"], i) else: v = vuln.vuln() v.setPluginName(self.getName()) v.setName(vuln_db_instance["name"]) v.setURL(vuln_url) v.setId(response.id) v.setDesc(vuln_db_instance["desc"]) kb.kb.append(self, vuln_db_instance["name"], v) fuzzable_requests = self._createFuzzableRequests(response) self._fuzzable_requests_to_return.extend(fuzzable_requests) return self._fuzzable_requests_to_return
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" res = self._urlOpener.PROPFIND(domain_path, data=content, headers={"Depth": "1"}) # Remember that httpResponse objects have a faster "__in__" than # the one in strings; so string in response.getBody() is slower than # string in response if "D:href" in res and res.getCode() in xrange(200, 300): v = vuln.vuln() v.setPluginName(self.getName()) v.setURL(res.getURL()) v.setId(res.id) v.setSeverity(severity.MEDIUM) v.setName("Insecure DAV configuration") v.setMethod("PROPFIND") msg = 'Directory listing with HTTP PROPFIND method was found at directory: "' msg += domain_path + '"' v.setDesc(msg) kb.kb.append(self, "dav", v)
def audit(self, freq ): ''' Check if the protocol specified in freq is https and fetch the same URL using http. ie: - input: https://a/ - check: http://a/ @param freq: A fuzzableRequest ''' if self._ignore_next_calls: return else: # Define some variables secure = freq.getURL() insecure = secure.setProtocol('http') if self._first_run: try: self._uri_opener.GET( insecure ) except: # The request failed because the HTTP port is closed or something like that # we shouldn't test any other fuzzable requests. self._ignore_next_calls = True msg = 'HTTP port seems to be closed. Not testing any other URLs in unSSL.' om.out.debug( msg ) return else: # Only perform the initial check once. self._first_run = False # It seems that we can request the insecure HTTP URL # (checked with the GET request) if 'HTTPS' == freq.getURL().getProtocol().upper(): # We are going to perform requests that (in normal cases) # are going to fail, so we set the ignore errors flag to True self._uri_opener.ignore_errors( True ) https_response = self._uri_opener.send_mutant(freq) freq.setURL( insecure ) http_response = self._uri_opener.send_mutant(freq) if http_response.getCode() == https_response.getCode(): if relative_distance_boolean( http_response.getBody(), https_response.getBody(), 0.97 ): v = vuln.vuln( freq ) v.setPluginName(self.getName()) v.setName( 'Secure content over insecure channel' ) v.setSeverity(severity.MEDIUM) msg = 'Secure content can be accesed using the insecure protocol HTTP.' msg += ' The vulnerable URLs are: "' + secure + '" - "' + insecure + '" .' v.setDesc( msg ) v.setId( [http_response.id, https_response.id] ) kb.kb.append( self, 'unSSL', v ) om.out.vulnerability( v.getDesc(), severity=v.getSeverity() ) # Disable error ignoring self._uri_opener.ignore_errors( False )
def _analyzeResult( self, mutant, response ): ''' Analyze results of the _sendMutant method. ''' # # Only one thread at the time can enter here. This is because I want to report each # vulnerability only once, and by only adding the "if self._hasNoBug" statement, that # could not be done. # with self._plugin_lock: # # I will only report the vulnerability once. # if self._hasNoBug( 'preg_replace' , 'preg_replace' , mutant.getURL() , mutant.getVar() ): preg_error_list = self._find_preg_error( response ) for preg_error_re, preg_error_string in preg_error_list: if not preg_error_re.search( mutant.getOriginalResponseBody() ): v = vuln.vuln( mutant ) v.setPluginName(self.getName()) v.setId( response.id ) v.setSeverity(severity.HIGH) v.setName( 'Unsafe usage of preg_replace' ) v.setDesc( 'Unsafe usage of preg_replace was found at: ' + mutant.foundAt() ) v.addToHighlight( preg_error_string ) kb.kb.append( self, 'preg_replace', v )
def grep(self, request, response): ''' Plugin entry point. @parameter request: The HTTP request object. @parameter response: The HTTP response object @return: None, all results are saved in the kb. ''' uri = response.getURI() if response.is_text_or_html() and uri not in self._already_inspected: # Don't repeat URLs self._already_inspected.add(uri) for regex in self._regex_list: for m in regex.findall(response.getBody()): v = vuln.vuln() v.setPluginName(self.getName()) v.setURI(uri) v.setId(response.id) msg = 'The URL: "' + uri + '" contains a SVN versioning ' msg += 'signature with the username: "******" .' v.setDesc(msg) v['user'] = m[0] v.setSeverity(severity.LOW) v.setName('SVN user disclosure vulnerability') v.addToHighlight(m[0]) kb.kb.append(self, 'users', v)
def _classic_worker(self, gh, search): # Init some variables google_se = google(self._urlOpener) google_list = google_se.getNResults( search, 9 ) for result in google_list: # I found a vuln in the site! response = self._urlOpener.GET(result.URL, useCache=True ) if not is_404( response ): v = vuln.vuln() v.setPluginName(self.getName()) v.setURL( response.getURL() ) v.setMethod( 'GET' ) v.setName( 'Google hack database vulnerability' ) v.setSeverity(severity.MEDIUM) msg = 'ghdb plugin found a vulnerability at URL: ' + result.URL msg += ' . Vulnerability description: ' + gh.desc v.setDesc( msg ) v.setId( response.id ) kb.kb.append( self, 'vuln', v ) om.out.vulnerability( v.getDesc(), severity=severity.MEDIUM ) # Create the fuzzable requests self._fuzzableRequests.extend( self._createFuzzableRequests( response ) )
def _check_if_exists(self, web_shell_url): ''' Check if the file exists. @parameter web_shell_url: The URL to check ''' try: response = self._uri_opener.GET(web_shell_url, cache=True) except w3afException: om.out.debug('Failed to GET webshell:' + web_shell_url) else: if self._is_possible_backdoor(response): v = vuln.vuln() v.setPluginName(self.getName()) v.setId(response.id) v.setName('Possible web backdoor') v.setSeverity(severity.HIGH) v.setURL(response.getURL()) msg = 'A web backdoor was found at: "%s"; this could ' \ 'indicate that the server was hacked.' % v.getURL() v.setDesc(msg) kb.kb.append(self, 'backdoors', v) om.out.vulnerability(v.getDesc(), severity=v.getSeverity()) fuzzable_requests = self._createFuzzableRequests(response) self._fuzzable_requests_to_return += fuzzable_requests
def _find_phishing_vector(self, mutant, response): """ Find the phishing vectors! """ dom = response.getDOM() res = [] if response.is_text_or_html() and dom is not None: elem_list = self._tag_xpath(dom) for element in elem_list: if "src" not in element.attrib: return [] src_attr = element.attrib["src"] for url in self._test_urls: if src_attr.startswith(url): # Vuln vuln! v = vuln.vuln(mutant) v.setPluginName(self.getName()) v.setId(response.id) v.setSeverity(severity.LOW) v.setName("Phishing vector") v.setDesc("A phishing vector was found at: " + mutant.foundAt()) v.addToHighlight(src_attr) res.append(v) return res
def grep(self, request, response): ''' Plugin entry point, search for directory indexing. @parameter request: The HTTP request object. @parameter response: The HTTP response object @return: None ''' if urlParser.getDomainPath(response.getURL()) in self._already_visited: # Already worked for this URL, no reason to work twice return else: # Save it, self._already_visited.add( urlParser.getDomainPath(response.getURL()) ) # Work, if response.is_text_or_html(): html_string = response.getBody() for indexing_regex in self._compiled_regex_list: if indexing_regex.search( html_string ): v = vuln.vuln() v.setPluginName(self.getName()) v.setURL( response.getURL() ) msg = 'The URL: "' + response.getURL() + '" has a directory ' msg += 'indexing vulnerability.' v.setDesc( msg ) v.setId( response.id ) v.setSeverity(severity.LOW) path = urlParser.getPath( response.getURL() ) v.setName( 'Directory indexing - ' + path ) kb.kb.append( self , 'directory' , v ) break
def _analyzeResult( self, mutant, response ): ''' Analyze results of the _sendMutant method. ''' # # Only one thread at the time can enter here. This is because I want to report each # vulnerability only once, and by only adding the "if self._hasNoBug" statement, that # could not be done. # with self._plugin_lock: # # I will only report the vulnerability once. # if self._hasNoBug( 'formatString' , 'formatString' , mutant.getURL() , mutant.getVar() ): for error in self._get_errors(): # Check if the error string is in the response if error in response: # And not in the originally requested (non fuzzed) request if not error not in mutant.getOriginalResponseBody(): # vuln, vuln! v = vuln.vuln( mutant ) v.setPluginName(self.getName()) v.setId( response.id ) v.setSeverity(severity.MEDIUM) v.setName( 'Format string vulnerability' ) msg = 'A possible (detection is really hard...) format string was found at: ' msg += mutant.foundAt() v.setDesc( msg ) v.addToHighlight( error ) kb.kb.append( self, 'formatString', v )
def end(self): ''' This method is called when the plugin wont be used anymore. The real job of this plugin is done here, where I will try to see if one of the error500 responses were not identified as a vuln by some of my audit plugins ''' all_vulns = kb.kb.getAllVulns() all_vulns_tuples = [ (v.getURI(), v.getDc()) for v in all_vulns ] for request, error_500_response in self._error_500_responses: if ( error_500_response.getURI() , request.getDc() ) not in all_vulns_tuples: # Found a err 500 that wasnt identified !!! v = vuln.vuln() v.setPluginName(self.getName()) v.setURI( error_500_response.getURI() ) v.setURL( error_500_response.getURL() ) v.setId( error_500_response.id ) v.setSeverity(severity.MEDIUM) v.setName( 'Unhandled error in web application' ) msg = 'An unidentified web application error (HTTP response code 500)' msg += ' was found at: "' + v.getURL()+'".' msg += ' Enable all plugins and try again, if the vulnerability still is not' msg += ' identified, please verify manually and report it to the w3af developers.' v.setDesc( msg ) kb.kb.append( self, 'error500', v ) self.printUniq( kb.kb.getData( 'error500', 'error500' ), 'VAR' )
def grep(self, request, response): ''' Plugin entry point, search for the DOM XSS vulns. @parameter request: The HTTP request object. @parameter response: The HTTP response object @return: None ''' res = [] if not response.is_text_or_html(): return if self._useSimpleGrep: res.extend(self._simpleGrep(response)) if self._useSmartGrep: res.extend(self._smartGrep(response)) for vulnCode in res: v = vuln.vuln() v.setPluginName(self.getName()) v.addToHighlight(vulnCode) v.setURL(response.getURL()) v.setId(response.id) v.setSeverity(severity.LOW) v.setName('DOM Cross site scripting (Risky JavaScript Code)') msg = 'The URL: "' + v.getURL() + '" has a DOM XSS (Risky JavaScript Code) ' msg += 'bug using: "'+ vulnCode + '".' v.setDesc(msg) kb.kb.append(self, 'domXss', v)
def _analyze_echo( self, mutant, response ): ''' Analyze results of the _sendMutant method that was sent in the _fuzz_with_echo method. ''' # # Only one thread at the time can enter here. This is because I want to report each # vulnerability only once, and by only adding the "if self._hasNoBug" statement, that # could not be done. # with self._plugin_lock: # # I will only report the vulnerability once. # if self._hasNoBug( 'eval' , 'eval' , mutant.getURL() , mutant.getVar() ): eval_error_list = self._find_eval_result( response ) for eval_error in eval_error_list: if not re.search( eval_error, mutant.getOriginalResponseBody(), re.IGNORECASE ): v = vuln.vuln( mutant ) v.setPluginName(self.getName()) v.setId( response.id ) v.setSeverity(severity.HIGH) v.setName( 'eval() input injection vulnerability' ) v.setDesc( 'eval() input injection was found at: ' + mutant.foundAt() ) kb.kb.append( self, 'eval', v )
def _check_if_exists(self, domain_path, git_url, regular_expression): ''' Check if the file exists. @parameter git_file_url: The URL to check ''' try: response = self._urlOpener.GET( git_url, useCache=True ) except w3afException: om.out.debug('Failed to GET git file:' + git_url) else: if not is_404(response): # Check pattern f = StringIO.StringIO(response.getBody()) for line in f: if regular_expression.match(line): v = vuln.vuln() v.setPluginName(self.getName()) v.setId( response.id ) v.setName( 'Possible Git repository found' ) v.setSeverity(severity.LOW) v.setURL( response.getURL() ) msg = 'A Git repository file was found at: "' + v.getURL() + '" ; this could' msg += ' indicate that a Git repo is accessible. You might be able to download' msg += ' the Web application source code by running' msg += ' "git clone ' + domain_path + '"' v.setDesc( msg ) kb.kb.append( self, 'GIT', v ) om.out.vulnerability( v.getDesc(), severity=v.getSeverity() ) fuzzable_requests = self._createFuzzableRequests( response ) self._fuzzable_requests_to_return.extend( fuzzable_requests )
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._urlOpener.SEARCH(domain_path, data=content) content_matches = "<a:response>" in res or "<a:status>" in res or 'xmlns:a="DAV:"' in res if content_matches and res.getCode() in xrange(200, 300): v = vuln.vuln() v.setPluginName(self.getName()) v.setURL(res.getURL()) v.setId(res.id) v.setSeverity(severity.MEDIUM) v.setName("Insecure DAV configuration") v.setMethod("SEARCH") msg = 'Directory listing with HTTP SEARCH method was found at directory: "' msg += domain_path + '"' v.setDesc(msg) kb.kb.append(self, "dav", v)
def _check_methods( self, url ): ''' Perform some requests in order to check if we are able to retrieve some data with methods that may be wrongly enabled. ''' allowed_methods = [] for method in ['GET', 'POST', 'ABCD', 'HEAD']: method_functor = getattr( self._urlOpener, method ) try: response = apply( method_functor, (url,) , {} ) code = response.getCode() except: pass else: if code not in self._bad_methods: allowed_methods.append( method ) if len(allowed_methods)>0: v = vuln.vuln() v.setPluginName(self.getName()) v.setURL( url ) v.setName( 'Misconfigured access control' ) v.setSeverity(severity.MEDIUM) msg = 'The resource: "'+ url + '" requires authentication but the access' msg += ' is misconfigured and can be bypassed using these methods: ' msg += ', '.join(allowed_methods) + '.' v.setDesc( msg ) v['methods'] = allowed_methods kb.kb.append( self , 'auth' , v ) om.out.vulnerability( v.getDesc(), severity=v.getSeverity() )
def _analyze_echo( self, mutant, response ): ''' Analyze results of the _send_mutant method that was sent in the _with_echo method. ''' with self._plugin_lock: # # I will only report the vulnerability once. # if self._has_no_bug(mutant): for file_pattern_match in self._multi_in.query( response.getBody() ): if file_pattern_match not in mutant.getOriginalResponseBody(): # Search for the correct command and separator sentOs, sentSeparator = self._get_os_separator(mutant) # Create the vuln obj v = vuln.vuln( mutant ) v.setPluginName(self.getName()) v.setName( 'OS commanding vulnerability' ) v.setSeverity(severity.HIGH) v['os'] = sentOs v['separator'] = sentSeparator v.setDesc( 'OS Commanding was found at: ' + mutant.foundAt() ) v.setDc( mutant.getDc() ) v.setId( response.id ) v.setURI( response.getURI() ) v.addToHighlight( file_pattern_match ) kb.kb.append( self, 'osCommanding', v ) break
def _secure_over_http(self, request, response, cookieObj): """ Checks if a cookie marked as secure is sent over http. Reference: http://en.wikipedia.org/wiki/HTTP_cookie @parameter request: The http request object @parameter response: The http response object @parameter cookieObj: The cookie object to analyze @return: None """ ### BUGBUG: There is a bug in python cookie.py which makes this ### code useless! The secure parameter is never parsed in the cookieObj ### http://bugs.python.org/issue1028088 ### https://sourceforge.net/tracker2/?func=detail&aid=2139517&group_id=170274&atid=853655 if "secure" in cookieObj and response.getURL().startswith("http://"): v = vuln.vuln() v.setPluginName(self.getName()) v.setURL(response.getURL()) v.setId(response.getId()) self._setCookieToRep(v, cookieObj) v.setSeverity(severity.HIGH) v.setName("Secure cookies over insecure channel") msg = "A cookie marked as secure was sent over an insecure channel" msg += ' when requesting the URL: "' + response.getURL() + '"' v.setDesc(msg) kb.kb.append(self, "cookies", v)
def _fuzz_with_time_delay(self, freq): """ Tests an URL for eval() usage vulnerabilities using time delays. @param freq: A fuzzableRequest """ fake_mutants = createMutants(freq, [""]) for mutant in fake_mutants: if self._has_bug(mutant): continue for delay_obj in self.WAIT_OBJ: ed = exact_delay(mutant, delay_obj, self._uri_opener) success, responses = ed.delay_is_controlled() if success: v = vuln.vuln(mutant) v.setPluginName(self.getName()) v.setId([r.id for r in responses]) v.setSeverity(severity.HIGH) v.setName("eval() input injection vulnerability") v.setDesc("eval() input injection was found at: " + mutant.foundAt()) kb.kb.append(self, "eval", v) break
def _analyze_wait(self, mutant, response): """ Analyze results of the _sendMutant method that was sent in the _with_time_delay method. """ # # Only one thread at the time can enter here. This is because I want to report each # vulnerability only once, and by only adding the "if self._hasNoBug" statement, that # could not be done. # with self._plugin_lock: # # I will only report the vulnerability once. # if self._hasNoBug("osCommanding", "osCommanding", mutant.getURL(), mutant.getVar()): if response.getWaitTime() > ( self._original_wait_time + self._wait_time - 2 ) and response.getWaitTime() < (self._original_wait_time + self._wait_time + 2): sentOs, sentSeparator = self._get_os_separator(mutant) # This could be because of an osCommanding vuln, or because of an error that # generates a delay in the response; so I'll resend changing the time and see # what happens original_wait_param = mutant.getModValue() more_wait_param = original_wait_param.replace(str(self._wait_time), str(self._second_wait_time)) mutant.setModValue(more_wait_param) response = self._sendMutant(mutant, analyze=False) if response.getWaitTime() > ( self._original_wait_time + self._second_wait_time - 3 ) and response.getWaitTime() < (self._original_wait_time + self._second_wait_time + 3): # Now I can be sure that I found a vuln, I control the time of the response. v = vuln.vuln(mutant) v.setPluginName(self.getName()) v.setName("OS commanding vulnerability") v.setSeverity(severity.HIGH) v["os"] = sentOs v["separator"] = sentSeparator v.setDesc("OS Commanding was found at: " + mutant.foundAt()) v.setDc(mutant.getDc()) v.setId(response.id) v.setURI(response.getURI()) kb.kb.append(self, "osCommanding", v) else: # The first delay existed... I must report something... i = info.info() i.setPluginName(self.getName()) i.setName("Possible OS commanding vulnerability") i.setId(response.id) i.setDc(mutant.getDc()) i.setMethod(mutant.getMethod()) i["os"] = sentOs i["separator"] = sentSeparator msg = "A possible OS Commanding was found at: " + mutant.foundAt() msg += "Please review manually." i.setDesc(msg) kb.kb.append(self, "osCommanding", i)