def test_keys(self): disk_dict = DiskDict() disk_dict['a'] = 'abc' disk_dict['b'] = 'abc' disk_dict['c'] = 'abc' self.assertEqual(set(disk_dict.keys()), set(['a', 'b', 'c']))
def test_keys(self): disk_dict = DiskDict() disk_dict['a'] = 'abc' disk_dict['b'] = 'abc' disk_dict['c'] = 'abc' self.assertEqual(set(disk_dict.keys()), set(['a', 'b', 'c']))
class ssi(AuditPlugin): """ Find server side inclusion vulnerabilities. :author: Andres Riancho ([email protected]) """ def __init__(self): AuditPlugin.__init__(self) # Internal variables self._expected_mutant_dict = DiskDict(table_prefix='ssi') self._extract_expected_re = re.compile('[1-9]{5}') def audit(self, freq, orig_response): """ Tests an URL for server side inclusion vulnerabilities. :param freq: A FuzzableRequest """ ssi_strings = [] for string in self._get_ssi_strings(): ssi_strings.append(string) mutants = create_mutants(freq, ssi_strings, orig_resp=orig_response) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result) def _get_ssi_strings(self): """ This method returns a list of server sides to try to include. :return: A string, see above. """ # Generic # yield '<!--#exec cmd="echo -n %s;echo -n %s" -->' % get_seeds() # Perl SSI # yield ('<!--#set var="SEED_A" value="%s" -->' # '<!--#echo var="SEED_A" -->' # '<!--#set var="SEED_B" value="%s" -->' # '<!--#echo var="SEED_B" -->' % get_seeds()) # Smarty # http://www.smarty.net/docsv2/en/language.function.math.tpl yield '{math equation="x * y" x=%s y=%s}' % get_seeds() # Mako # http://docs.makotemplates.org/en/latest/syntax.html yield '${%s * %s}' % get_seeds() # Jinja2 and Twig # http://jinja.pocoo.org/docs/dev/templates/#math # http://twig.sensiolabs.org/doc/templates.html yield '{{%s * %s}}' % get_seeds() # Generic yield '{%s * %s}' % get_seeds() # OGNL (struts2) #yield '${%%{%s * %s}}' % get_seeds() def _get_expected_results(self, mutant): """ Extracts the potential results from the mutant payload and returns them in a list. """ sent_payload = mutant.get_token_payload() seed_numbers = self._extract_expected_re.findall(sent_payload) seed_a = int(seed_numbers[0]) seed_b = int(seed_numbers[1]) return [str(seed_a * seed_b), '%s%s' % (seed_a, seed_b)] def _analyze_result(self, mutant, response): """ Analyze the result of the previously sent request. :return: None, save the vuln to the kb. """ # Store the mutants in order to be able to analyze the persistent case # later expected_results = self._get_expected_results(mutant) for expected_result in expected_results: self._expected_mutant_dict[expected_result] = mutant # Now we analyze the "reflected" case if self._has_bug(mutant): return for expected_result in expected_results: if expected_result not in response: continue if expected_result in mutant.get_original_response_body(): continue desc = 'Server side include (SSI) was found at: %s' desc %= mutant.found_at() v = Vuln.from_mutant('Server side include vulnerability', desc, severity.HIGH, response.id, self.get_name(), mutant) v.add_to_highlight(expected_result) self.kb_append_uniq(self, 'ssi', v) def end(self): """ This method is called when the plugin wont be used anymore and is used to find persistent SSI vulnerabilities. Example where a persistent SSI can be found: Say you have a "guest book" (a CGI application that allows visitors to leave messages for everyone to see) on a server that has SSI enabled. Most such guest books around the Net actually allow visitors to enter HTML code as part of their comments. Now, what happens if a malicious visitor decides to do some damage by entering the following: <!--#exec cmd="ls" --> If the guest book CGI program was designed carefully, to strip SSI commands from the input, then there is no problem. But, if it was not, there exists the potential for a major headache! For a working example please see moth VM. """ fuzzable_request_set = kb.kb.get_all_known_fuzzable_requests() self._send_mutants_in_threads(self._uri_opener.send_mutant, fuzzable_request_set, self._analyze_persistent, cache=False) self._expected_mutant_dict.cleanup() def _analyze_persistent(self, freq, response): """ Analyze the response of sending each fuzzable request found by the framework, trying to identify any locations where we might have injected a payload. :param freq: The fuzzable request :param response: The HTTP response :return: None, vulns are stored in KB """ multi_in_inst = multi_in(self._expected_mutant_dict.keys()) for matched_expected_result in multi_in_inst.query( response.get_body()): # We found one of the expected results, now we search the # self._expected_mutant_dict to find which of the mutants sent it # and create the vulnerability mutant = self._expected_mutant_dict[matched_expected_result] desc = ('Server side include (SSI) was found at: %s' ' The result of that injection is shown by browsing' ' to "%s".') desc %= (mutant.found_at(), freq.get_url()) v = Vuln.from_mutant( 'Persistent server side include vulnerability', desc, severity.HIGH, response.id, self.get_name(), mutant) v.add_to_highlight(matched_expected_result) self.kb_append(self, 'ssi', v) def get_long_desc(self): """ :return: A DETAILED description of the plugin functions and features. """ return """
class ssi(AuditPlugin): """ Find server side inclusion vulnerabilities. :author: Andres Riancho ([email protected]) """ def __init__(self): AuditPlugin.__init__(self) # Internal variables self._expected_res_mutant = DiskDict() self._freq_list = DiskList() re_str = '<!--#exec cmd="echo -n (.*?);echo -n (.*?)" -->' self._extract_results_re = re.compile(re_str) def audit(self, freq, orig_response): """ Tests an URL for server side inclusion vulnerabilities. :param freq: A FuzzableRequest """ # Create the mutants to send right now, ssi_strings = self._get_ssi_strings() mutants = create_mutants(freq, ssi_strings, orig_resp=orig_response) # Used in end() to detect "persistent SSI" for mut in mutants: expected_result = self._extract_result_from_payload( mut.get_token_value()) self._expected_res_mutant[expected_result] = mut self._freq_list.append(freq) # End of persistent SSI setup self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result) def _get_ssi_strings(self): """ This method returns a list of server sides to try to include. :return: A string, see above. """ yield '<!--#exec cmd="echo -n %s;echo -n %s" -->' % (rand_alpha(5), rand_alpha(5)) # TODO: Add mod_perl ssi injection support # http://www.sens.buffalo.edu/services/webhosting/advanced/perlssi.shtml #yield <!--#perl sub="sub {print qq/If you see this, mod_perl is working!/;}" --> def _extract_result_from_payload(self, payload): """ Extract the expected result from the payload we're sending. """ match = self._extract_results_re.search(payload) return match.group(1) + match.group(2) def _analyze_result(self, mutant, response): """ Analyze the result of the previously sent request. :return: None, save the vuln to the kb. """ if self._has_no_bug(mutant): e_res = self._extract_result_from_payload(mutant.get_token_value()) if e_res in response and not e_res in mutant.get_original_response_body(): desc = 'Server side include (SSI) was found at: %s' desc = desc % mutant.found_at() v = Vuln.from_mutant('Server side include vulnerability', desc, severity.HIGH, response.id, self.get_name(), mutant) v.add_to_highlight(e_res) self.kb_append_uniq(self, 'ssi', v) def end(self): """ This method is called when the plugin wont be used anymore and is used to find persistent SSI vulnerabilities. Example where a persistent SSI can be found: Say you have a "guestbook" (a CGI application that allows visitors to leave messages for everyone to see) on a server that has SSI enabled. Most such guestbooks around the Net actually allow visitors to enter HTML code as part of their comments. Now, what happens if a malicious visitor decides to do some damage by entering the following: <!--#exec cmd="ls" --> If the guestbook CGI program was designed carefully, to strip SSI commands from the input, then there is no problem. But, if it was not, there exists the potential for a major headache! For a working example please see moth VM. """ multi_in_inst = multi_in(self._expected_res_mutant.keys()) def filtered_freq_generator(freq_list): already_tested = ScalableBloomFilter() for freq in freq_list: if freq not in already_tested: already_tested.add(freq) yield freq def analyze_persistent(freq, response): for matched_expected_result in multi_in_inst.query(response.get_body()): # We found one of the expected results, now we search the # self._persistent_data to find which of the mutants sent it # and create the vulnerability mutant = self._expected_res_mutant[matched_expected_result] desc = 'Server side include (SSI) was found at: %s' \ ' The result of that injection is shown by browsing'\ ' to "%s".' desc = desc % (mutant.found_at(), freq.get_url()) v = Vuln.from_mutant('Persistent server side include vulnerability', desc, severity.HIGH, response.id, self.get_name(), mutant) v.add_to_highlight(matched_expected_result) self.kb_append(self, 'ssi', v) self._send_mutants_in_threads(self._uri_opener.send_mutant, filtered_freq_generator(self._freq_list), analyze_persistent, cache=False) self._expected_res_mutant.cleanup() self._freq_list.cleanup() def get_long_desc(self): """ :return: A DETAILED description of the plugin functions and features. """ return """
class ssi(AuditPlugin): """ Find server side inclusion vulnerabilities. :author: Andres Riancho ([email protected]) """ def __init__(self): AuditPlugin.__init__(self) # Internal variables self._expected_res_mutant = DiskDict() self._freq_list = DiskList() re_str = '<!--#exec cmd="echo -n (.*?);echo -n (.*?)" -->' self._extract_results_re = re.compile(re_str) def audit(self, freq, orig_response): """ Tests an URL for server side inclusion vulnerabilities. :param freq: A FuzzableRequest """ # Create the mutants to send right now, ssi_strings = self._get_ssi_strings() mutants = create_mutants(freq, ssi_strings, orig_resp=orig_response) # Used in end() to detect "persistent SSI" for mut in mutants: expected_result = self._extract_result_from_payload( mut.get_mod_value()) self._expected_res_mutant[expected_result] = mut self._freq_list.append(freq) # End of persistent SSI setup self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result) def _get_ssi_strings(self): """ This method returns a list of server sides to try to include. :return: A string, see above. """ yield '<!--#exec cmd="echo -n %s;echo -n %s" -->' % (rand_alpha(5), rand_alpha(5)) # TODO: Add mod_perl ssi injection support # http://www.sens.buffalo.edu/services/webhosting/advanced/perlssi.shtml #yield <!--#perl sub="sub {print qq/If you see this, mod_perl is working!/;}" --> def _extract_result_from_payload(self, payload): """ Extract the expected result from the payload we're sending. """ match = self._extract_results_re.search(payload) return match.group(1) + match.group(2) def _analyze_result(self, mutant, response): """ Analyze the result of the previously sent request. :return: None, save the vuln to the kb. """ if self._has_no_bug(mutant): e_res = self._extract_result_from_payload(mutant.get_mod_value()) if e_res in response and not e_res in mutant.get_original_response_body( ): desc = 'Server side include (SSI) was found at: %s' desc = desc % mutant.found_at() v = Vuln.from_mutant('Server side include vulnerability', desc, severity.HIGH, response.id, self.get_name(), mutant) v.add_to_highlight(e_res) self.kb_append_uniq(self, 'ssi', v) def end(self): """ This method is called when the plugin wont be used anymore and is used to find persistent SSI vulnerabilities. Example where a persistent SSI can be found: Say you have a "guestbook" (a CGI application that allows visitors to leave messages for everyone to see) on a server that has SSI enabled. Most such guestbooks around the Net actually allow visitors to enter HTML code as part of their comments. Now, what happens if a malicious visitor decides to do some damage by entering the following: <!--#exec cmd="ls" --> If the guestbook CGI program was designed carefully, to strip SSI commands from the input, then there is no problem. But, if it was not, there exists the potential for a major headache! For a working example please see moth VM. """ multi_in_inst = multi_in(self._expected_res_mutant.keys()) def filtered_freq_generator(freq_list): already_tested = ScalableBloomFilter() for freq in freq_list: if freq not in already_tested: already_tested.add(freq) yield freq def analyze_persistent(freq, response): for matched_expected_result in multi_in_inst.query( response.get_body()): # We found one of the expected results, now we search the # self._persistent_data to find which of the mutants sent it # and create the vulnerability mutant = self._expected_res_mutant[matched_expected_result] desc = 'Server side include (SSI) was found at: %s' \ ' The result of that injection is shown by browsing'\ ' to "%s".' desc = desc % (mutant.found_at(), freq.get_url()) v = Vuln.from_mutant( 'Persistent server side include vulnerability', desc, severity.HIGH, response.id, self.get_name(), mutant) v.add_to_highlight(matched_expected_result) self.kb_append(self, 'ssi', v) self._send_mutants_in_threads(self._uri_opener.send_mutant, filtered_freq_generator(self._freq_list), analyze_persistent, cache=False) self._expected_res_mutant.cleanup() self._freq_list.cleanup() def get_long_desc(self): """ :return: A DETAILED description of the plugin functions and features. """ return """
class ssi(AuditPlugin): """ Find server side inclusion vulnerabilities. :author: Andres Riancho ([email protected]) """ def __init__(self): AuditPlugin.__init__(self) # Internal variables self._expected_mutant_dict = DiskDict(table_prefix="ssi") self._extract_expected_re = re.compile("[1-9]{5}") def audit(self, freq, orig_response): """ Tests an URL for server side inclusion vulnerabilities. :param freq: A FuzzableRequest """ ssi_strings = self._get_ssi_strings() mutants = create_mutants(freq, ssi_strings, orig_resp=orig_response) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result) def _get_ssi_strings(self): """ This method returns a list of server sides to try to include. :return: A string, see above. """ # Generic yield '<!--#exec cmd="echo -n %s;echo -n %s" -->' % get_seeds() # Perl SSI yield ( '<!--#set var="SEED_A" value="%s" -->' '<!--#echo var="SEED_A" -->' '<!--#set var="SEED_B" value="%s" -->' '<!--#echo var="SEED_B" -->' % get_seeds() ) # Smarty # http://www.smarty.net/docsv2/en/language.function.math.tpl yield '{math equation="x * y" x=%s y=%s}' % get_seeds() # Mako # http://docs.makotemplates.org/en/latest/syntax.html yield "${%s * %s}" % get_seeds() # Jinja2 and Twig # http://jinja.pocoo.org/docs/dev/templates/#math # http://twig.sensiolabs.org/doc/templates.html yield "{{%s * %s}}" % get_seeds() # Generic yield "{%s * %s}" % get_seeds() def _get_expected_results(self, mutant): """ Extracts the potential results from the mutant payload and returns them in a list. """ sent_payload = mutant.get_token_payload() seed_numbers = self._extract_expected_re.findall(sent_payload) seed_a = int(seed_numbers[0]) seed_b = int(seed_numbers[1]) return [str(seed_a * seed_b), "%s%s" % (seed_a, seed_b)] def _analyze_result(self, mutant, response): """ Analyze the result of the previously sent request. :return: None, save the vuln to the kb. """ # Store the mutants in order to be able to analyze the persistent case # later expected_results = self._get_expected_results(mutant) for expected_result in expected_results: self._expected_mutant_dict[expected_result] = mutant # Now we analyze the "reflected" case if self._has_bug(mutant): return for expected_result in expected_results: if expected_result not in response: continue if expected_result in mutant.get_original_response_body(): continue desc = "Server side include (SSI) was found at: %s" desc %= mutant.found_at() v = Vuln.from_mutant( "Server side include vulnerability", desc, severity.HIGH, response.id, self.get_name(), mutant ) v.add_to_highlight(expected_result) self.kb_append_uniq(self, "ssi", v) def end(self): """ This method is called when the plugin wont be used anymore and is used to find persistent SSI vulnerabilities. Example where a persistent SSI can be found: Say you have a "guest book" (a CGI application that allows visitors to leave messages for everyone to see) on a server that has SSI enabled. Most such guest books around the Net actually allow visitors to enter HTML code as part of their comments. Now, what happens if a malicious visitor decides to do some damage by entering the following: <!--#exec cmd="ls" --> If the guest book CGI program was designed carefully, to strip SSI commands from the input, then there is no problem. But, if it was not, there exists the potential for a major headache! For a working example please see moth VM. """ fuzzable_request_set = kb.kb.get_all_known_fuzzable_requests() self._send_mutants_in_threads( self._uri_opener.send_mutant, fuzzable_request_set, self._analyze_persistent, cache=False ) self._expected_mutant_dict.cleanup() def _analyze_persistent(self, freq, response): """ Analyze the response of sending each fuzzable request found by the framework, trying to identify any locations where we might have injected a payload. :param freq: The fuzzable request :param response: The HTTP response :return: None, vulns are stored in KB """ multi_in_inst = multi_in(self._expected_mutant_dict.keys()) for matched_expected_result in multi_in_inst.query(response.get_body()): # We found one of the expected results, now we search the # self._expected_mutant_dict to find which of the mutants sent it # and create the vulnerability mutant = self._expected_mutant_dict[matched_expected_result] desc = ( "Server side include (SSI) was found at: %s" " The result of that injection is shown by browsing" ' to "%s".' ) desc %= (mutant.found_at(), freq.get_url()) v = Vuln.from_mutant( "Persistent server side include vulnerability", desc, severity.HIGH, response.id, self.get_name(), mutant, ) v.add_to_highlight(matched_expected_result) self.kb_append(self, "ssi", v) def get_long_desc(self): """ :return: A DETAILED description of the plugin functions and features. """ return """