def test_ip_memoized(self): result_1 = smart_fill('ip') result_2 = smart_fill('ip') self.assertEquals(result_1, '127.0.0.1') self.assertIs(result_1, result_2) self.assertIn(('ip',), smart_fill.cache.d)
def test_ip_memoized(self): result_1 = smart_fill('ip') result_2 = smart_fill('ip') self.assertEquals(result_1, '127.0.0.1') self.assertIs(result_1, result_2) self.assertIn(('ip', ), smart_fill.cache.d)
def _fill_form(self, fuzzable_req): """ Fill the HTTP request form that is passed as fuzzable_req. :return: A filled form """ self._already_filled_form.add(fuzzable_req.get_url()) to_send = fuzzable_req.get_dc().copy() for param_name in to_send: # I do not want to mess with the "static" fields if isinstance(to_send, form.Form): if to_send.get_type(param_name) in ('checkbox', 'file', 'radio', 'select'): continue # Set all the other fields, except from the ones that have a # value set (example: hidden fields like __VIEWSTATE). for elem_index in xrange(len(to_send[param_name])): # TODO: Should I ignore it because it already has a value? if to_send[param_name][elem_index] != '': continue # SmartFill it! to_send[param_name][elem_index] = smart_fill(param_name) fuzzable_req.set_dc(to_send) return fuzzable_req
def smart_fill(self): """ :return: Fills all the empty parameters (which should be filled) using the smart_fill function. """ file_variables = self.get_file_vars() for var_name, value, path, setter in self.iter_setters(): if self.get_parameter_type(var_name) in self.AVOID_FILLING_FORM_TYPES: continue if isinstance(value, DataToken): # This is the value which is being fuzzed (the payload) and # I don't want to change/fill it continue # The basic idea here is that if the form has files in it, we'll # need to fill that input with a file (gif, txt, html) in order # to go through the form validations if var_name in file_variables: file_name = self.get_file_name(var_name, None) setter(smart_fill_file(var_name, file_name)) # Fill only if the parameter does NOT have a value set. # # The reason of having this already set would be that the form # has something like this: # # <input type="text" name="p" value="foobar"> # elif value == '': setter(smart_fill(var_name))
def smart_fill(self): """ :return: Fills all the empty parameters (which should be filled) using the smart_fill function. """ file_variables = self.get_file_vars() for var_name, value, path, setter in self.iter_setters(): if self.get_parameter_type( var_name) in self.AVOID_FILLING_FORM_TYPES: continue if isinstance(value, DataToken): # This is the value which is being fuzzed (the payload) and # I don't want to change/fill it continue # The basic idea here is that if the form has files in it, we'll # need to fill that input with a file (gif, txt, html) in order # to go through the form validations if var_name in file_variables: file_name = self.get_file_name(var_name, None) setter(smart_fill_file(var_name, file_name)) # Fill only if the parameter does NOT have a value set. # # The reason of having this already set would be that the form # has something like this: # # <input type="text" name="p" value="foobar"> # elif value == '': setter(smart_fill(var_name))
def _get_param_value_for_type_and_spec(self, parameter_type, parameter_spec): """ :param parameter_type: The type of parameter (string, int32, array, etc.) :param parameter_spec: The parameter spec :return: The parameter value """ # # Easiest cases, the parameter already has a default or example value # default_value = parameter_spec.get('default', None) if default_value is not None: return default_value example_value = parameter_spec.get('example', None) if example_value is not None: return example_value # This handles the case where the value is an enum and can only be selected # from a predefined option list if 'enum' in parameter_spec: if parameter_spec['enum']: return parameter_spec['enum'][0] if parameter_type in ('integer', 'float', 'double', 'int32', 'int64'): _max = None _min = None if 'maximum' in parameter_spec: _max = parameter_spec['maximum'] if 'minimum' in parameter_spec: _min = parameter_spec['minimum'] # Only do something if max or min are set if _max is not None or _min is not None: _max = _max if _max is not None else 56 _min = _min if _min is not None else 0 # We always want to generate the same number for the same range r = random.Random() r.seed(1) return r.randint(_min, _max) default_value = self.DEFAULT_VALUES_BY_TYPE.get(parameter_type, None) if default_value is not None: return default_value parameter_name = parameter_spec.get('name', None) if parameter_type == 'string': parameter_name = 'unknown' if parameter_name is None else parameter_name return smart_fill(parameter_name) if parameter_type == 'file': parameter_name = 'unknown' if parameter_name is None else parameter_name return smart_fill_file(parameter_name, 'cat.png')
def mutant_smart_fill(freq, dc_copy, ignore_pname, ignore_index, fuzzer_config): """ :param freq: The fuzzable request (original request instance) we're fuzzing :param ignore_pname: A parameter name to ignore :param ignore_index: The index we want to ignore :return: A data container that has been filled using smart_fill, ignoring the parameters that I'm fuzzing and filling the file inputs with valid image file. """ for var_name_dc in dc_copy: for element_index_dc, element_value_dc in enumerate( dc_copy[var_name_dc]): if (var_name_dc, element_index_dc) == (ignore_pname, ignore_index): continue if dc_copy.get_type(var_name_dc) in AVOID_FILLING_FORM_TYPES: continue # Fill only if the parameter does NOT have a value set. # # The reason of having this already set would be that the form # has something like this: # # <input type="text" name="p" value="foobar"> # if dc_copy[var_name_dc][element_index_dc] == '': # # Fill it smartly # dc_copy[var_name_dc][element_index_dc] = smart_fill( var_name_dc) # Please see the comment above (search for __HERE__) for an explanation # of what we are doing here: for var_name in freq.get_file_vars(): # Try to upload a valid file extension = fuzzer_config.get('fuzz_form_files') or 'gif' success, file_content, file_name = get_file_from_template(extension) # I have to create the NamedStringIO with a "name", # required for MultipartPostHandler str_file = NamedStringIO(file_content, name=file_name) # TODO: Is this hard-coded [0] enough? dc_copy[var_name][0] = str_file return dc_copy
def mutant_smart_fill(freq, dc_copy, ignore_pname, ignore_index, fuzzer_config): """ :param freq: The fuzzable request (original request instance) we're fuzzing :param ignore_pname: A parameter name to ignore :param ignore_index: The index we want to ignore :return: A data container that has been filled using smart_fill, ignoring the parameters that I'm fuzzing and filling the file inputs with valid image file. """ for var_name_dc in dc_copy: for element_index_dc, element_value_dc in enumerate(dc_copy[var_name_dc]): if (var_name_dc, element_index_dc) == (ignore_pname, ignore_index): continue if dc_copy.get_type(var_name_dc) in AVOID_FILLING_FORM_TYPES: continue # Fill only if the parameter does NOT have a value set. # # The reason of having this already set would be that the form # has something like this: # # <input type="text" name="p" value="foobar"> # if dc_copy[var_name_dc][element_index_dc] == '': # # Fill it smartly # dc_copy[var_name_dc][element_index_dc] = smart_fill(var_name_dc) # Please see the comment above (search for __HERE__) for an explanation # of what we are doing here: for var_name in freq.get_file_vars(): # Try to upload a valid file extension = fuzzer_config.get('fuzz_form_files') or 'gif' success, file_content, file_name = get_file_from_template(extension) # I have to create the NamedStringIO with a "name", # required for MultipartPostHandler str_file = NamedStringIO(file_content, name=file_name) # TODO: Is this hard-coded [0] enough? dc_copy[var_name][0] = str_file return dc_copy
def _get_param_value_for_type_and_spec(self, parameter_type, parameter_spec): """ :param parameter_type: The type of parameter (string, int32, array, etc.) :param parameter_spec: The parameter spec :return: The parameter value """ parameter_name = parameter_spec.get('name', None) # This handles the case where the value is an enum and can only be selected # from a predefined option list if 'enum' in parameter_spec: if parameter_spec['enum']: return parameter_spec['enum'][0] if parameter_type in ('integer', 'float', 'double', 'int32', 'int64'): _max = None _min = None if 'maximum' in parameter_spec: _max = parameter_spec['maximum'] if 'minimum' in parameter_spec: _min = parameter_spec['minimum'] # Only do something if max or min are set if _max is not None or _min is not None: _max = _max if _max is not None else 56 _min = _min if _min is not None else 0 # We always want to generate the same number for the same range r = random.Random() r.seed(1) return r.randint(_min, _max) default_value = self.DEFAULT_VALUES_BY_TYPE.get(parameter_type, None) if default_value is not None: return default_value if parameter_type == 'string': parameter_name = 'unknown' if parameter_name is None else parameter_name return smart_fill(parameter_name) if parameter_type == 'file': parameter_name = 'unknown' if parameter_name is None else parameter_name return smart_fill_file(parameter_name, 'cat.png')
def test_default(self): self.assertEquals(smart_fill('foobar'), '56')
def test_ip_case_insensitive(self): self.assertEquals(smart_fill('IP'), '127.0.0.1')
def test_ip(self): self.assertEquals(smart_fill('ip'), '127.0.0.1')
def test_address_2(self): self.assertEquals(smart_fill('street_address'), 'Bonsai Street 123')