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 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 _find_delay_in_mutant(self, mutant, delay_obj, debugging_id): """ Try to delay the response and save a vulnerability if successful :param mutant: The mutant to modify and test :param delay_obj: The delay to use :param debugging_id: The debugging ID for logging """ adc = AproxDelayController(mutant, delay_obj, self._uri_opener, delay_setting=EXPONENTIALLY) adc.set_debugging_id(debugging_id) success, responses = adc.delay_is_controlled() if not success: return # 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)
def test_delay_controlled(self): for expected_result, delays in self.TEST_SUITE: mock_uri_opener = Mock() side_effect = generate_delays(delays) mock_uri_opener.send_mutant = MagicMock(side_effect=side_effect) delay_obj = AproxDelay('%s9!', '1', 10) url = URL('http://moth/?id=1') req = FuzzableRequest(url) mutant = QSMutant(req) mutant.set_dc(url.querystring) mutant.set_token(('id', 0)) ed = AproxDelayController(mutant, delay_obj, mock_uri_opener) controlled, responses = ed.delay_is_controlled() self.assertEqual(expected_result, controlled, delays)
class redos(AuditPlugin): """ Find ReDoS vulnerabilities. :author: Sebastien Duquette ( [email protected] ) :author: Andres Riancho ([email protected]) """ def audit(self, freq, orig_response, debugging_id): """ Tests an URL for ReDoS vulnerabilities using time delays. :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 self.ignore_this_request(freq): return self._send_mutants_in_threads(func=self._find_delay_in_mutant, iterable=self._generate_delay_tests( freq, debugging_id), callback=lambda x, y: None) def _generate_delay_tests(self, freq, debugging_id): for mutant in create_mutants(freq, [ '', ]): for delay_obj in self.get_delays(): yield mutant, delay_obj, debugging_id def _find_delay_in_mutant(self, (mutant, delay_obj, debugging_id)): """ Try to delay the response and save a vulnerability if successful :param mutant: The mutant to modify and test :param delay_obj: The delay to use :param debugging_id: The debugging ID for logging """ adc = AproxDelayController(mutant, delay_obj, self._uri_opener, delay_setting=EXPONENTIALLY) adc.set_debugging_id(debugging_id) success, responses = adc.delay_is_controlled() if not success: return # 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)