def get_body_start(request): """ Get the starting index of the request body @param request: The target request @type request: Request @return: The starting index; -1 if not found @rtype: Int or -1 on failure """ # search for the first of these patterns in the request definition body_start_pattern_dict = primitives.restler_static_string('{') body_start_pattern_array = primitives.restler_static_string('[') dict_index = -1 array_index = -1 try: dict_index = request.definition.index(body_start_pattern_dict) except Exception: pass try: array_index = request.definition.index(body_start_pattern_array) except Exception: pass if dict_index == -1 or array_index == -1: # If one of the indices is -1 then it wasn't found, return the other return max(dict_index, array_index) # Return the lowest index / first character found in body. return min(dict_index, array_index)
def get_fuzzing_blocks(self, config): """ Returns the fuzzing request blocks per the config @return: The list of request blocks @rtype : List[str] """ # default value default_value = config.get_default_value( self.tag, primitives.FUZZABLE_BOOL ) default_value = str(default_value).lower() if not self.is_fuzzable(): return [primitives.restler_static_string(default_value)] if not config.merge_fuzzable_values: return [primitives.restler_fuzzable_bool(default_value)] # get the set of fuzzable variables fuzzable_values_raw = config.get_fuzzable_values( self.tag, primitives.FUZZABLE_BOOL ) fuzzable_values = [ str(value) for value in fuzzable_values_raw ] # merge default + fuzzable values fuzzable_group = config.cleanup_fuzzable_group( default_value, fuzzable_values ) return [(primitives.FUZZABLE_GROUP, fuzzable_group)]
def set_id_values_for_create_once_dynamic_objects(self, dynamic_object_values, rendered_sequence): """ Sets the ID values for specified dynamic object values in the request definition. The function iterates through the definition and replaces the variable names specified in the @param dynamic_object_values dictionary with the values associated with them. That variable is then removed as a consumer for this request because that variable will now be replaced with what can be thought of as a static_string (not dynamic). @param dynamic_object_values: Dictionary of dynamic object names and values @type dynamic_object_values: Dict @param rendered_sequence: The rendered create-once sequence that was sent to create the dynamic objects @type rendered_sequence: RenderedSequence @return: None @rtype : None """ for i, line in enumerate(self.definition): var_name = self._get_var_name_from_definition_line(line) if var_name and var_name in dynamic_object_values: self._definition[i] =\ primitives.restler_static_string(dynamic_object_values[var_name]) # Remove the variable from consumers, because the reader has # been removed from the definition. if var_name in self._consumes: self._consumes.remove(var_name) self._create_once_requests += rendered_sequence.sequence.sent_request_data_list
def fuzz_body_blocks(self, config) -> list: """ Fuzz the value of interpreted body blocks @param config: PayloadBodyChecker specific configuration data (can be None) @type config: Dict @return: The fuzzed request blocks @rtype : List[str] """ # Set the config self._config = FuzzingConfig(config) # Get the fuzzing blocks blocks = self._schema.get_fuzzing_blocks(self._config) if self._config.fuzz_strategy == 'restler': return [blocks] acc = '' sets = [] for block in blocks: primitive_type = block[0] value = block[1] if len(block) > 2: quoted = block[2] # accumulate if primitive_type == primitives.STATIC_STRING: if quoted: value = f'"{value}"' acc += str(value) # fuzzable values elif primitive_type == primitives.FUZZABLE_GROUP: choices = [f'{acc}{choice}' for choice in value] sets.append(choices) acc = '' # not supported yet else: logger.raw_network_logging(f'Cannot fuzz type {primitive_type}') return blocks # tailing static string sets.append([acc]) import engine.fuzzing_parameters.fuzzing_utils as fuzzing_utils # compose if self._config.fuzz_strategy == 'EX': pool = fuzzing_utils.get_product_exhaust(sets, self._config.max_combination) elif self._config.fuzz_strategy == 'D1': pool = fuzzing_utils.get_product_linear_fair(sets, self._config.max_combination) else: pool = fuzzing_utils.get_product_linear_bias(sets, self._config.max_combination) strs = [''.join(p) for p in pool] outs = [[primitives.restler_static_string(string)] for string in strs] return outs
def _send_each_example(self, request): """ Substitutes each example into the request and sends it """ def _send_request(request_to_send): self._log( "Sending example request: \n" f"{request_to_send.definition}", print_to_network_log=False) seq = self._sequence + Sequence(request_to_send) response, _ = self._render_and_send_data(seq, request_to_send) code = response.status_code self._log(f"Status Code: {code}", print_to_network_log=False) if code not in status_codes: status_codes[code] = 0 status_codes[code] += 1 # Check to make sure a bug wasn't uncovered while executing the sequence if response and response.has_bug_code(): self._print_suspect_sequence(seq, response) BugBuckets.Instance().update_bug_buckets( seq, code, origin=self.__class__.__name__, hash_full_request=True) status_codes = {} # Send new request for each body example for example in request.examples.body_examples: blocks = example.get_blocks() new_request = substitute_body(request, blocks) if new_request: _send_request(new_request) else: self._log( f"Failed to substitute body for request {request.endpoint}." ) # Send new request for each query example. # For now don't try to match these up with body examples. # There will soon be IDs associated with the examples, so they can be matched. for example in request.examples.query_examples: q_blocks = [] for idx, query in enumerate(example.queries): q_blocks += query.get_blocks() if idx < len(example) - 1: # Add the query separator q_blocks.append(primitives.restler_static_string('&')) new_request = substitute_query(request, q_blocks) if new_request: _send_request(new_request) else: self._log('Failed to substitute query') self._log("Results:") for code in status_codes: self._log(f"{code}: {status_codes[code]}") self._log("\n", print_to_network_log=False)
def get_fuzzing_blocks(self, config): """ Returns the fuzzing request blocks of this member @return: The list of request blocks @rtype : List[str] """ return [primitives.restler_static_string(f'"{self._name}":')] +\ self._value.get_fuzzing_blocks(config)
def get_blocks(self): """ Gets the request blocks for the Query Parameter. @return: Request blocks representing the format: key=ParamObject @rtype : List[str] """ key = primitives.restler_static_string(f'{self._key}=') return [key] + self._content.get_blocks(FuzzingConfig())
def get_blocks(self, config=None): """ Gets request blocks for the Member Parameters. @return: Request blocks representing the format: "key":value @rtype : List[str] """ return [primitives.restler_static_string(f'"{self._name}":')] +\ self._value.get_blocks(config)
def get_blocks(self, config=None): """ Gets the request blocks for this value param. @return: A request block containing the value of the param @rtype : List[str] """ if self._custom: return[primitives.restler_custom_payload(self._content)] return [primitives.restler_static_string(self._content)]
def get_blocks(self, config=None): """ Gets request blocks for the String Parameters. @return: A request block containing the string @rtype : List[str] """ if self._is_custom: return [primitives.restler_custom_payload(self._content, quoted=True)] return [primitives.restler_static_string(self._content, quoted=True)]
def get_blocks(self, config=None): """ Gets request blocks for Object Leaf Parameters @return: Request block @rtype : List[str] """ formalized_content = self._content.replace("'", '"') formalized_content = formalized_content.replace('u"', '"') return [primitives.restler_static_string(formalized_content)]
def _get_blocks(self, values_blocks): """ Returns list of request blocks associated with this array @param values_blocks: The array's values' blocks retrieved during traversal of this array @return: The list of request blocks associated with this array @rtype : List[str] """ blocks = [] blocks.append(primitives.restler_static_string('[')) for idx, value_blocks in enumerate(values_blocks): blocks += value_blocks if idx != (len(values_blocks) - 1): blocks.append(primitives.restler_static_string(',')) blocks.append(primitives.restler_static_string(']')) return blocks
def _get_blocks(self, members_blocks: list) -> list: """ Returns list of request blocks associated with this object @param members_blocks: The object's members' blocks retrieved during traversal of this object @return: The list of request blocks associated with this object @rtype : List[str] """ blocks = [] blocks.append(primitives.restler_static_string('{')) for idx, member_blocks in enumerate(members_blocks): blocks += member_blocks if idx != (len(members_blocks) - 1): blocks.append(primitives.restler_static_string(',')) blocks.append(primitives.restler_static_string('}')) return blocks
def get_fuzzing_blocks(self, config): """ Returns the fuzzing request blocks per the config @return: The list of request blocks @rtype : List[str] """ # helper function to sanitize raw object string def formalize_object_value(raw_object): object_str = str(raw_object) object_tmp = object_str.replace("'", '"') object_tmp = object_tmp.replace('u"', '"') try: test_object = json.loads(object_tmp) if str(test_object) == raw_object: return object_tmp except Exception: return '{ "fuzz" : false }' return object_str # default value default_value = config.get_default_value(self.tag, primitives.FUZZABLE_OBJECT) default_value = formalize_object_value(default_value) # not fuzzalbe --> constant if not self.is_fuzzable(): return [primitives.restler_static_string(default_value)] # fuzz as normal fuzzable object using wordbook if not config.merge_fuzzable_values: return [primitives.restler_fuzzable_object(default_value)] # get the set of fuzzable values fuzzable_values_raw = config.get_fuzzable_values( self.tag, primitives.FUZZABLE_OBJECT) fuzzable_values = [ formalize_object_value(value) for value in fuzzable_values_raw ] # merge default + fuzzable values fuzzable_group = config.cleanup_fuzzable_group(default_value, fuzzable_values) return [ primitives.restler_fuzzable_group(FUZZABLE_GROUP_TAG, fuzzable_group) ]
def update_host(self): """ Updates the Host field for every request with the one specified in Settings @return: None @rtype : None """ new_host_line = primitives.restler_static_string(f"{request_utilities.HOST_PREFIX}{Settings().host}\r\n") host_idx = self.get_host_index() if host_idx >= 0: self._definition[host_idx] = new_host_line else: # Host not in grammar, add it header_idx = self.header_start_index() if header_idx < 0: raise InvalidGrammarException self._definition.insert(header_idx, new_host_line)
def get_body_start(request): """ Get the starting index of the request body @param request: The target request @type request: Request @return: The starting index; -1 if not found @rtype: Int or -1 on failure """ # search for this pattern in the request definition body_start_pattern = primitives.restler_static_string('{') try: body_start_index = request.definition.index(body_start_pattern) return body_start_index except Exception: return -1
def get_query_start_end(request): """ Get the start and end index of a request's query @param request: The target request @type request: Request @return: A tuple containing the start and end index of the query @rtype : Tuple(int, int) or (-1, -1) on failure """ query_start_pattern = primitives.restler_static_string('?') query_end_str = ' HTTP' try: query_start_index = request.definition.index(query_start_pattern) + 1 for idx, line in enumerate(request.definition[query_start_index + 1:]): if line[1].startswith(query_end_str): query_end_index = query_start_index + idx + 1 return query_start_index, query_end_index else: return -1, -1 except: return -1, -1
"Exception parsing response, data was not valid json: {}".format( error)) try: temp_123 = str(data["name"]) except Exception as error: pass if temp_123: dependencies.set_variable("_group_put_name", temp_123) req_collection = requests.RequestCollection([]) request = requests.Request([ primitives.restler_static_string("GET "), primitives.restler_static_string("/"), primitives.restler_static_string(" HTTP/1.1\r\n"), primitives.restler_static_string("Accept: application/json\r\n"), primitives.restler_static_string("Host: restler.unit.test.server.com\r\n"), primitives.restler_static_string("Content-Type: application/json\r\n"), primitives.restler_refreshable_authentication_token( "authentication_token_tag"), primitives.restler_static_string("\r\n") ], requestId="/") req_collection.add_request(request) request = requests.Request([ primitives.restler_static_string("GET "), primitives.restler_static_string("/"),
"Exception parsing response, data was not valid json: {}".format( error)) try: temp_123 = str(data["name"]) except Exception as error: pass if temp_123: dependencies.set_variable("_city_house_put_name", temp_123) req_collection = requests.RequestCollection([]) request = requests.Request([ primitives.restler_static_string("GET "), primitives.restler_static_string("/"), primitives.restler_static_string("city"), primitives.restler_static_string(" HTTP/1.1\r\n"), primitives.restler_static_string("Accept: application/json\r\n"), primitives.restler_static_string("Host: restler.unit.test.server.com\r\n"), primitives.restler_static_string("Content-Type: application/json\r\n"), primitives.restler_refreshable_authentication_token( "authentication_token_tag"), primitives.restler_static_string("\r\n") ], requestId="/city") req_collection.add_request(request) request = requests.Request([ primitives.restler_static_string("PUT "),
# This is not an error, since some properties are not always returned pass # If no dynamic objects were extracted, throw. if not (temp_7262): raise ResponseParsingException("Error: all of the expected dynamic objects were not present in the response.") # Set dynamic variables if temp_7262: dependencies.set_variable("_stores_post_id", temp_7262) req_collection = requests.RequestCollection([]) # Endpoint: /stores, method: Post request = requests.Request([ primitives.restler_static_string("POST "), primitives.restler_static_string("/"), primitives.restler_static_string("api"), primitives.restler_static_string("/"), primitives.restler_static_string("stores"), primitives.restler_static_string(" HTTP/1.1\r\n"), primitives.restler_static_string("Accept: application/json\r\n"), primitives.restler_static_string("Host: localhost:8888\r\n"), primitives.restler_static_string("\r\n"), { 'post_send': { 'parser': parse_storespost, 'dependencies': [
def get_fuzzing_blocks(self, config): """ Returns the fuzzing request blocks per the config @return: The list of request blocks @rtype : List[str] """ # default value default_value = config.get_default_value( self.tag, primitives.FUZZABLE_STRING, self._content ) def not_like_string(val): """ Tests if a value seems to be some type other than a string (i.e. array, dict, bool, int) """ if not val or not isinstance(val, str): return True if val[0] == '[' and val[-1] == ']': return True if val[0] == '{' and val[-1] == '}': return True if val.lower() == 'true' or val.lower() == 'false': return True try: v = int(val) return True except Exception: pass return False if self.is_unknown and not_like_string(default_value): # Try to get a new default value without a hint default_value = config.get_default_value( self.tag, primitives.FUZZABLE_STRING, hint=None ) if not_like_string(default_value): return [primitives.restler_static_string(default_value, quoted=False)] if not self.is_fuzzable(): return [primitives.restler_static_string(default_value, quoted=True)] # fuzz as normal fuzzable string if not config.merge_fuzzable_values: blocks = [] blocks.append(primitives.restler_fuzzable_string(default_value), quoted=True) return blocks # get the set of fuzzable values fuzzable_values_raw = config.get_fuzzable_values( self.tag, primitives.FUZZABLE_STRING ) fuzzable_values = [ f'"{value}"' for value in fuzzable_values_raw ] # merge default + fuzzable values fuzzable_group = config.cleanup_fuzzable_group( f'"{default_value}"', fuzzable_values ) return [(primitives.FUZZABLE_GROUP, fuzzable_group)]
# If no dynamic objects were extracted, throw. if not (temp_7262): raise ResponseParsingException( "Error: all of the expected dynamic objects were not present in the response." ) # Set dynamic variables if temp_7262: dependencies.set_variable("_stores__storeId__order_post_id", temp_7262) req_collection = requests.RequestCollection([]) # Endpoint: /stores, method: Get request = requests.Request([ primitives.restler_static_string("GET "), primitives.restler_static_string("/"), primitives.restler_static_string("api"), primitives.restler_static_string("/"), primitives.restler_static_string("stores"), primitives.restler_static_string(" HTTP/1.1\r\n"), primitives.restler_static_string("Accept: application/json\r\n"), primitives.restler_static_string("Host: localhost:8888\r\n"), primitives.restler_refreshable_authentication_token( "authentication_token_tag"), primitives.restler_static_string("\r\n"), ], requestId="/stores") req_collection.add_request(request) # Endpoint: /stores/{storeId}/order, method: Post
raise ResponseParsingException( "Exception parsing response, data was not valid json: {}".format( error)) try: temp_123 = str(data["name"]) except Exception as error: pass if temp_123: dependencies.set_variable("_namespaceruletest_put_name", temp_123) req_collection = requests.RequestCollection([]) request = requests.Request([ primitives.restler_static_string("GET "), primitives.restler_static_string("/"), primitives.restler_static_string("city"), primitives.restler_static_string(" HTTP/1.1\r\n"), primitives.restler_refreshable_authentication_token( "authentication_token_tag"), primitives.restler_static_string("\r\n") ], requestId="/city") req_collection.add_request(request) request = requests.Request([ primitives.restler_static_string("PUT "), primitives.restler_static_string("/"), primitives.restler_static_string("city"), primitives.restler_static_string("/"),