Sublist3r/live.py

156 lines
6.0 KiB
Python

#!/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()