forked from sqlmapproject/sqlmap
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsqlmapcli.py
More file actions
executable file
·285 lines (248 loc) · 9.04 KB
/
sqlmapcli.py
File metadata and controls
executable file
·285 lines (248 loc) · 9.04 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
#!/usr/bin/env python3
"""
SQLMap CLI - A beautiful CLI wrapper for sqlmap
Automates comprehensive SQL injection testing with a single command
"""
import sys
import argparse
import json
from pathlib import Path
# Add the current directory to path so we can import from sql_cli
sys.path.append(str(Path(__file__).parent))
try:
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt, Confirm
except ImportError:
print("Error: 'rich' library is required. Install it with: pip install rich")
sys.exit(1)
from sql_cli.scanner import SQLMapScanner
from sql_cli.utils import SQLMAP_PATH
from sql_cli.ui import print_banner
console = Console()
def interactive_mode(scanner: SQLMapScanner):
"""Interactive mode for user input"""
console.print()
console.print(
Panel(
"[cyan]Interactive Mode[/cyan]\n[dim]Enter target details for SQL injection testing[/dim]",
border_style="cyan",
)
)
url = Prompt.ask("\n[cyan]Enter target URL[/cyan]")
# Ask if this is a POST request
has_data = Confirm.ask(
"[cyan]Does this request require POST data/body?[/cyan]", default=False
)
data = None
if has_data:
console.print("\n[dim]Examples:[/dim]")
console.print(
'[dim] JSON: {"email":"test@example.com","password":"pass123"}[/dim]'
)
console.print("[dim] Form: username=admin&password=secret[/dim]")
data = Prompt.ask("\n[cyan]Enter POST data/body[/cyan]")
# Ask for custom headers
has_headers = Confirm.ask(
"[cyan]Do you need to add custom headers (Auth, etc.)?[/cyan]", default=False
)
headers = None
if has_headers:
console.print("\n[dim]Example:[/dim]")
console.print(
'[dim] "Authorization: Bearer token; Cookie: PHPSESSID=..."[/dim]'
)
headers = Prompt.ask("\n[cyan]Enter headers[/cyan]")
scan_type = Prompt.ask(
"\n[cyan]Select scan type[/cyan]",
choices=["quick", "comprehensive"],
default="quick",
)
if scan_type == "quick":
# Input validation for level and risk
while True:
try:
level_str = Prompt.ask("[cyan]Test level (1-5)[/cyan]", default="1")
level = int(level_str)
if 1 <= level <= 5:
break
console.print("[red]Level must be between 1 and 5[/red]")
except ValueError:
console.print("[red]Please enter a valid number[/red]")
while True:
try:
risk_str = Prompt.ask("[cyan]Test risk (1-3)[/cyan]", default="1")
risk = int(risk_str)
if 1 <= risk <= 3:
break
console.print("[red]Risk must be between 1 and 3[/red]")
except ValueError:
console.print("[red]Please enter a valid number[/red]")
scanner.quick_scan(url, level, risk, data=data, headers=headers)
else:
# Input validation for max_level and max_risk
while True:
try:
max_level_str = Prompt.ask("[cyan]Maximum test level (1-5)[/cyan]", default="5")
max_level = int(max_level_str)
if 1 <= max_level <= 5:
break
console.print("[red]Level must be between 1 and 5[/red]")
except ValueError:
console.print("[red]Please enter a valid number[/red]")
while True:
try:
max_risk_str = Prompt.ask("[cyan]Maximum test risk (1-3)[/cyan]", default="3")
max_risk = int(max_risk_str)
if 1 <= max_risk <= 3:
break
console.print("[red]Risk must be between 1 and 3[/red]")
except ValueError:
console.print("[red]Please enter a valid number[/red]")
scanner.comprehensive_scan(url, max_level, max_risk, data=data, headers=headers)
def main():
parser = argparse.ArgumentParser(
description="SQLMap CLI - Beautiful automated SQL injection testing",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Quick scan with default settings (GET parameter)
python sqlmapcli.py -u "https://demo.owasp-juice.shop/rest/products/search?q=test"
# Test with POST data (JSON)
python sqlmapcli.py -u "https://demo.owasp-juice.shop/rest/user/login" --data='{"email":"test@example.com","password":"pass123"}'
# Comprehensive scan (all risk and level combinations)
python sqlmapcli.py -u "https://demo.owasp-juice.shop/rest/products/search?q=test" --comprehensive
# Batch mode - test multiple endpoints from JSON file
python sqlmapcli.py -b endpoints.json --level 2 --risk 2
# Interactive mode
python sqlmapcli.py --interactive
""",
)
parser.add_argument(
"-u", "--url", help='Target URL (e.g., "http://example.com/page?id=1")'
)
parser.add_argument(
"--comprehensive", action="store_true", help="Run comprehensive scan"
)
parser.add_argument(
"--level",
type=int,
default=1,
choices=[1, 2, 3, 4, 5],
help="Level (1-5, default: 1)",
)
parser.add_argument(
"--risk", type=int, default=1, choices=[1, 2, 3], help="Risk (1-3, default: 1)"
)
parser.add_argument(
"--max-level",
type=int,
default=5,
choices=[1, 2, 3, 4, 5],
help="Max level for comprehensive",
)
parser.add_argument(
"--max-risk",
type=int,
default=3,
choices=[1, 2, 3],
help="Max risk for comprehensive",
)
parser.add_argument(
"--technique",
type=str,
default="BEUSTQ",
help="SQL techniques (default: BEUSTQ)",
)
parser.add_argument("--data", type=str, help="POST data")
parser.add_argument("--headers", type=str, help="Extra headers")
parser.add_argument("--raw", action="store_true", help="Show raw sqlmap output")
parser.add_argument(
"--verbose", type=int, choices=[0, 1, 2, 3, 4, 5, 6], help="Verbosity (0-6)"
)
parser.add_argument(
"-i", "--interactive", action="store_true", help="Interactive mode"
)
parser.add_argument("-b", "--batch-file", type=str, help="Path to batch JSON")
parser.add_argument(
"-c",
"--concurrency",
type=int,
default=0,
help="Number of concurrent scans (default: 0 for auto-scale)",
)
parser.add_argument("--no-logs", action="store_true", help="Disable logs")
args = parser.parse_args()
scanner = SQLMapScanner(enable_logging=not args.no_logs)
print_banner()
if not SQLMAP_PATH.exists():
console.print(
f"[bold red]Error: sqlmap.py not found at {SQLMAP_PATH}[/bold red]"
)
sys.exit(1)
if args.interactive:
interactive_mode(scanner)
return
if args.batch_file:
try:
with open(args.batch_file, "r") as f:
endpoints = json.load(f)
if not isinstance(endpoints, list):
console.print(
"[bold red]Error: Batch file must contain a JSON array[/bold red]"
)
sys.exit(1)
verbose_level = args.verbose if args.verbose is not None else 1
scanner.batch_scan(
endpoints,
level=args.level,
risk=args.risk,
concurrency=args.concurrency,
verbose=verbose_level,
)
return
except FileNotFoundError:
console.print(
f"[bold red]Error: Batch file not found: {args.batch_file}[/bold red]"
)
sys.exit(1)
except json.JSONDecodeError as e:
console.print(
f"[bold red]Error: Invalid JSON in batch file '{args.batch_file}': {e}[/bold red]"
)
sys.exit(1)
except PermissionError:
console.print(
f"[bold red]Error: Permission denied when reading batch file: {args.batch_file}[/bold red]"
)
sys.exit(1)
except Exception as e:
console.print(f"[bold red]Error loading batch file: {e}[/bold red]")
sys.exit(1)
if not args.url:
console.print("[bold red]Error: URL is required[/bold red]")
parser.print_help()
sys.exit(1)
verbose_level = args.verbose if args.verbose is not None else 1
if args.comprehensive:
scanner.comprehensive_scan(
args.url,
max_level=args.max_level,
max_risk=args.max_risk,
techniques=args.technique,
data=args.data,
headers=args.headers,
verbose=verbose_level,
)
else:
scanner.quick_scan(
args.url,
level=args.level,
risk=args.risk,
data=args.data,
headers=args.headers,
raw=args.raw,
verbose=verbose_level,
)
if __name__ == "__main__":
main()