mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-01-12 11:41:05 +03:00
235 lines
7.1 KiB
Python
Executable File
235 lines
7.1 KiB
Python
Executable File
#!/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":
|
|
level = int(Prompt.ask("[cyan]Test level (1-5)[/cyan]", default="1"))
|
|
risk = int(Prompt.ask("[cyan]Test risk (1-3)[/cyan]", default="1"))
|
|
scanner.quick_scan(url, level, risk, data=data, headers=headers)
|
|
else:
|
|
max_level = int(
|
|
Prompt.ask("[cyan]Maximum test level (1-5)[/cyan]", default="5")
|
|
)
|
|
max_risk = int(Prompt.ask("[cyan]Maximum test risk (1-3)[/cyan]", default="3"))
|
|
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 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()
|