1
+ import requests
2
+ # import re # uncomment this for DVWA
3
+ from bs4 import BeautifulSoup as bs
4
+ from urllib .parse import urljoin
5
+ from pprint import pprint
6
+
7
+ s = requests .Session ()
8
+ s .headers ["User-Agent" ] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36"
9
+
10
+ # below code is for logging to your local DVWA
11
+ # uncomment it if you want to use this on DVWA
12
+ # login_payload = {
13
+ # "username": "admin",
14
+ # "password": "password",
15
+ # "Login": "Login",
16
+ # }
17
+ # # change URL to the login page of your DVWA login URL
18
+ # login_url = "http://localhost:8080/DVWA-master/login.php"
19
+
20
+ # # login
21
+ # r = s.get(login_url)
22
+ # token = re.search("user_token'\s*value='(.*?)'", r.text).group(1)
23
+ # login_payload['user_token'] = token
24
+ # s.post(login_url, data=login_payload)
25
+
26
+
27
+ def get_all_forms (url ):
28
+ """Given a `url`, it returns all forms from the HTML content"""
29
+ soup = bs (s .get (url ).content , "html.parser" )
30
+ return soup .find_all ("form" )
31
+
32
+
33
+ def get_form_details (form ):
34
+ """
35
+ This function extracts all possible useful information about an HTML `form`
36
+ """
37
+ details = {}
38
+ # get the form action (target url)
39
+ try :
40
+ action = form .attrs .get ("action" ).lower ()
41
+ except :
42
+ action = None
43
+ # get the form method (POST, GET, etc.)
44
+ method = form .attrs .get ("method" , "get" ).lower ()
45
+ # get all the input details such as type and name
46
+ inputs = []
47
+ for input_tag in form .find_all ("input" ):
48
+ input_type = input_tag .attrs .get ("type" , "text" )
49
+ input_name = input_tag .attrs .get ("name" )
50
+ input_value = input_tag .attrs .get ("value" , "" )
51
+ inputs .append ({"type" : input_type , "name" : input_name , "value" : input_value })
52
+ # put everything to the resulting dictionary
53
+ details ["action" ] = action
54
+ details ["method" ] = method
55
+ details ["inputs" ] = inputs
56
+ return details
57
+
58
+
59
+ def is_vulnerable (response ):
60
+ """A simple boolean function that determines whether a page
61
+ is SQL Injection vulnerable from its `response`"""
62
+ errors = {
63
+ # MySQL
64
+ "you have an error in your sql syntax;" ,
65
+ "warning: mysql" ,
66
+ # SQL Server
67
+ "unclosed quotation mark after the character string" ,
68
+ # Oracle
69
+ "quoted string not properly terminated" ,
70
+ }
71
+ for error in errors :
72
+ # if you find one of these errors, return True
73
+ if error in response .content .decode ().lower ():
74
+ return True
75
+ # no error detected
76
+ return False
77
+
78
+
79
+ def scan_sql_injection (url ):
80
+ # test on URL
81
+ for c in "\" '" :
82
+ # add quote/double quote character to the URL
83
+ new_url = f"{ url } { c } "
84
+ print ("[!] Trying" , new_url )
85
+ # make the HTTP request
86
+ res = s .get (new_url )
87
+ if is_vulnerable (res ):
88
+ # SQL Injection detected on the URL itself,
89
+ # no need to preceed for extracting forms and submitting them
90
+ print ("[+] SQL Injection vulnerability detected, link:" , new_url )
91
+ return
92
+ # test on HTML forms
93
+ forms = get_all_forms (url )
94
+ print (f"[+] Detected { len (forms )} forms on { url } ." )
95
+ for form in forms :
96
+ form_details = get_form_details (form )
97
+ for c in "\" '" :
98
+ # the data body we want to submit
99
+ data = {}
100
+ for input_tag in form_details ["inputs" ]:
101
+ if input_tag ["value" ] or input_tag ["type" ] == "hidden" :
102
+ # any input form that has some value or hidden,
103
+ # just use it in the form body
104
+ try :
105
+ data [input_tag ["name" ]] = input_tag ["value" ] + c
106
+ except :
107
+ pass
108
+ elif input_tag ["type" ] != "submit" :
109
+ # all others except submit, use some junk data with special character
110
+ data [input_tag ["name" ]] = f"test{ c } "
111
+ # join the url with the action (form request URL)
112
+ url = urljoin (url , form_details ["action" ])
113
+ if form_details ["method" ] == "post" :
114
+ res = s .post (url , data = data )
115
+ elif form_details ["method" ] == "get" :
116
+ res = s .get (url , params = data )
117
+ # test whether the resulting page is vulnerable
118
+ if is_vulnerable (res ):
119
+ print ("[+] SQL Injection vulnerability detected, link:" , url )
120
+ print ("[+] Form:" )
121
+ pprint (form_details )
122
+ break
123
+
124
+ if __name__ == "__main__" :
125
+ import sys
126
+ url = sys .argv [1 ]
127
+ scan_sql_injection (url )
0 commit comments