def _with_echo(self, freq, orig_response, debugging_id): """ Tests an URL for OS Commanding vulnerabilities using cat/type to write the content of a known file (i.e. /etc/passwd) to the HTML. :param freq: A FuzzableRequest """ # Prepare the strings to create the mutants command_list = self._get_echo_commands() only_command_strings = [v.get_command() for v in command_list] # Create the mutants, notice that we use append=False (default) and # True to have better coverage. mutants = create_mutants(freq, only_command_strings, orig_resp=orig_response) mutants.extend( create_mutants(freq, only_command_strings, orig_resp=orig_response, append=True)) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_echo, debugging_id=debugging_id)
def _with_echo(self, freq, orig_response, debugging_id): """ Tests an URL for OS Commanding vulnerabilities using cat/type to write the content of a known file (i.e. /etc/passwd) to the HTML. :param freq: A FuzzableRequest """ # Prepare the strings to create the mutants command_list = self._get_echo_commands() only_command_strings = [v.get_command() for v in command_list] # Create the mutants, notice that we use append=False (default) and # True to have better coverage. mutants = create_mutants(freq, only_command_strings, orig_resp=orig_response) mutants.extend(create_mutants(freq, only_command_strings, orig_resp=orig_response, append=True)) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_echo, debugging_id=debugging_id)
def _generate_delay_tests(self, freq, debugging_id): fake_mutants = create_mutants(freq, ['', ]) fake_mutants.extend(create_mutants(freq, ['', ], append=True)) for mutant in fake_mutants: # # Don't try to find an OS commanding using a time delay method # if we already found it via echo # if self._has_bug(mutant): return for delay_obj in self._get_wait_commands(): yield mutant, delay_obj, debugging_id
def test_qs_and_cookie(self): cf_singleton.save('fuzzable_headers', []) cf_singleton.save('fuzz_cookies', True) # This one changed cf_singleton.save('fuzz_url_filenames', False) cf_singleton.save('fuzzed_files_extension', 'gif') cf_singleton.save('fuzz_form_files', False) cf_singleton.save('fuzz_url_parts', False) url = URL('http://moth/?id=1') # And now there is a cookie cookie = Cookie('foo=bar') freq = HTTPQSRequest(url, cookie=cookie) generated_mutants = create_mutants(freq, self.payloads) expected_urls = [ u'http://moth/?id=abc', u'http://moth/?id=def', u'http://moth/?id=1', u'http://moth/?id=1' ] generated_urls = [m.get_uri().url_string for m in generated_mutants] self.assertEqual(generated_urls, expected_urls) expected_cookies = ['foo=bar;', 'foo=bar;', 'foo=abc;', 'foo=def;'] generated_cookies = [str(m.get_cookie()) for m in generated_mutants] self.assertEqual(expected_cookies, generated_cookies) self.assertTrue( all( isinstance(m, QSMutant) or isinstance(m, CookieMutant) for m in generated_mutants))
def audit(self, freq, orig_response): """ Tests a URL for rosetta flash vulnerabilities https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ http://quaxio.com/jsonp_handcrafted_flash_files/ https://molnarg.github.io/ascii-flash/#/24 :param freq: A FuzzableRequest """ content_type, _ = orig_response.get_headers().iget('Content-Type') if not content_type: return # Only check JSONP endpoints, other "reflections" like XSS are checked # in xss.py , have different severity, exploits, etc. if 'javascript' not in content_type or 'text/plain' not in content_type: return # Note that we're only creating QS mutants, since that's a requirement # to be able to "host" the reflected Flash in the vulnerable site mutants = create_mutants(freq, [self.FLASH], orig_resp=orig_response, mutant_tuple=[QSMutant]) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def audit(self, freq, orig_response, debugging_id): """ Searches for file upload vulns. :param freq: A FuzzableRequest :param orig_response: The HTTP response associated with the fuzzable request :param debugging_id: A unique identifier for this call to audit() """ if freq.get_method().upper() != 'POST' or not freq.get_file_vars(): return # Unique payload for the files we upload payload = rand_alnum(239) for file_parameter in freq.get_file_vars(): for extension in self._extensions: _, file_content, file_name = get_template_with_payload( extension, payload) # Only file handlers are passed to the create_mutants functions named_stringio = NamedStringIO(file_content, file_name) mutants = create_mutants(freq, [named_stringio], fuzzable_param_list=[file_parameter]) for mutant in mutants: mutant.uploaded_file_name = file_name mutant.extension = extension mutant.file_content = file_content mutant.file_payload = payload self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result, debugging_id=debugging_id)
def test_fuzz_headers_no_headers(self): cf_singleton.save('fuzzable_headers', ['Referer']) # This one changed cf_singleton.save('fuzz_cookies', False) cf_singleton.save('fuzz_url_filenames', False) cf_singleton.save('fuzzed_files_extension', 'gif') cf_singleton.save('fuzz_form_files', False) cf_singleton.save('fuzz_url_parts', False) url = URL('http://moth/?id=1') # No headers in the original request #headers = Headers([('Referer', 'http://moth/foo/bar/')]) freq = HTTPQSRequest(url) generated_mutants = create_mutants(freq, self.payloads) expected_urls = ['http://moth/?id=abc', 'http://moth/?id=def', 'http://moth/?id=1', 'http://moth/?id=1', ] generated_urls = [m.get_uri().url_string for m in generated_mutants] self.assertEqual(generated_urls, expected_urls) expected_headers = [Headers(), Headers(), Headers([('Referer', 'abc')]), Headers([('Referer', 'def')]), ] generated_headers = [m.get_headers() for m in generated_mutants] self.assertEqual(expected_headers, generated_headers) self.assertTrue(all(isinstance(m, QSMutant) or isinstance(m, HeadersMutant) for m in generated_mutants))
def batch_injection_test(self, freq, orig_response): """ Uses the batch injection technique to find memcache injections """ # shortcuts send_clean = self._uri_opener.send_clean orig_body = orig_response.get_body() for mutant in create_mutants(freq, ['']): # trying to break normal execution flow with ERROR_1 payload mutant.set_token_value(self.ERROR_1) error_1_response, body_error_1_response = send_clean(mutant) if fuzzy_equal(orig_body, body_error_1_response, self._eq_limit): # # if we manage to break execution flow, there is a potential # injection otherwise - no injection! # continue # trying the correct injection request, to confirm that we've found # it! mutant.set_token_value(self.OK) ok_response, body_ok_response = send_clean(mutant) if fuzzy_equal(body_error_1_response, body_ok_response, self._eq_limit): # # The "OK" and "ERROR_1" responses are equal, this means that # we're not in a memcached injection # continue # ERROR_2 request to just make sure that we're in a memcached case mutant.set_token_value(self.ERROR_2) error_2_response, body_error_2_response = send_clean(mutant) if fuzzy_equal(orig_body, body_error_2_response, self._eq_limit): # # now requests should be different again, otherwise injection # is not confirmed # continue response_ids = [error_1_response.id, ok_response.id, error_2_response.id] desc = ('Memcache injection was found at: "%s", using' ' HTTP method %s. The injectable parameter is: "%s"') desc %= (mutant.get_url(), mutant.get_method(), mutant.get_token_name()) v = Vuln.from_mutant('Memcache injection vulnerability', desc, severity.HIGH, response_ids, 'memcachei', mutant) self.kb_append_uniq(self, 'memcachei', v)
def test_qs_and_cookie(self): cf_singleton.save('fuzzable_headers', []) cf_singleton.save('fuzz_cookies', True) # This one changed cf_singleton.save('fuzz_url_filenames', False) cf_singleton.save('fuzzed_files_extension', 'gif') cf_singleton.save('fuzz_form_files', False) cf_singleton.save('fuzz_url_parts', False) url = URL('http://moth/?id=1') # And now there is a cookie cookie = Cookie('foo=bar') freq = HTTPQSRequest(url, cookie=cookie) generated_mutants = create_mutants(freq, self.payloads) expected_urls = [u'http://moth/?id=abc', u'http://moth/?id=def', u'http://moth/?id=1', u'http://moth/?id=1'] generated_urls = [m.get_uri().url_string for m in generated_mutants] self.assertEqual(generated_urls, expected_urls) expected_cookies = ['foo=bar;', 'foo=bar;', 'foo=abc;', 'foo=def;'] generated_cookies = [str(m.get_cookie()) for m in generated_mutants] self.assertEqual(expected_cookies, generated_cookies) self.assertTrue(all(isinstance(m, QSMutant) or isinstance(m, CookieMutant) for m in generated_mutants))
def _is_token_checked(self, freq, token, orig_response): """ Please note that this method generates lots of false positives and negatives. Read the github issue for more information. :see: https://github.com/andresriancho/w3af/issues/120 :return: True if the CSRF token is NOT verified by the web application """ token_pname_lst = token.keys() token_value = token[token_pname_lst[0]] # This will generate mutants for the original fuzzable request using # the reversed token value as a CSRF-token (this is a feature: we want # to make sure it has the same length as the original token and that # it has the same type: digits, hash, etc. in order to pass the first # trivial validations) # # Only create mutants that modify the token parameter name mutants = create_mutants(freq, [token_value[::-1]], False, token_pname_lst) for mutant in mutants: mutant_response = self._uri_opener.send_mutant(mutant) if not self._is_resp_equal(orig_response, mutant_response): return True return False
def test_fuzz_headers(self): cf_singleton.save("fuzzable_headers", ["Referer"]) # This one changed cf_singleton.save("fuzz_cookies", False) cf_singleton.save("fuzz_url_filenames", False) cf_singleton.save("fuzzed_files_extension", "gif") cf_singleton.save("fuzz_form_files", False) cf_singleton.save("fuzz_url_parts", False) url = URL("http://moth/?id=1") # With headers headers = Headers([("Referer", "http://moths/"), ("Foo", "Bar")]) freq = FuzzableRequest(url, headers=headers) generated_mutants = create_mutants(freq, self.payloads) expected_urls = ["http://moth/?id=abc", "http://moth/?id=def", "http://moth/?id=1", "http://moth/?id=1"] generated_urls = [m.get_uri().url_string for m in generated_mutants] self.assertEqual(generated_urls, expected_urls) expected_headers = [ headers, headers, Headers([("Referer", "abc"), ("Foo", "Bar")]), Headers([("Referer", "def"), ("Foo", "Bar")]), ] generated_headers = [m.get_headers() for m in generated_mutants] self.assertEqual(expected_headers, generated_headers) self.assertAllInstance(generated_mutants[:2], QSMutant) self.assertAllInstance(generated_mutants[2:], HeadersMutant) self.assertAllHaveTokens(generated_mutants)
def _fuzz_with_time_delay(self, freq): """ Tests an URL for eval() usage vulnerabilities using time delays. :param freq: A FuzzableRequest """ fake_mutants = create_mutants(freq, ['', ]) self.worker_pool.map(self._test_delay, fake_mutants)
def audit(self, freq, orig_response): """ Searches for file upload vulns. :param freq: A FuzzableRequest """ if freq.get_method().upper() == 'POST' and len( freq.get_file_vars()) != 0: for file_parameter in freq.get_file_vars(): fileh_filen_list = self._create_files() # Only file handlers are passed to the create_mutants functions file_handlers = [i[0] for i in fileh_filen_list] mutants = create_mutants(freq, file_handlers, fuzzable_param_list=[ file_parameter, ]) for mutant in mutants: _, filename = os.path.split(mutant.get_mod_value().name) mutant.uploaded_file_name = filename self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result) self._remove_files(fileh_filen_list)
def test_qs_and_cookie(self): """ Even when fuzz_cookies is True, we won't create HeaderMutants based on a FuzzableRequest. This is one of the ugly things related with https://github.com/andresriancho/w3af/issues/3149 Which we fixed! """ cf_singleton.save('fuzzable_headers', []) cf_singleton.save('fuzz_cookies', True) # This one changed cf_singleton.save('fuzz_url_filenames', False) cf_singleton.save('fuzzed_files_extension', 'gif') cf_singleton.save('fuzz_form_files', False) cf_singleton.save('fuzz_url_parts', False) url = URL('http://moth/?id=1') # And now there is a cookie cookie = Cookie('foo=bar') freq = FuzzableRequest(url, cookie=cookie) mutants = create_mutants(freq, self.payloads) expected_urls = [u'http://moth/?id=abc', u'http://moth/?id=def', u'http://moth/?id=1', u'http://moth/?id=1'] generated_urls = [m.get_uri().url_string for m in mutants] self.assertEqual(generated_urls, expected_urls) self.assertAllInstance(mutants[:2], QSMutant) self.assertAllInstance(mutants[2:], CookieMutant) self.assertAllHaveTokens(mutants)
def test_filename_fname_qs(self): cf_singleton.save('fuzzable_headers', []) cf_singleton.save('fuzz_cookies', False) cf_singleton.save('fuzz_url_filenames', True) # This one changed cf_singleton.save('fuzzed_files_extension', 'gif') cf_singleton.save('fuzz_form_files', False) cf_singleton.save('fuzz_url_parts', False) url = URL('http://moth/foo.htm?id=1') freq = FuzzableRequest(url) generated_mutants = create_mutants(freq, self.payloads) expected_urls = [ u'http://moth/foo.htm?id=abc', u'http://moth/foo.htm?id=def', u'http://moth/abc.htm', u'http://moth/def.htm', u'http://moth/foo.abc', u'http://moth/foo.def', ] generated_urls = [m.get_uri().url_string for m in generated_mutants] self.assertEqual(generated_urls, expected_urls) self.assertAllInstance(generated_mutants[:2], QSMutant) self.assertAllInstance(generated_mutants[2:], FileNameMutant) self.assertAllHaveTokens(generated_mutants)
def _with_time_delay(self, freq): """ Tests an URL for OS Commanding vulnerabilities using time delays. :param freq: A FuzzableRequest """ fake_mutants = create_mutants(freq, [ '', ]) for mutant in fake_mutants: if self._has_bug(mutant): continue for delay_obj in self._get_wait_commands(): ed = ExactDelayController(mutant, delay_obj, self._uri_opener) success, responses = ed.delay_is_controlled() if success: desc = 'OS Commanding was found at: %s' % mutant.found_at() v = Vuln.from_mutant('OS commanding vulnerability', desc, severity.HIGH, [r.id for r in responses], self.get_name(), mutant) v['os'] = delay_obj.get_OS() v['separator'] = delay_obj.get_separator() self.kb_append_uniq(self, 'os_commanding', v) break
def test_urlparts_filename_path_qs(self): cf_singleton.save('fuzzable_headers', []) cf_singleton.save('fuzz_cookies', False) cf_singleton.save('fuzz_url_filenames', True) # This one changed cf_singleton.save('fuzzed_files_extension', 'gif') cf_singleton.save('fuzz_form_files', False) cf_singleton.save('fuzz_url_parts', True) # This one changed url = URL('http://moth/foo/bar.htm?id=1') freq = FuzzableRequest(url) generated_mutants = create_mutants(freq, self.payloads) generated_uris = [m.get_uri().url_string for m in generated_mutants] expected_uris = [ 'http://moth/foo/bar.htm?id=abc', 'http://moth/foo/bar.htm?id=def', 'http://moth/foo/abc.htm', 'http://moth/foo/def.htm', 'http://moth/foo/bar.abc', 'http://moth/foo/bar.def', 'http://moth/abc/bar.htm', 'http://moth/def/bar.htm', 'http://moth/foo/abc', 'http://moth/foo/def', ] self.assertEqual(generated_uris, expected_uris)
def audit(self, freq, orig_response): """ Tests an URL for ReDoS vulnerabilities using time delays. :param freq: A FuzzableRequest """ if self.ignore_this_request(freq): return fake_mutants = create_mutants(freq, [ '', ]) for mutant in fake_mutants: for delay_obj in self.get_delays(): adc = AproxDelayController(mutant, delay_obj, self._uri_opener, delay_setting=EXPONENTIALLY) success, responses = adc.delay_is_controlled() if success: # Now I can be sure that I found a vuln, we control the # response time with the delay desc = 'ReDoS was found at: %s' % mutant.found_at() response_ids = [r.id for r in responses] v = Vuln.from_mutant('ReDoS vulnerability', desc, severity.MEDIUM, response_ids, self.get_name(), mutant) self.kb_append_uniq(self, 'redos', v) break
def test_filename_fname_qs(self): cf_singleton.save('fuzzable_headers', []) cf_singleton.save('fuzz_cookies', False) cf_singleton.save('fuzz_url_filenames', True) # This one changed cf_singleton.save('fuzzed_files_extension', 'gif') cf_singleton.save('fuzz_form_files', False) cf_singleton.save('fuzz_url_parts', False) url = URL('http://moth/foo.htm?id=1') freq = FuzzableRequest(url) generated_mutants = create_mutants(freq, self.payloads) expected_urls = [u'http://moth/foo.htm?id=abc', u'http://moth/foo.htm?id=def', u'http://moth/abc.htm', u'http://moth/def.htm', u'http://moth/foo.abc', u'http://moth/foo.def', ] generated_urls = [m.get_uri().url_string for m in generated_mutants] self.assertEqual(generated_urls, expected_urls) self.assertAllInstance(generated_mutants[:2], QSMutant) self.assertAllInstance(generated_mutants[2:], FileNameMutant) self.assertAllHaveTokens(generated_mutants)
def test_fuzz_headers(self): cf_singleton.save('fuzzable_headers', ['Referer']) # This one changed cf_singleton.save('fuzz_cookies', False) cf_singleton.save('fuzz_url_filenames', False) cf_singleton.save('fuzzed_files_extension', 'gif') cf_singleton.save('fuzz_form_files', False) cf_singleton.save('fuzz_url_parts', False) url = URL('http://moth/?id=1') # With headers headers = Headers([('Referer', 'http://moths/'), ('Foo', 'Bar')]) freq = FuzzableRequest(url, headers=headers) generated_mutants = create_mutants(freq, self.payloads) expected_urls = ['http://moth/?id=abc', 'http://moth/?id=def', 'http://moth/?id=1', 'http://moth/?id=1', ] generated_urls = [m.get_uri().url_string for m in generated_mutants] self.assertEqual(generated_urls, expected_urls) expected_headers = [ headers, headers, Headers([('Referer', 'abc'), ('Foo', 'Bar')]), Headers([('Referer', 'def'), ('Foo', 'Bar')]),] generated_headers = [m.get_headers() for m in generated_mutants] self.assertEqual(expected_headers, generated_headers) self.assertAllInstance(generated_mutants[:2], QSMutant) self.assertAllInstance(generated_mutants[2:], HeadersMutant) self.assertAllHaveTokens(generated_mutants)
def _with_time_delay(self, freq): """ Tests an URL for OS Commanding vulnerabilities using time delays. :param freq: A FuzzableRequest """ fake_mutants = create_mutants(freq, ['', ]) for mutant in fake_mutants: if self._has_bug(mutant): continue for delay_obj in self._get_wait_commands(): ed = ExactDelayController(mutant, delay_obj, self._uri_opener) success, responses = ed.delay_is_controlled() if success: desc = 'OS Commanding was found at: %s' % mutant.found_at() v = Vuln.from_mutant('OS commanding vulnerability', desc, severity.HIGH, [r.id for r in responses], self.get_name(), mutant) v['os'] = delay_obj.get_OS() v['separator'] = delay_obj.get_separator() self.kb_append_uniq(self, 'os_commanding', v) break
def audit(self, freq, orig_response): """ Tests a URL for rosetta flash vulnerabilities https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ http://quaxio.com/jsonp_handcrafted_flash_files/ https://molnarg.github.io/ascii-flash/#/24 :param freq: A FuzzableRequest """ content_type, _ = orig_response.get_headers().iget('Content-Type') # Only check JSONP endpoints, other "reflections" like XSS are checked # in xss.py , have different severity, exploits, etc. if 'javascript' not in content_type or 'text/plain' not in content_type: return # Note that we're only creating QS mutants, since that's a requirement # to be able to "host" the reflected Flash in the vulnerable site mutants = create_mutants(freq, [self.FLASH], orig_resp=orig_response, mutant_tuple=[QSMutant]) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def audit(self, freq, orig_response): """ Tests an URL for ReDoS vulnerabilities using time delays. :param freq: A FuzzableRequest """ if self.ignore_this_request(freq): return fake_mutants = create_mutants(freq, ['', ]) for mutant in fake_mutants: for delay_obj in self.get_delays(): adc = AproxDelayController(mutant, delay_obj, self._uri_opener, delay_setting=EXPONENTIALLY) success, responses = adc.delay_is_controlled() if not success: continue # Now I can be sure that I found a vuln, we control the # response time with the delay desc = 'ReDoS was found at: %s' % mutant.found_at() response_ids = [r.id for r in responses] v = Vuln.from_mutant('ReDoS vulnerability', desc, severity.MEDIUM, response_ids, self.get_name(), mutant) self.kb_append_uniq(self, 'redos', v) # Only test regular expressions until we find a delay break
def audit(self, freq, orig_response): if not self._dns_zone: om.out.debug("DNS zone not configured!") return self.fqdn = "xxe.{target}.{domain}".format( target=freq.get_uri().get_domain(), domain=self._dns_zone) for mutant in create_mutants(freq, [ '&a;', ]): if isinstance(mutant, XMLMutant): mutant.get_dc().doctype = '<!DOCTYPE aa [\n' mutant.get_dc( ).doctype += ' <!ENTITY a SYSTEM "http://{FQDN}">\n'.format( FQDN=self.fqdn) mutant.get_dc().doctype += ']>' try: response = self._uri_opener.send_mutant(mutant, cache=False, timeout=10) if self.check('get.' + self.fqdn): desc = 'XXE injection at: "%s", using'\ ' HTTP method %s. The injectable parameter may be: "%s"' desc = desc % (mutant.get_url(), mutant.get_method(), mutant.get_token_name()) vuln = Vuln.from_mutant('XXE injection vulnerability', desc, severity.HIGH, response.id, 'xxe', mutant) om.out.debug(vuln.get_desc()) om.out.vulnerability("XXE injection", severity=severity.HIGH) except HTTPRequestException: om.out.debug("HTTPRequestException") except Exception as e: om.out.debug(str(e))
def test_qs_and_cookie(self): """ Even when fuzz_cookies is True, we won't create HeaderMutants based on a FuzzableRequest. This is one of the ugly things related with https://github.com/andresriancho/w3af/issues/3149 Which we fixed! """ cf_singleton.save('fuzzable_headers', []) cf_singleton.save('fuzz_cookies', True) # This one changed cf_singleton.save('fuzz_url_filenames', False) cf_singleton.save('fuzzed_files_extension', 'gif') cf_singleton.save('fuzz_form_files', False) cf_singleton.save('fuzz_url_parts', False) url = URL('http://moth/?id=1') # And now there is a cookie cookie = Cookie('foo=bar') freq = FuzzableRequest(url, cookie=cookie) mutants = create_mutants(freq, self.payloads) expected_urls = [ u'http://moth/?id=abc', u'http://moth/?id=def', u'http://moth/?id=1', u'http://moth/?id=1' ] generated_urls = [m.get_uri().url_string for m in mutants] self.assertEqual(generated_urls, expected_urls) self.assertAllInstance(mutants[:2], QSMutant) self.assertAllInstance(mutants[2:], CookieMutant) self.assertAllHaveTokens(mutants)
def audit(self, freq, orig_response): """ Find all kind of bugs without using a fixed database of errors. :param freq: A FuzzableRequest """ # First, get the original response and create the mutants mutants = create_mutants(freq, [ '', ], orig_resp=orig_response) for m in mutants: # First I check that the current modified parameter in the mutant # doesn't have an already reported vulnerability. I don't want to # report vulnerabilities more than once. if (m.get_url(), m.get_token_name()) in self._potential_vulns: continue # Now, we request the limit (something that doesn't exist) # If http://localhost/a.php?b=1 # * Then I should request b=12938795 (random number) # # If http://localhost/a.php?b=abc # * Then I should request b=hnv98yks (random alnum) limit_response = self._get_limit_response(m) # Now I request something that could generate an error # If http://localhost/a.php?b=1 # * Then I should request b=d'kcz'gj'"**5*(((*) # # If http://localhost/a.php?b=abc # * Then I should request b=d'kcz'gj'"**5*(((*) # # I also try to trigger errors by sending empty strings # If http://localhost/a.php?b=1 ; then I should request b= # If http://localhost/a.php?b=abc ; then I should request b= for error_string in self.ERROR_STRINGS: m.set_token_value(error_string) error_response = self._uri_opener.send_mutant(m) # Now I compare responses self._analyze_responses(orig_response, limit_response, error_response, m) m.set_token_value("") void_response = self._uri_opener.send_mutant(m) old_token_name = m.get_token_name() if old_token_name.find('[') != -1: new_token_name = old_token_name[0:old_token_name.index('[')] else: new_token_name = m.get_token_name() + '[]' if m.get_dc().get(old_token_name): m.get_dc()[new_token_name] = m.get_dc().pop(old_token_name) else: m.get_dc()[new_token_name] = '' m.get_dc().token._name = new_token_name error_response = self._uri_opener.send_mutant(m) self._compare_responses(void_response, error_response, m)
def batch_injection_test(self, freq, orig_response): """ Uses the batch injection technique to find memcache injections """ # shortcuts send_clean = self._uri_opener.send_clean orig_body = orig_response.get_body() for mutant in create_mutants(freq, ['']): # trying to break normal execution flow with ERROR_1 payload mutant.set_token_value(self.ERROR_1) error_1_response, body_error_1_response = send_clean(mutant) if fuzzy_equal(orig_body, body_error_1_response, self._eq_limit): # # if we manage to break execution flow, there is a potential # injection otherwise - no injection! # continue # trying the correct injection request, to confirm that we've found # it! mutant.set_token_value(self.OK) ok_response, body_ok_response = send_clean(mutant) if fuzzy_equal(body_error_1_response, body_ok_response, self._eq_limit): # # The "OK" and "ERROR_1" responses are equal, this means that # we're not in a memcached injection # continue # ERROR_2 request to just make sure that we're in a memcached case mutant.set_token_value(self.ERROR_2) error_2_response, body_error_2_response = send_clean(mutant) if fuzzy_equal(orig_body, body_error_2_response, self._eq_limit): # # now requests should be different again, otherwise injection # is not confirmed # continue response_ids = [ error_1_response.id, ok_response.id, error_2_response.id ] desc = ('Memcache injection was found at: "%s", using' ' HTTP method %s. The injectable parameter is: "%s"') desc %= (mutant.get_url(), mutant.get_method(), mutant.get_token_name()) v = Vuln.from_mutant('Memcache injection vulnerability', desc, severity.HIGH, response_ids, 'memcachei', mutant) self.kb_append_uniq(self, 'memcachei', v)
def audit(self, freq, orig_response): """ Tests an URL for buffer overflow vulnerabilities. :param freq: A FuzzableRequest """ mutants = create_mutants(freq, self.BUFFER_TESTS, orig_resp=orig_response) self.worker_pool.map(self._send_request, mutants)
def audit(self, freq, orig_response): """ Tests an URL for response splitting vulnerabilities. :param freq: A fuzzable_request """ mutants = create_mutants(freq, self.HEADER_INJECTION_TESTS) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def audit(self, freq, orig_response): """ Tests an URL for SQL injection vulnerabilities. :param freq: A FuzzableRequest """ mutants = create_mutants(freq, self.SQLI_STRINGS, orig_resp=orig_response) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def _generate_delay_tests(self, freq, debugging_id): fake_mutants = create_mutants(freq, [ '', ]) fake_mutants.extend(create_mutants(freq, [ '', ], append=True)) for mutant in fake_mutants: # # Don't try to find an OS commanding using a time delay method # if we already found it via echo # if self._has_bug(mutant): return for delay_obj in self._get_wait_commands(): yield mutant, delay_obj, debugging_id
def audit(self, freq, orig_response): """ Tests an URL for xpath injection vulnerabilities. :param freq: A FuzzableRequest """ mutants = create_mutants(freq, self.XPATH_TEST_PAYLOADS, orig_resp=orig_response) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def audit(self, freq, orig_response): """ Tests an URL for mx injection vulnerabilities. :param freq: A FuzzableRequest """ mx_injection_strings = self._get_MX_injection_strings() mutants = create_mutants(freq, mx_injection_strings, orig_resp=orig_response) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def audit(self, freq, orig_response): """ Find those phishing vectors! :param freq: A FuzzableRequest """ mutants = create_mutants(freq, self._test_urls) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def audit(self, freq, orig_response): """ Tests an URL for SQL injection vulnerabilities. :param freq: A FuzzableRequest """ sqli_str = [replace_randomize(i, 2) for i in self.SQLI_STRINGS] mutants = create_mutants(freq, sqli_str, orig_resp=orig_response) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def test_xmlrpc_mutant(self): url = URL('http://moth/?id=1') post_data = XML_WITH_FUZZABLE headers = Headers() freq = FuzzableRequest.from_parts(url, 'POST', post_data, headers) mutants = create_mutants(freq, self.payloads) self.assertAllInstance(mutants[:2], QSMutant) self.assertAllInstance(mutants[4:], XmlRpcMutant) self.assertAllHaveTokens(mutants)
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 audit(self, freq, orig_response): """ Tests an URL for global redirect vulnerabilities. :param freq: A FuzzableRequest object """ mutants = create_mutants(freq, self.TEST_URLS) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def test_empty_string_as_payload(self): url = URL("http://moth/?id=1&spam=2") freq = FuzzableRequest(url) generated_mutants = create_mutants(freq, [""]) expected_urls = ["http://moth/?id=&spam=2", "http://moth/?id=1&spam="] generated_urls = [m.get_uri().url_string for m in generated_mutants] self.assertEqual(generated_urls, expected_urls) self.assertAllInstance(generated_mutants, QSMutant) self.assertAllHaveTokens(generated_mutants)
def batch_injection_test(self, freq, orig_response, debugging_id): """ Uses the batch injection technique to find memcache injections """ mutants = create_mutants(freq, ['']) self._send_mutants_in_threads(self._analyze_echo, mutants, callback=lambda x, y: None, debugging_id=debugging_id, original_response=orig_response)
def audit(self, freq, orig_response): """ Tests an URL for format string vulnerabilities. :param freq: A FuzzableRequest """ string_list = self._get_string_list() mutants = create_mutants(freq, string_list, orig_resp=orig_response) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def test_empty_string_as_payload_one_param(self): url = URL('http://moth/?id=1') freq = FuzzableRequest(url) generated_mutants = create_mutants(freq, ['']) expected_urls = ['http://moth/?id='] generated_urls = [m.get_uri().url_string for m in generated_mutants] self.assertEqual(generated_urls, expected_urls) self.assertAllInstance(generated_mutants, QSMutant) self.assertAllHaveTokens(generated_mutants)
def audit(self, freq, orig_response): """ Tests an URL for xpath injection vulnerabilities. :param freq: A FuzzableRequest """ xpath_strings = self._get_xpath_strings() mutants = create_mutants(freq, xpath_strings, orig_resp=orig_response) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_result)
def audit(self, freq, orig_response): """ Tests an URL for XSS vulnerabilities. :param freq: A FuzzableRequest """ fake_mutants = create_mutants(freq, ['',]) # Run this in the worker pool in order to get different # parameters tested at the same time. self.worker_pool.map(self._check_xss_in_parameter, fake_mutants)
def _generate_delay_tests(self, freq, debugging_id): for mutant in create_mutants(freq, ['', ]): # # Don't try to find an eval() using a time delay method if we already found # it via echo # if self._has_bug(mutant): return for delay_obj in self.WAIT_OBJ: yield mutant, delay_obj, debugging_id
def _fuzz_with_echo(self, freq, orig_response): """ Tests an URL for eval() usage vulnerabilities using echo strings. :param freq: A FuzzableRequest """ print_strings = [pstr % (self._rnd, ) for pstr in self.PRINT_STRINGS] mutants = create_mutants(freq, print_strings, orig_resp=orig_response) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_echo)
def _fuzz_with_echo(self, freq, orig_response): """ Tests an URL for eval() usage vulnerabilities using echo strings. :param freq: A FuzzableRequest """ print_strings = [pstr % (self._rnd,) for pstr in self.PRINT_STRINGS] mutants = create_mutants(freq, print_strings, orig_resp=orig_response) self._send_mutants_in_threads(self._uri_opener.send_mutant, mutants, self._analyze_echo)