1
+ # pylint: disable=line-too-long,C0114
2
+
1
3
import argparse
4
+ import sys
2
5
import requests
3
6
4
- class ValidateMethodsAction (argparse .Action ):
7
+ def validatemethod (value ):
8
+ r"""Validates the methods passed into the script via the -m parameter
9
+ """
10
+
11
+ methods = list (dict .fromkeys (value .split (',' )))
12
+ if methods [0 ] == 'all' :
13
+ return 'get' , 'post' , 'delete' , 'put'
14
+ for method in methods :
15
+ if method .lower () not in ['get' ,'post' ,'put' ,'delete' ]:
16
+ raise argparse .ArgumentTypeError (f"argument -m/--method: invalid choice(s): '{ methods } ' (choose from 'get', 'post', 'put', 'delete' or choose 'all')" )
17
+ return methods
18
+
19
+ def formatter (prog ):
20
+ r"""Formats the help display of the script to have a certain width
21
+ """
5
22
6
- def __call__ (self , parser , namespace , values , option_string = None ):
7
- methods = list (dict .fromkeys (values [0 ].split (',' )))
8
- if methods [0 ] != 'all' :
9
- for method in methods :
10
- if method .lower () not in ['get' ,'post' ,'put' ,'delete' ]:
11
- parser .error (f"argument -m/--method: invalid choice(s): '{ methods } ' (choose from 'get', 'post', 'put', 'delete' or choose 'all')" )
12
- else :
13
- methods = ['get' , 'post' , 'delete' , 'put' ]
14
- setattr (namespace , self .dest , methods )
23
+ return argparse .HelpFormatter (prog , max_help_position = 64 )
15
24
16
25
def error (message ):
26
+ r"""Is called whenever an error is handled by the script
27
+
28
+ :param message: Error message to be printed.
29
+ """
17
30
18
31
print (message )
19
- exit ()
32
+ sys . exit ()
20
33
21
34
def process_response (request , match_string , default_testing_length , verbose ):
35
+ r"""Processes the response of the selected method and print it out
36
+
37
+ :param request: The request's:class:`Response <Response>` object.
38
+ :param default_testing_length: The default_testing_length that is tested against.
39
+ :param verbose: Enable/disable verbose output.
40
+ :param match_string: The string to match within the response text.
41
+ """
22
42
23
43
response = request .text
24
44
if match_string is not None :
@@ -31,51 +51,66 @@ def process_response(request, match_string, default_testing_length, verbose):
31
51
if verbose :
32
52
print (f"[VERBOSE] { request .request .method } { str (len (response ))} { request .request .url } " )
33
53
34
- def prepare_request (methods , url , default_testing_length , verbose , ignore_ssl_verification , match_string ):
54
+ def prepare_request (methods : list , url : str , match_string : str , timeout : float , default_testing_length : int , verbose : bool , ignore_ssl_verification : bool ):
55
+ r"""Prepare the requests to be sent
56
+
57
+ :param methods: The methods set for the current URL.
58
+ :param url: The current URL to be reqquested.
59
+ :param default_testing_length: The default_testing_length that is tested against.
60
+ :param verbose: Enable/disable verbose output.
61
+ :param timeout: The amount of seconds after a request times out.
62
+ :param ignore_ssl_verification: Ignore SSL verification.
63
+ :param match_string: The string to match within the response text.
64
+ """
35
65
36
66
for method in methods :
37
67
try :
38
- request = requests .request (method , url , verify = ignore_ssl_verification )
68
+ request = requests .request (method , url , timeout = timeout , verify = ignore_ssl_verification )
39
69
process_response (request , match_string , default_testing_length , verbose )
40
70
except requests .ConnectTimeout :
41
- if verbose :
42
- print (f"[Verbose] { method } - Connection timed out - { url } " )
71
+ print (f"[Verbose] { method } - Connection timed out - { url } " )
43
72
44
- def banner ():
73
+ def banner () -> None :
74
+ r"""Prints the banner at the start of the script
75
+ """
45
76
46
77
print ("""_____________________________________________________________________
47
78
FAPI - API endpoint fuzzer v0.1
48
79
Developed by: arcan3, TheM8thy
49
- Last updated: 26 /04/2023
80
+ Last updated: 27 /04/2023
50
81
_____________________________________________________________________
51
82
""" )
52
83
53
84
def fapi ():
85
+ r"""Main function
86
+ """
54
87
55
88
banner ()
56
89
57
- formatter = lambda prog : argparse .HelpFormatter (prog ,max_help_position = 64 )
58
90
parser = argparse .ArgumentParser (formatter_class = formatter )
59
91
parser .add_argument ('-u' , '--url' , metavar = '<example url>' , type = str , help = 'Specify the target url after the -u flag.' , nargs = '+' , required = True )
60
92
parser .add_argument ('-w' , '--wordlist' , metavar = '<wordlist>' , type = argparse .FileType ('r' ), help = 'Specify your chosen wordlist after the -w flag.' , nargs = 1 , required = True )
61
- parser .add_argument ('-m' , '--method' , action = ValidateMethodsAction , metavar = '<method>' , type = str , help = 'Specify the desired request methods, accepted methods are get,post,put,delete.' , nargs = 1 , required = True )
93
+ parser .add_argument ('-m' , '--method' , metavar = '<method>' , type = validatemethod , help = 'Specify the desired request methods, accepted methods are get,post,put,delete.' , nargs = 1 , required = True )
62
94
parser .add_argument ('-dl' , '--default_testing_length' , metavar = '' , type = int , help = 'Specify the testing length thats tested against.' , default = 0 , nargs = 1 )
63
95
parser .add_argument ('-ms' , '--match_string' , metavar = '<string>' , type = str , help = 'Match a specific string within the response text.' , nargs = '+' )
96
+ parser .add_argument ('-t' , '--timeout' , metavar = '<seconds>' , type = float , help = 'Specify the amount of seconds before a request times out, defaults to 5' , default = 5 )
64
97
parser .add_argument ('-v' , '--verbose' , action = 'store_true' , help = 'Verbose mode' )
65
98
parser .add_argument ('-k' , '--ignore_certificates' , action = 'store_false' , help = 'Ignore SSL certificate verification.' )
66
99
#group = parser.add_mutually_exclusive_group(required=True)
67
- #group.add_argument('-t ', '--threading', metavar='<threads>', type=int, help='Specify number of threads to use.', nargs=1)
100
+ #group.add_argument('-th ', '--threading', metavar='<threads>', type=int, help='Specify number of threads to use.', nargs=1)
68
101
#group.add_argument('-mp', '--multiprocessing', metavar='<processes>', type=int, help='Specify number of processes to use.', nargs=1)
69
102
parser .add_argument ('--version' , action = 'version' , help = 'Show %(prog)s version number' , version = '%(prog)s 0.1' )
70
- parser ._actions [0 ].help = 'Display the help options.'
103
+ parser ._actions [0 ].help = 'Display the help options.' # pylint: disable=W0212
71
104
args = parser .parse_args ()
105
+
72
106
urls : list = args .url
73
107
wordlist = args .wordlist [0 ]
74
- methods : list = args .method
108
+ methods : list = args .method [ 0 ]
75
109
default_testing_length : int = args .default_testing_length [0 ] if isinstance (args .default_testing_length ,list ) else args .default_testing_length
76
- ignore_ssl_verification = args .ignore_certificates
110
+ ignore_ssl_verification : bool = args .ignore_certificates
77
111
match_string : list = args .match_string
78
112
verbose : bool = args .verbose
113
+ timeout : float = args .timeout
79
114
80
115
print (f"URL: { ',' .join (urls )} " )
81
116
print (f"Methods: { ',' .join ([x .upper () for x in methods ])} " )
@@ -94,6 +129,6 @@ def fapi():
94
129
for url in urls :
95
130
for endpoint in [x for x in endpoints if x [0 ].strip () not in ['#' ,'' ,'/' ]]:
96
131
request_url = f"{ url } /{ endpoint .strip ()} "
97
- prepare_request (methods , request_url , default_testing_length , verbose , ignore_ssl_verification , match_string )
132
+ prepare_request (methods , request_url , match_string , timeout , default_testing_length , verbose , ignore_ssl_verification )
98
133
99
134
fapi ()
0 commit comments