def grep(self, request, response): ''' Plugin entry point, search for the code disclosures. Unit tests are available at plugins/grep/tests. :param request: The HTTP request object. :param response: The HTTP response object :return: None ''' if response.is_text_or_html() and \ response.get_url() not in self._already_added: match, lang = is_source_file(response.get_body()) if match: # Check also for 404 if not is_404(response): desc = 'The URL: "%s" has a %s code disclosure vulnerability.' desc = desc % (response.get_url(), lang) v = Vuln('Code disclosure vulnerability', desc, severity.LOW, response.id, self.get_name()) v.set_url(response.get_url()) v.add_to_highlight(match.group()) self.kb_append_uniq(self, 'code_disclosure', v, 'URL') self._already_added.add(response.get_url()) else: self._first_404 = False desc = 'The URL: "%s" has a %s code disclosure'\ ' vulnerability in the customized 404 script.' desc = desc % (v.get_url(), lang) v = Vuln('Code disclosure vulnerability in 404 page', desc, severity.LOW, response.id, self.get_name()) v.set_url(response.get_url()) v.add_to_highlight(match.group()) self.kb_append_uniq(self, 'code_disclosure', v, 'URL')
def grep(self, request, response): ''' Plugin entry point, search for the code disclosures. Unit tests are available at plugins/grep/tests. :param request: The HTTP request object. :param response: The HTTP response object :return: None ''' if response.is_text_or_html() and \ response.get_url() not in self._already_added: match, lang = is_source_file(response.get_body()) if match: # Check also for 404 if not is_404(response): desc = 'The URL: "%s" has a %s code disclosure vulnerability.' desc = desc % (response.get_url(), lang) v = Vuln('Code disclosure vulnerability', desc, severity.LOW, response.id, self.get_name()) v.set_url(response.get_url()) v.add_to_highlight(match.group()) self.kb_append_uniq(self, 'code_disclosure', v, 'URL') self._already_added.add(response.get_url()) else: self._first_404 = False desc = 'The URL: "%s" has a %s code disclosure'\ ' vulnerability in the customized 404 script.' desc = desc % (v.get_url(), lang) v = Vuln('Code disclosure vulnerability in 404 page', desc, severity.LOW, response.id, self.get_name()) v.set_url(response.get_url()) v.add_to_highlight(match.group()) self.kb_append_uniq(self, 'code_disclosure', v, 'URL')
def _analyze_result(self, mutant, response): ''' Analyze results of the _send_mutant method. Try to find the local file inclusions. ''' # I analyze the response searching for a specific PHP error string # that tells me that open_basedir is enabled, and our request triggered # the restriction. If open_basedir is in use, it makes no sense to keep # trying to read "/etc/passwd", that is why this variable is used to # determine which tests to send if it was possible to detect the usage # of this security feature. if not self._open_basedir: basedir_warning = 'open_basedir restriction in effect' if basedir_warning in response and \ basedir_warning not in mutant.get_original_response_body(): self._open_basedir = True # # I will only report the vulnerability once. # if self._has_bug(mutant): return # # Identify the vulnerability # file_content_list = self._find_file(response) for file_pattern_match in file_content_list: if file_pattern_match not in mutant.get_original_response_body(): desc = 'Local File Inclusion was found at: %s' desc = desc % mutant.found_at() v = Vuln.from_mutant('Local file inclusion vulnerability', desc, severity.MEDIUM, response.id, self.get_name(), mutant) v['file_pattern'] = file_pattern_match v.add_to_highlight(file_pattern_match) self.kb_append_uniq(self, 'lfi', v) return # # If the vulnerability could not be identified by matching strings that commonly # appear in "/etc/passwd", then I'll check one more thing... # (note that this is run if no vulns were identified) # # http://host.tld/show_user.php?id=show_user.php if mutant.get_mod_value() == mutant.get_url().get_file_name(): match, lang = is_source_file(response.get_body()) if match: # We were able to read the source code of the file that is # vulnerable to local file read desc = 'An arbitrary local file read vulnerability was'\ ' found at: %s' % mutant.found_at() v = Vuln.from_mutant('Local file inclusion vulnerability', desc, severity.MEDIUM, response.id, self.get_name(), mutant) # # Set which part of the source code to match # match_source_code = match.group(0) v['file_pattern'] = match_source_code self.kb_append_uniq(self, 'lfi', v) return # # Check for interesting errors (note that this is run if no vulns were # identified) # for regex in self.get_include_errors(): match = regex.search(response.get_body()) if match and not regex.search(mutant.get_original_response_body()): desc = 'A file read error was found at: %s' desc = desc % mutant.found_at() i = Info.from_mutant('File read error', desc, response.id, self.get_name(), mutant) self.kb_append_uniq(self, 'error', i)
def grep(self, request, response): ''' Plugin entry point, search for the code disclosures. Unit tests are available at plugins/grep/tests. @parameter request: The HTTP request object. @parameter response: The HTTP response object @return: None Init >>> import codeDisclosure >>> from core.data.url.httpResponse import httpResponse >>> from core.data.request.fuzzableRequest import fuzzableRequest >>> from core.controllers.misc.temp_dir import create_temp_dir >>> from core.data.parsers.urlParser import url_object >>> from core.controllers.coreHelpers.fingerprint_404 import fingerprint_404_singleton >>> from core.data.url.xUrllib import xUrllib >>> xurllib = xUrllib() >>> f = fingerprint_404_singleton( [False, False, False] ) >>> f.set_urlopener( xurllib ) >>> o = create_temp_dir() Simple test, empty string. >>> body = '' >>> url = url_object('http://www.w3af.com/') >>> headers = {'content-type': 'text/html'} >>> response = httpResponse(200, body , headers, url, url) >>> request = fuzzableRequest() >>> request.setURL(url) >>> request.setMethod('GET') >>> c = codeDisclosure.codeDisclosure() >>> c.grep(request, response) >>> len(kb.kb.getData('codeDisclosure', 'codeDisclosure')) 0 Disclose some PHP code, >>> kb.kb.cleanup() >>> body = 'header <? echo "a"; ?> footer' >>> url = url_object('http://www.w3af.com/') >>> headers = {'content-type': 'text/html'} >>> response = httpResponse(200, body , headers, url, url) >>> request = fuzzableRequest() >>> request.setURL(url) >>> request.setMethod('GET') >>> c = codeDisclosure.codeDisclosure() >>> c.grep(request, response) >>> len(kb.kb.getData('codeDisclosure', 'codeDisclosure')) 1 ''' if response.is_text_or_html() and response.getURL() not in self._already_added: match, lang = is_source_file(response.getBody()) if match: # Check also for 404 if not is_404( response ): v = vuln.vuln() v.setPluginName(self.getName()) v.setURL( response.getURL() ) v.setId( response.id ) v.setSeverity(severity.LOW) v.setName( lang + ' code disclosure vulnerability' ) v.addToHighlight(match.group()) msg = 'The URL: "' + v.getURL() + '" has a '+lang+' code disclosure vulnerability.' v.setDesc( msg ) kb.kb.append( self, 'codeDisclosure', v ) self._already_added.add( response.getURL() ) else: self._first_404 = False v = vuln.vuln() v.setPluginName(self.getName()) v.setURL( response.getURL() ) v.setId( response.id ) v.setSeverity(severity.LOW) v.addToHighlight(match.group()) v.setName( lang + ' code disclosure vulnerability in 404 page' ) msg = 'The URL: "' + v.getURL() + '" has a '+lang+' code disclosure vulnerability in' msg += ' the customized 404 script.' v.setDesc( msg ) kb.kb.append( self, 'codeDisclosure', v )
def _analyzeResult( self, mutant, response ): ''' Analyze results of the _sendMutant method. Try to find the local file inclusions. ''' # # 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 analyze the response searching for a specific PHP error string that tells me # that open_basedir is enabled, and our request triggered the restriction. If # open_basedir is in use, it makes no sense to keep trying to read "/etc/passwd", # that is why this variable is used to determine which tests to send if it was possible # to detect the usage of this security feature. # if not self._open_basedir: if 'open_basedir restriction in effect' in response\ and 'open_basedir restriction in effect' not in mutant.getOriginalResponseBody(): self._open_basedir = True # # I will only report the vulnerability once. # if self._hasNoBug( 'localFileInclude' , 'localFileInclude' , mutant.getURL() , mutant.getVar() ): # # Identify the vulnerability # file_content_list = self._find_file( response ) for file_pattern_regex, file_content in file_content_list: if not file_pattern_regex.search( mutant.getOriginalResponseBody() ): v = vuln.vuln( mutant ) v.setPluginName(self.getName()) v.setId( response.id ) v.setName( 'Local file inclusion vulnerability' ) v.setSeverity(severity.MEDIUM) v.setDesc( 'Local File Inclusion was found at: ' + mutant.foundAt() ) v['file_pattern'] = file_content v.addToHighlight( file_content ) kb.kb.append( self, 'localFileInclude', v ) return # # If the vulnerability could not be identified by matching strings that commonly # appear in "/etc/passwd", then I'll check one more thing... # (note that this is run if no vulns were identified) # # http://host.tld/show_user.php?id=show_user.php if mutant.getModValue() == urlParser.getFileName( mutant.getURL() ): match, lang = is_source_file( response.getBody() ) if match: # We were able to read the source code of the file that is vulnerable to # local file read v = vuln.vuln( mutant ) v.setPluginName(self.getName()) v.setId( response.id ) v.setName( 'Local file read vulnerability' ) v.setSeverity(severity.MEDIUM) msg = 'An arbitrary local file read vulnerability was found at: ' msg += mutant.foundAt() v.setDesc( msg ) # # Set which part of the source code to match # match_source_code = match.group(0) v['file_pattern'] = match_source_code kb.kb.append( self, 'localFileInclude', v ) return # # Check for interesting errors (note that this is run if no vulns were identified) # for regex in self.get_include_errors(): match = regex.search( response.getBody() ) if match and not \ regex.search( mutant.getOriginalResponseBody() ): i = info.info( mutant ) i.setPluginName(self.getName()) i.setId( response.id ) i.setName( 'File read error' ) i.setDesc( 'A file read error was found at: ' + mutant.foundAt() ) kb.kb.append( self, 'error', i )
def _analyze_result(self, mutant, response): ''' Analyze results of the _send_mutant method. Try to find the local file inclusions. ''' # I analyze the response searching for a specific PHP error string # that tells me that open_basedir is enabled, and our request triggered # the restriction. If open_basedir is in use, it makes no sense to keep # trying to read "/etc/passwd", that is why this variable is used to # determine which tests to send if it was possible to detect the usage # of this security feature. if not self._open_basedir: basedir_warning = 'open_basedir restriction in effect' if basedir_warning in response and \ basedir_warning not in mutant.get_original_response_body(): self._open_basedir = True # # I will only report the vulnerability once. # if self._has_bug(mutant): return # # Identify the vulnerability # file_content_list = self._find_file(response) for file_pattern_match in file_content_list: if file_pattern_match not in mutant.get_original_response_body(): desc = 'Local File Inclusion was found at: %s' desc = desc % mutant.found_at() v = Vuln.from_mutant('Local file inclusion vulnerability', desc, severity.MEDIUM, response.id, self.get_name(), mutant) v['file_pattern'] = file_pattern_match v.add_to_highlight(file_pattern_match) self.kb_append_uniq(self, 'lfi', v) return # # If the vulnerability could not be identified by matching strings that commonly # appear in "/etc/passwd", then I'll check one more thing... # (note that this is run if no vulns were identified) # # http://host.tld/show_user.php?id=show_user.php if mutant.get_mod_value() == mutant.get_url().get_file_name(): match, lang = is_source_file(response.get_body()) if match: # We were able to read the source code of the file that is # vulnerable to local file read desc = 'An arbitrary local file read vulnerability was'\ ' found at: %s' % mutant.found_at() v = Vuln.from_mutant('Local file inclusion vulnerability', desc, severity.MEDIUM, response.id, self.get_name(), mutant) # # Set which part of the source code to match # match_source_code = match.group(0) v['file_pattern'] = match_source_code self.kb_append_uniq(self, 'lfi', v) return # # Check for interesting errors (note that this is run if no vulns were # identified) # for regex in self.get_include_errors(): match = regex.search(response.get_body()) if match and not regex.search(mutant.get_original_response_body()): desc = 'A file read error was found at: %s' desc = desc % mutant.found_at() i = Info.from_mutant('File read error', desc, response.id, self.get_name(), mutant) self.kb_append_uniq(self, 'error', i)
def test_no_code_case04(self): source = 'foo <?ypacket ?> "bar' match, lang = is_source_file(source) self.assertNotEqual(match, None) self.assertEqual(lang, 'PHP')
def test_no_code_case02(self): source = 'foo <?xml ?> "bar' match, lang = is_source_file(source) self.assertEqual(match, None) self.assertEqual(lang, None)
def test_php(self): source = 'foo <? echo "a"; ?> bar' match, lang = is_source_file(source) self.assertNotEqual(match, None) self.assertEqual(lang, 'PHP')
def test_no_code_case04(self): source = 'foo <?ypacket ?> "bar' match, lang = is_source_file(source) self.assertNotEqual(match, None) self.assertEqual(lang, 'PHP')
def test_no_code_case02(self): source = 'foo <?xml ?> "bar' match, lang = is_source_file(source) self.assertEqual(match, None) self.assertEqual(lang, None)
def test_php(self): source = 'foo <? echo "a"; ?> bar' match, lang = is_source_file(source) self.assertNotEqual(match, None) self.assertEqual(lang, 'PHP')