def test_code_false_positive_java_02(self): source = self.create_response(''' public class Person{ } ''') match, lang = contains_source_code(source) self.assertEqual(match, None)
def test_code_false_positive_ruby_01(self): source = self.create_response('var f=_.template("<div class="alert' ' alert-error <% if (title) { %>' ' alert-block <% } %>', content_type='application/javascript') match, lang = contains_source_code(source) self.assertEqual(match, None)
def test_code_false_positive_ruby_03(self): source = self.create_response('class IPs on VPS or Dedicated Server' ' <a href="/seo-hosting/"> def </a>' ' ga("send', content_type='application/javascript') match, lang = contains_source_code(source) self.assertEqual(match, None)
def test_code_ruby_01(self): source = self.create_response('''class Person < ActiveRecord::Base validates :name, presence: true end''') match, lang = contains_source_code(source) self.assertNotEqual(match, None) self.assertEqual(lang, {RUBY})
def test_code_false_positive_ruby_03(self): source = self.create_response( 'class IPs on VPS or Dedicated Server' ' <a href="/seo-hosting/"> def </a>' ' ga("send', content_type='application/javascript') match, lang = contains_source_code(source) self.assertEqual(match, None)
def test_code_false_positive_ruby_01(self): source = self.create_response( 'var f=_.template("<div class="alert' ' alert-error <% if (title) { %>' ' alert-block <% } %>', content_type='application/javascript') match, lang = contains_source_code(source) self.assertEqual(match, None)
def test_code_python(self): source = self.create_response(''' def foo(self): pass ''') match, lang = contains_source_code(source) self.assertNotEqual(match, None) self.assertEqual(lang, {PYTHON})
def test_code_ruby_02(self): source = self.create_response('''class Person def say_hi puts 'hi' end end''') match, lang = contains_source_code(source) self.assertNotEqual(match, None) self.assertEqual(lang, {RUBY})
def test_code_false_positive_ruby_04(self): """ Will not match because of the </a> before end. End requires a space (\s) before the token. """ source = self.create_response('class IPs on VPS or Dedicated Server' ' <a href="/seo-hosting/"> def </a>end', content_type='application/javascript') match, lang = contains_source_code(source) self.assertEqual(match, None)
def test_code_false_positive_ruby_04(self): """ Will not match because of the </a> before end. End requires a space (\s) before the token. """ source = self.create_response( 'class IPs on VPS or Dedicated Server' ' <a href="/seo-hosting/"> def </a>end', content_type='application/javascript') match, lang = contains_source_code(source) self.assertEqual(match, None)
def test_code_java(self): source = self.create_response(''' public class Person{ public void printPerson() { System.out.println(name + ", " + this.getAge()); } } ''') match, lang = contains_source_code(source) self.assertNotEqual(match, None) self.assertEqual(lang, {JAVA})
def test_code_false_positive_java_01(self): """ Java source code regex matches bootstrap.js """ source = self.create_response("""PUBLIC CLASS DEFINITION // ============================== var Button = function (element, options) { this.$element = $(element) this.options = $.extend({}, Button.DEFAULTS, options) this.isLoading = false } """, content_type='application/javascript') match, lang = contains_source_code(source) self.assertEqual(match, None)
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 response_is_404 = is_404(response) # This is a performance improvement to prevent the plugin from # applying contains_source_code to a 404 response that will be # discarded even if it matches if response_is_404 and not self._report_404_match: return match, lang = contains_source_code(response) if not match: return # Only report 404 findings once if response_is_404 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(), ' or '.join(list(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 test_code_false_positive_image(self): no_source = self.create_response(file(self.TEST_FILE).read(), content_type='image/jpeg') match, lang = contains_source_code(no_source) self.assertEqual(match, None)
def _analyze_result(self, mutant, response): """ Analyze results of the _send_mutant method. Try to find the local file inclusions. """ # # I will only report the vulnerability once. # if self._has_bug(mutant): return # # Identify the vulnerability # for file_pattern_match in self._find_common_file_fragments(response): if file_pattern_match not in mutant.get_original_response_body(): desc = 'Local File Inclusion was found at: %s' 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_url().get_file_name() in mutant.get_token_value(): match, lang = contains_source_code(response) 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') desc %= 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) # body = response.get_body() for _, error_str, _ in self.file_read_error_multi_re.query(body): if error_str not in mutant.get_original_response_body(): desc = 'A file read error was found at: %s' desc %= mutant.found_at() i = Info.from_mutant('File read error', desc, response.id, self.get_name(), mutant) i.add_to_highlight(error_str) self.kb_append_uniq(self, 'error', i)
def _analyze_result(self, mutant, response): """ Analyze results of the _send_mutant method. Try to find the local file inclusions. """ # # I will only report the vulnerability once. # if self._has_bug(mutant): return # # Identify the vulnerability # for file_pattern_match in self._find_common_file_fragments(response): if file_pattern_match not in mutant.get_original_response_body(): desc = 'Local File Inclusion was found at: %s' 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 # # The calls to smart_str_ignore fix a UnicodeDecoreError which appears when # the token value is a binary string which can't be converted to unicode. # This happens, for example, when trying to upload JPG files to a multipart form # # >>> u'' in '\x80' # ... # UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0: ordinal not in range(128) # filename = smart_str_ignore(mutant.get_url().get_file_name()) token_value = smart_str_ignore(mutant.get_token_value()) if filename in token_value: match, lang = contains_source_code(response) 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') desc %= 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) # body = response.get_body() for _, error_str, _ in self.file_read_error_multi_re.query(body): if error_str not in mutant.get_original_response_body(): desc = 'A file read error was found at: %s' desc %= mutant.found_at() i = Info.from_mutant('File read error', desc, response.id, self.get_name(), mutant) i.add_to_highlight(error_str) self.kb_append_uniq(self, 'error', i)
def test_no_code_case02(self): source = self.create_response('foo <?xml ?> "bar') match, lang = contains_source_code(source) self.assertEqual(match, None) self.assertEqual(lang, None)
def test_php(self): source = self.create_response('foo <?php echo "a"; ?> bar') match, lang = contains_source_code(source) self.assertNotEqual(match, None) self.assertEqual(lang, {PHP})
def test_code_case04(self): source = self.create_response('foo <?php ypacket ?> "bar') match, lang = contains_source_code(source) self.assertNotEqual(match, None) self.assertEqual(lang, {PHP})