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 not response.is_text_or_html(): return # https://github.com/andresriancho/w3af/issues/5379 # Avoid some (rather common) false positives that appear in JS files if 'javascript' in response.content_type: return match, lang = is_source_file(response.get_body()) if not match: return # Only report 404 findings once if is_404(response) and self._report_404_match: self._report_404_match = False desc = u'The URL: "%s" has a %s code disclosure' \ u' vulnerability in the customized 404 script.' name = u'Code disclosure vulnerability in 404 page' else: desc = u'The URL: "%s" has a %s code disclosure vulnerability.' name = u'Code disclosure vulnerability' # Report the vulnerability desc %= (response.get_url(), lang) v = Vuln(name, desc, severity.INFORMATION, response.id, self.get_name()) v.set_url(response.get_url()) v.add_to_highlight(match.group()) om.out.vulnerability(v.get_desc(), severity=severity.INFORMATION) 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 not response.is_text_or_html(): return 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') else: self._first_404 = False desc = 'The URL: "%s" has a %s code disclosure'\ ' vulnerability in the customized 404 script.' desc = desc % (response.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 not response.is_text_or_html(): return # https://github.com/andresriancho/w3af/issues/5379 # Avoid some (rather common) false positives that appear in JS files if 'javascript' in response.content_type: return match, lang = is_source_file(response.get_body()) if not match: return # Only report 404 findings once if is_404(response) and self._report_404_match: self._report_404_match = False desc = u'The URL: "%s" has a %s code disclosure' \ u' vulnerability in the customized 404 script.' name = u'Code disclosure vulnerability in 404 page' else: desc = u'The URL: "%s" has a %s code disclosure vulnerability.' name = u'Code disclosure vulnerability' # Report the vulnerability desc %= (response.get_url(), lang) v = Vuln(name, 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_token_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_code_case04(self): source = 'foo <?php ypacket ?> "bar' match, lang = is_source_file(source) self.assertNotEqual(match, None) self.assertEqual(lang, 'PHP')
def test_no_code_case03(self): source = 'foo <?php xpacket ?> "bar' match, lang = is_source_file(source) self.assertEqual(match, None) self.assertEqual(lang, None)
def test_php(self): source = 'foo <?php echo "a"; ?> bar' match, lang = is_source_file(source) self.assertNotEqual(match, None) self.assertEqual(lang, 'PHP')
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_token_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_case01(self): source = 'foo <? echo "bar' match, lang = is_source_file(source) self.assertEqual(match, None) self.assertEqual(lang, None)