diff --git a/live.py b/live.py new file mode 100644 index 0000000..7afccd2 --- /dev/null +++ b/live.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# Nmap Integrator for Subdomains - v1.0 +# Integrates Nmap port scanning with subdomain lists (e.g., from Sublist3r). +# Filters live subdomains (DNS + HTTP check), then scans for open ports. +# Usage: python nmap_integrator.py -i subdomains.txt -o nmap_results.xml +# Requires: pip install requests dnspython; nmap installed on system + +import argparse +import sys +import subprocess +import xml.etree.ElementTree as ET +from concurrent.futures import ThreadPoolExecutor, as_completed +import requests +import dns.resolver +import dns.exception +import tempfile +import os + +def is_dns_live(subdomain): + """Check if subdomain resolves to an IP.""" + try: + dns.resolver.resolve(subdomain, 'A') + return True + except (dns.exception.DNSException, Exception): + return False + +def is_http_live(subdomain, timeout=5): + """Check if subdomain responds to HTTP/HTTPS.""" + for protocol in ['http', 'https']: + url = f"{protocol}://{subdomain}" + try: + resp = requests.get(url, timeout=timeout, verify=False, allow_redirects=True) + if resp.status_code > 0: + return True + except requests.RequestException: + continue + return False + +def check_live(subdomain, dns_only=False, timeout=5): + """Full live check: DNS + optional HTTP.""" + if not is_dns_live(subdomain): + return False + if dns_only: + return True + return is_http_live(subdomain, timeout) + +def run_nmap_scan(subdomain, ports='top-1000', output_dir=None, output_format='xml'): + """Run Nmap scan on a subdomain and return results.""" + if output_dir: + output_file = os.path.join(output_dir, f"{subdomain}_nmap.{output_format}") + else: + output_file = f"{subdomain}_nmap.{output_format}" + + cmd = [ + 'nmap', '-sV', '-sC', # Service version + script scan + f'-p{ports}', # Ports to scan + f'--open', # Only show open ports + f'-o{output_format}', output_file, # Output format + subdomain + ] + + try: + result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) # 5-min timeout per host + if result.returncode == 0: + print(f"[SCAN] {subdomain}: Scan complete. Output: {output_file}") + return output_file + else: + print(f"[ERROR] {subdomain}: Nmap failed - {result.stderr}") + return None + except subprocess.TimeoutExpired: + print(f"[TIMEOUT] {subdomain}: Scan timed out") + return None + except FileNotFoundError: + print("[ERROR] Nmap not found. Install Nmap and ensure it's in PATH.", file=sys.stderr) + sys.exit(1) + +def parse_nmap_xml(xml_file): + """Parse Nmap XML for summary (open ports).""" + try: + tree = ET.parse(xml_file) + root = tree.getroot() + host = root.find('host') + if host is None: + return [] + ports = [] + for port in host.findall('.//port[@state="open"]'): + port_id = port.get('portid') + service = port.find('service') + service_name = service.get('name') if service is not None else 'unknown' + ports.append(f"{port_id}/{service_name}") + return ports + except ET.ParseError: + return [] + +def main(): + parser = argparse.ArgumentParser(description="Integrate Nmap port scanning with subdomain lists.") + parser.add_argument('-i', '--input', required=True, help="Input file with subdomains (one per line)") + parser.add_argument('-o', '--output-dir', help="Directory for Nmap output files (default: current dir)") + parser.add_argument('-t', '--threads', type=int, default=10, help="Threads for live check (default: 10); Nmap is sequential") + parser.add_argument('--dns-only', action='store_true', help="Only check DNS (faster, skip HTTP)") + parser.add_argument('--ports', default='top-1000', help="Nmap ports (default: top-1000)") + parser.add_argument('--timeout', type=int, default=5, help="HTTP timeout in seconds (default: 5)") + parser.add_argument('--summary', action='store_true', help="Print summary of open ports after scanning") + args = parser.parse_args() + + # Read subdomains + try: + with open(args.input, 'r') as f: + subdomains = [line.strip() for line in f if line.strip()] + except FileNotFoundError: + print(f"Error: Input file '{args.input}' not found.", file=sys.stderr) + sys.exit(1) + + print(f"[INFO] Filtering {len(subdomains)} subdomains for live hosts...") + + # Filter live subdomains + live_subdomains = [] + with ThreadPoolExecutor(max_workers=args.threads) as executor: + futures = {executor.submit(check_live, sub, args.dns_only, args.timeout): sub for sub in subdomains} + for future in as_completed(futures): + sub = futures[future] + try: + if future.result(): + live_subdomains.append(sub) + print(f"[LIVE] {sub}") + else: + print(f"[DEAD] {sub}") + except Exception as e: + print(f"[ERROR] {sub}: {e}", file=sys.stderr) + + print(f"[INFO] Found {len(live_subdomains)} live subdomains. Starting Nmap scans...") + + # Create output dir if specified + if args.output_dir: + os.makedirs(args.output_dir, exist_ok=True) + + # Run Nmap sequentially (to avoid overwhelming the network; parallelize if needed) + scan_results = {} + for subdomain in live_subdomains: + output_file = run_nmap_scan(subdomain, args.ports, args.output_dir) + if output_file and args.summary: + open_ports = parse_nmap_xml(output_file) + if open_ports: + scan_results[subdomain] = open_ports + print(f"[PORTS] {subdomain}: {', '.join(open_ports)}") + + if args.summary and scan_results: + print("\n[SUMMARY] Open Ports by Host:") + for host, ports in scan_results.items(): + print(f"{host}: {', '.join(ports)}") + + print(f"[COMPLETE] Scanned {len(live_subdomains)} hosts. Check output files for details.") + +if __name__ == "__main__": + main()