def test_empty_data(self): method = "get" url = "http://example.com/api/v2/list" data = "" headers = json.loads('{}') curlcommand = CurlCommand(url, method, data, headers) self.assertEqual(curlcommand.get(), "curl -XGET -H \"Content-type: application/json\" " "http://example.com/api/v2/list")
def test_generate_headers(self): method = "get" url = "http://example.com/api/v2/list" data = "" headers = '{ \"X-API-Key\": \"abcdef12345\", \"user-agent\": \"tntfuzzer\" }' expected_result = u'-H \"Content-type: application/json\" -H \"X-API-Key\": \"abcdef12345\" ' \ u'-H \"user-agent\": \"tntfuzzer\"' curlcommand = CurlCommand(url, method, data, headers) self.assertEquals(curlcommand.generate_headers(), expected_result)
def test_get_method(self): method = "get" url = "http://example.com/api/v2/test" data = "{\"id\": 1, \"name\": \"Foo\"}" headers = json.loads('{}') curlcommand = CurlCommand(url, method, data, headers) self.assertEqual(curlcommand.get(), "curl -XGET -H \"Content-type: application/json\" -d " "'{\"id\": 1, \"name\": \"Foo\"}' http://example.com/api/v2/test")
def test_generate_headers_returns_contenttype_only_when_headers_nonetype(self): method = "get" url = "http://example.com/api/v2/list" data = "" expected_result = u'-H \"Content-type: application/json\"' curlcommand = CurlCommand(url, method, data, None) self.assertEqual(curlcommand.generate_headers(), expected_result)
def test_post_method(self): method = "pOsT" url = "http://example.com/api/post" data = "{\"id\": 2, \"name\": \"Bar\"}" headers = u'{}' curlcommand = CurlCommand(url, method, data, headers) self.assertEquals( curlcommand.get(), "curl -XPOST -H \"Content-type: application/json\" -d " "'{\"id\": 2, \"name\": \"Bar\"}' http://example.com/api/post")
def start(self): print('Fetching open API from: ' + self.url) # Try to find the protocol, host and basePath from the Swagger spec. # host and schemes can be omitted, and the "standard" says you should use the spec's URL to derive them. # https://swagger.io/docs/specification/2-0/api-host-and-base-path/ schemes = [] host = None basePath = None try: spec = self.get_swagger_spec(self.url) specURL = urlparse(self.url) except json.JSONDecodeError: error_cant_connect() if 'openapi' not in spec: if 'swagger' not in spec: self.log_operation( None, self.url, { "status_code": "000", "documented_reason": "Specification: no version string found", "body": "Specification: no version string found in Swagger spec" }, '') raise SchemaException if not spec['swagger'].startswith('2'): self.log_operation( None, self.url, { "status_code": "000", "documented_reason": "Specification: wrong specification version", "body": "Specification: version in swagger spec not supported" }, '') raise SchemaException elif not spec['openapi'].startswith('3'): self.log_operation( None, self.url, { "status_code": "000", "documented_reason": "Specification: wrong specification version", "body": "Specification: version in openapi spec not supported" }, '') raise SchemaException baseUris = [] if 'servers' in spec and len(spec['servers']) > 0: for server in spec['servers']: baseUris.append(server['url']) elif 'schemes' in spec: schemes = spec['schemes'] else: # fake the array we'd find in the spec schemes.append(specURL.scheme) self.log_operation( None, self.url, { "status_code": "000", "documented_reason": "Specification: no schemes entry, fallback to spec URL scheme", "body": "Specification: host entry not present in Swagger spec" }, '') if len(baseUris) == 0: if self.host: host = self.host elif 'host' in spec: host = spec['host'] else: host = specURL.netloc self.log_operation( None, self.url, { "status_code": "000", "documented_reason": "Specification: no host entry, fallback to spec URL host", "body": "Specification: schemes entry not present in Swagger spec" }, '') # There is no nice way to derive the basePath from the spec's URL. They *have* to include it if 'basePath' not in spec: self.log_operation( None, self.url, { "status_code": "000", "documented_reason": "Specification: basePath entry missing from Swagger spec", "body": "Specification Error: basePath entry missing from Swagger spec" }, '') raise SchemaException basePath = self.basepath if self.basepath else spec['basePath'] host_basepath = host + basePath for protocol in schemes: baseUris.append(protocol + '://' + host_basepath) paths = spec['paths'] if 'definitions' in spec: type_definitions = spec['definitions'] elif 'components' in spec and 'schemas' in spec['components']: type_definitions = spec['components']['schemas'] else: self.log_operation( None, self.url, { "status_code": "000", "documented_reason": "Specification: type definitions missing from Swagger spec", "body": "Specification Error: type definitions missing from Swagger spec" }, '') raise SchemaException # the specifcation can list multiple schemes (http, https, ws, wss) - all should be tested. # Each scheme is a potentially different end point replicator = Replicator(type_definitions, self.use_string_pattern, True, self.max_string_length) for baseUri in baseUris: for path_key in paths.keys(): if path_key in self.ignored_paths: continue path = paths[path_key] for op_code in path.keys(): operation = HttpOperation(op_code, baseUri, path_key, replicator=replicator, op_infos=path[op_code], use_fuzzing=True, headers=self.headers, ignore_tls=self.ignore_tls) for _ in range(self.iterations): response = operation.execute() validator = ResultValidator() log = validator.evaluate( response, path[op_code]['responses'], self.log_unexpected_errors_only) curlcommand = CurlCommand(response.url, operation.op_code, operation.request_body, self.headers, self.ignore_tls) # log to screen for now self.log_operation(operation.op_code, response.url, log, curlcommand) return True
def start(self): print('Fetching open API from: ' + self.url) # Try to find the protocol, host and basePath from the Swagger spec. # host and schemes can be omitted, and the "standard" says you should use the spec's URL to derive them. # https://swagger.io/docs/specification/2-0/api-host-and-base-path/ schemes = [] host = None basePath = None client = SwaggerClient.from_url(self.url) spec = client.swagger_spec.spec_dict specURL = urlparse(self.url) if 'schemes' in spec: schemes = spec['schemes'] else: # fake the array we'd find in the spec schemes.append(specURL.scheme) self.log_operation( None, self.url, { "status_code": "000", "documented_reason": "Specification: no schemes entry, fallback to spec URL scheme", "body": "Specification: host entry not present in Swagger spec" }, '') if 'host' in spec: host = spec['host'] else: host = specURL.netloc self.log_operation( None, self.url, { "status_code": "000", "documented_reason": "Specification: no host entry, fallback to spec URL host", "body": "Specification: schemes entry not present in Swagger spec" }, '') # There is no nice way to derive the basePath from the spec's URL. They *have* to include it if 'basePath' not in spec: self.log_operation( None, self.url, { "status_code": "000", "body": "Specification Error: basePath entry missing from Swagger spec" }, '') host_basepath = host + spec['basePath'] paths = spec['paths'] type_definitions = spec['definitions'] # the specifcation can list multiple schemes (http, https, ws, wss) - all should be tested. # Each scheme is a potentially different end point for protocol in schemes: for path_key in paths.keys(): path = paths[path_key] for op_code in path.keys(): operation = HttpOperation(op_code, protocol + '://' + host_basepath, path_key, op_infos=path[op_code], use_fuzzing=True, headers=self.headers) for x in range(self.iterations): response = operation.execute(type_definitions) validator = ResultValidator() log = validator.evaluate( response, path[op_code]['responses'], self.log_unexpected_errors_only) curlcommand = CurlCommand(response.url, operation.op_code, operation.request_body, self.headers) # log to screen for now self.log_operation(operation.op_code, response.url, log, curlcommand)