mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-01-11 19:21:11 +03:00
- Implemented a new UI module (sql_cli/ui.py) for displaying banners and scan results using the Rich library. - Created utility functions in sql_cli/utils.py for generating log filenames and saving logs. - Refactored sqlmapcli.py to utilize the new UI and utility functions, enhancing the interactive mode and scan processes. - Added support for custom headers and POST data in the interactive mode. - Introduced a test endpoints JSON file (test_endpoints.json) for batch testing.
193 lines
6.8 KiB
Python
Executable File
193 lines
6.8 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 --concurrency 10
|
|
|
|
# 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=5, help='Concurrency (default: 5)')
|
|
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()
|