diff --git a/tntfuzzer/core/curlcommand.py b/tntfuzzer/core/curlcommand.py index aa03ae7..312efe0 100644 --- a/tntfuzzer/core/curlcommand.py +++ b/tntfuzzer/core/curlcommand.py @@ -3,7 +3,7 @@ class CurlCommand: - def __init__(self, url, method, data, headers, ignore_tls=False): + def __init__(self, url, method, data, headers, ignore_tls=False, proxy=None): self.url = url self.method = method self.data = data @@ -13,13 +13,18 @@ def __init__(self, url, method, data, headers, ignore_tls=False): self.ignore_tls = "-k " # short for --insecure else: self.ignore_tls = "" + + if proxy: + self.proxy = "--proxy " + proxy + else: + self.proxy = "" def get(self): if not self.data or len(self.data) < 1: - curl_command = "curl " + self.ignore_tls + "-X" + self.method.upper() + " " + self.generate_headers() \ + curl_command = "curl " + self.ignore_tls + self.proxy + " -X" + self.method.upper() + " " + self.generate_headers() \ + " " + self.url else: - curl_command = "curl " + self.ignore_tls + "-X" + self.method.upper() + " " + \ + curl_command = "curl " + self.ignore_tls + self.proxy + " -X" + self.method.upper() + " " + \ self.generate_headers() + " -d '" + self.data + "' " + self.url return curl_command diff --git a/tntfuzzer/core/httpoperation.py b/tntfuzzer/core/httpoperation.py index 573190d..47f9e92 100644 --- a/tntfuzzer/core/httpoperation.py +++ b/tntfuzzer/core/httpoperation.py @@ -10,7 +10,7 @@ class HttpOperation: - def __init__(self, op_code, host_basepath, path, op_infos, headers, replicator, use_fuzzing=True, ignore_tls=False): + def __init__(self, op_code, host_basepath, path, op_infos, headers, replicator, use_fuzzing=True, ignore_tls=False, proxy=None): self.op_code = op_code self.url = host_basepath.rstrip("/") + "/" + path.lstrip("/") self.op_infos = op_infos @@ -20,6 +20,8 @@ def __init__(self, op_code, host_basepath, path, op_infos, headers, replicator, self.request_body = None self.headers = headers self.ignore_tls = ignore_tls + self.proxies = {'http':proxy, 'https':proxy} + #self.proxies = {'http':'http://host.docker.internal:8081', 'https':'http://host.docker.internal:8081'} self.random = Random() def fuzz(self, json_str): @@ -42,14 +44,21 @@ def execute(self): if 'parameters' in self.op_infos: for parameter in self.op_infos['parameters']: # catch path parameters and replace them in url - if 'path' == parameter['in']: - if 'type' in parameter: - parameter_type = parameter['type'] - elif 'type' in parameter['schema']: - parameter_type = parameter['schema']['type'] - else: - parameter_type = parameter['schema']['$ref'].split('/')[-1] - url = self.replace_url_parameter(url, parameter['name'], parameter_type) + + # sometimes KeyError is thrown here + try: + if 'path' == parameter['in']: + if 'type' in parameter: + parameter_type = parameter['type'] + elif 'type' in parameter['schema']: + parameter_type = parameter['schema']['type'] + else: + parameter_type = parameter['schema']['$ref'].split('/')[-1] + url = self.replace_url_parameter(url, parameter['name'], parameter_type) + except KeyError: + #print("Error: no key 'in' for this parameter") + #print(parameter) + continue if 'body' == parameter['in']: self.request_body = self.create_body(parameter) @@ -76,22 +85,22 @@ def execute(self): if self.op_code == 'post': if bool(form_data): - response = requests.post(url=url, data=form_data, json=None, headers=self.headers, verify=verify_tls) + response = requests.post(url=url, data=form_data, json=None, headers=self.headers, verify=verify_tls, proxies=self.proxies) else: response = requests.post(url=url, data=None, json=self.request_body, headers=self.headers, verify=verify_tls) elif self.op_code == 'get': - response = requests.get(url=url, params=form_data, headers=self.headers, verify=verify_tls) + response = requests.get(url=url, params=form_data, headers=self.headers, verify=verify_tls, proxies=self.proxies) elif self.op_code == 'delete': - response = requests.delete(url=url, headers=self.headers, verify=verify_tls) + response = requests.delete(url=url, headers=self.headers, verify=verify_tls, proxies=self.proxies) elif self.op_code == 'put': - response = requests.put(url=url, data=form_data, headers=self.headers, verify=verify_tls) + response = requests.put(url=url, data=form_data, headers=self.headers, verify=verify_tls, proxies=self.proxies) elif self.op_code == 'patch': - response = requests.patch(url=url, data=form_data, headers=self.headers, verify=verify_tls) + response = requests.patch(url=url, data=form_data, headers=self.headers, verify=verify_tls, proxies=self.proxies) else: response = None diff --git a/tntfuzzer/tntfuzzer.py b/tntfuzzer/tntfuzzer.py index eb7e5fd..20ccab4 100644 --- a/tntfuzzer/tntfuzzer.py +++ b/tntfuzzer/tntfuzzer.py @@ -23,7 +23,7 @@ class TntFuzzer: def __init__(self, url, iterations, headers, log_unexpected_errors_only, max_string_length, use_string_pattern, ignore_tls=False, - host=None, basepath=None, ignored_paths=[]): + host=None, basepath=None, ignored_paths=[], proxy=None): self.url = url self.iterations = iterations self.headers = headers @@ -34,6 +34,7 @@ def __init__(self, url, iterations, headers, log_unexpected_errors_only, self.host = host self.basepath = basepath self.ignored_paths = ignored_paths + self.proxy = proxy if self.ignore_tls: # removes warnings for insecure connections @@ -148,14 +149,14 @@ def start(self): 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) + headers=self.headers, ignore_tls=self.ignore_tls, proxy=self.proxy) 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) + self.ignore_tls, proxy=self.proxy) # log to screen for now self.log_operation(operation.op_code, response.url, log, curlcommand) @@ -233,6 +234,10 @@ def main(): parser.add_argument('--ignored-paths', type=json.loads, dest='ignored-paths', default=[], help='List of the API paths to exclude from fuzzing.') + parser.add_argument('--proxy', dest='proxy', default=None, + help='HTTP proxy server address, e.g. http://127.0.0.1:8080. ' + 'Use in combination with --ignore-cert-errors for proxies like Burp to work.') + args = vars(parser.parse_args()) if args['url'] is None: @@ -241,7 +246,8 @@ def main(): tnt = TntFuzzer(url=args['url'], iterations=args['iterations'], headers=args['headers'], log_unexpected_errors_only=not args['log_all'], use_string_pattern=args['string-patterns'], max_string_length=args['max-random-string-len'], ignore_tls=args["ignore-tls"], - host=args["host"], basepath=args["basepath"], ignored_paths=args['ignored-paths']) + host=args["host"], basepath=args["basepath"], ignored_paths=args['ignored-paths'], + proxy=args['proxy']) try: tnt.start() except SchemaException: