Files
live-campus-mcs-p-2027.2/Semaine_10/Jour_01/tesla_recon.py
T
2026-06-12 20:25:28 +02:00

360 lines
11 KiB
Python

"""
tesla_security_scan.py - Enhanced Security Scanner for Tesla Subdomains using Shodan API
Features:
- Read subdomains from .txt file or command line
- Query Shodan API for each host with detailed info (ports, services, versions)
- Detect CVEs using OS and service banner intelligence
- Generate structured JSON report with vulnerability analysis
- Provide executive summary review
"""
import sys
import json
import argparse
import shodan
import re
from datetime import datetime
from collections import defaultdict
def load_subdomains_from_file(file_path):
"""Load subdomains from a .txt file."""
with open(file_path, 'r', encoding='utf-8') as f:
domains = [line.strip() for line in f if line.strip()]
return domains
def search_host_shodan(ip_address, api_key):
"""Get detailed host information from Shodan API."""
try:
api = shodan.Shodan(api_key)
results = api.host(ip_address)
return {
'ip': ip_address,
'ports': [],
'services': {},
'os': results.get('os', None),
'org': results.get('org', 'Unknown'),
'last_update': datetime.now().isoformat(),
'banners': [],
'vulnerabilities': []
}
except shodan.APIError as e:
return {
'ip': ip_address,
'error': str(e),
'ports': [],
'services': {},
'os': None,
'org': 'Unknown',
'last_update': datetime.now().isoformat(),
'banners': []
}
def extract_service_info(shodan_data):
"""Extract and organize service information from Shodan data."""
services = {}
if not shodan_data or 'ports' not in shodan_data:
return services
for port_entry in shodan_data.get('ports', []):
port_num = port_entry.get('port')
banner = port_entry.get('banner', '')
service_info = {
'port': port_num,
'protocol': port_entry.get('transport', 'tcp'),
'service': port_entry.get('name', 'unknown'),
'version': port_entry.get('product') or port_entry.get('version', 'unknown'),
'banners': []
}
if banner:
try:
banner_lines = banner.split('\n')
service_info['banners'].append({
'raw': '\n'.join(banner_lines[:10]),
'hostname': port_entry.get('host', ''),
'app': port_entry.get('app', '')
})
banner_upper = banner.upper()
if 'TLS' in banner_upper or 'SSL' in banner_upper:
service_info['ssl'] = True
except Exception:
pass
services[str(port_num)] = service_info
return services
def detect_os_cves(os_string):
"""Detect CVEs mentioned in OS information."""
if not os_string:
return []
cve_pattern = r'(CVE-[0-9]{4}-[0-9]+)'
detected_cves = re.findall(cve_pattern, os_string)
os_info = {
'cves': detected_cves,
'os_type': os_string.split(' ')[0] if os_string else None,
'kernel_version': os_string.split(' (')[0].split('.')[-1] if ' (' in os_string else None
}
return [{'cve_id': cve_id, 'source': 'OS', 'description': f'Potential vulnerability in {os_string}'} for cve_id in detected_cves]
def detect_service_cves(banners):
"""Detect CVEs mentioned in service banners."""
all_cves = []
if not banners:
return all_cves
cve_pattern = r'(CVE-[0-9]{4}-[0-9]+)'
for banner_info in banners:
raw_content = banner_info.get('raw', '')
detected_cves = re.findall(cve_pattern, raw_content)
if detected_cves:
for cve_id in detected_cves:
all_cves.append({
'cve_id': cve_id,
'source': banner_info.get('app', 'Service'),
'port': banner_info.get('port', 0),
'description': f'Potential vulnerability found in {banner_info.get("hostname", "service")}'
})
return all_cves
def analyze_host_vulnerabilities(host_data):
"""Analyze a host for vulnerabilities from OS and services."""
detected_cves = []
os_cves = detect_os_cves(host_data.get('os'))
detected_cves.extend(os_cves)
service_cves = detect_service_cves(host_data.get('banners', []))
detected_cves.extend(service_cves)
host_data['vulnerabilities'] = detected_cves
return host_data
def scan_subdomain(subdomain, api_key):
"""Scan all hosts associated with a subdomain."""
api = shodan.Shodan(api_key)
try:
results = api.search(f"hostname:{subdomain}")
if not results.get('matches'):
return {
'subdomain': subdomain,
'hosts': [],
'total_hosts': 0,
'unique_services': set(),
'vulnerable_hosts': []
}
hosts = []
unique_ports = set()
all_services = set()
vulnerable_count = 0
for match in results['matches']:
ip = match.get('ip_str')
if not ip:
continue
host_info = search_host_shodan(ip, api_key)
services = extract_service_info(host_info)
unique_ports.update(str(p) for p in host_info.get('ports', []))
all_services.update(services.keys())
vulnerable_host = analyze_host_vulnerabilities(host_info)
if vulnerable_host['vulnerabilities']:
vulnerable_count += 1
hosts.append({
'ip': host_info['ip'],
'org': host_info.get('org', 'Unknown'),
'os': host_info.get('os'),
'ports_count': len(host_info.get('ports', [])),
'services': services,
'banners': host_info.get('banners', []),
'vulnerabilities': vulnerable_host['vulnerabilities']
})
return {
'subdomain': subdomain,
'hosts': hosts,
'total_hosts': len(hosts),
'unique_ports': unique_ports,
'unique_services': all_services,
'vulnerable_hosts': vulnerable_count
}
except shodan.APIError as e:
print(f"Error querying Shodan for {subdomain}: {e}", file=sys.stderr)
return {
'subdomain': subdomain,
'hosts': [],
'total_hosts': 0,
'unique_services': set(),
'vulnerable_hosts': 0
}
def generate_summary_report(all_results):
"""Generate a summary of scan results."""
total_hosts = sum(r['total_hosts'] for r in all_results)
unique_services = set()
vulnerable_hosts_count = 0
for result in all_results:
unique_services.update(result.get('unique_services', []))
vulnerable_hosts_count += result.get('vulnerable_hosts', 0)
hosts_with_cves = sum(1 for r in all_results if r['vulnerable_hosts'] > 0)
return {
'total_subdomains_scanned': len(all_results),
'total_hosts_found': total_hosts,
'unique_services_identified': len(unique_services),
'hosts_with_cves': hosts_with_cves,
'total_vulnerable_hosts': vulnerable_hosts_count,
'scan_timestamp': datetime.now().isoformat()
}
def main():
parser = argparse.ArgumentParser(
description="Enhanced Security Scanner for Tesla Subdomains using Shodan API",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python tesla_security_scan.py -d tesla.com -s YOUR_API_KEY -o report.json
python tesla_security_scan.py -i subdomains.txt -s YOUR_API_KEY --json-output scan_results.json
"""
)
parser.add_argument(
"-d", "--domain",
dest="domain",
help="Single domain to scan (e.g., tesla.com)"
)
parser.add_argument(
"-i", "--input-file",
dest="file_name",
help=".txt file containing subdomains to scan"
)
parser.add_argument(
"-s", "--shodan-key",
dest="shodan_key",
required=True,
help="Shodan API Key"
)
parser.add_argument(
"-o", "--json-output",
dest="json_output",
default=None,
help="Output JSON file for detailed results (default: console)"
)
parser.add_argument(
"-q", "--quick-summary",
action="store_true",
help="Print quick summary only"
)
args = parser.parse_args()
if not args.domain and not args.file_name:
print("Error: Please provide either -d (domain) or -i (input file)", file=sys.stderr)
parser.print_help()
sys.exit(1)
try:
api = shodan.Shodan(args.shodan_key)
except shodan.APIError as e:
print(f"Error initializing Shodan API: {e}", file=sys.stderr)
sys.exit(1)
if args.file_name:
subdomains = load_subdomains_from_file(args.file_name)
else:
subdomains = [args.domain]
print(f"[*] Starting security scan for {len(subdomains)} target(s)...")
print(f"[+] API Key validated (Shodan)")
print()
all_results = []
total_hosts = 0
total_services = set()
vulnerable_count = 0
for i, subdomain in enumerate(subdomains, 1):
print(f"[*] Scanning {i}/{len(subdomains)}: {subdomain}...")
result = scan_subdomain(subdomain, args.shodan_key)
all_results.append(result)
total_hosts += result['total_hosts']
total_services.update(result.get('unique_services', []))
vulnerable_count += result.get('vulnerable_hosts', 0)
summary = generate_summary_report(all_results)
if args.json_output:
full_report = {
'summary': summary,
'detailed_results': all_results
}
with open(args.json_output, 'w', encoding='utf-8') as f:
json.dump(full_report, f, indent=2, ensure_ascii=False)
print(f"\n[+] Detailed JSON report saved to: {args.json_output}")
print("\n" + "=" * 70)
print("EXECUTIVE SECURITY SUMMARY")
print("=" * 70)
print()
print(f"[INFO] Total Subdomains Scanned : {summary['total_subdomains_scanned']}")
print(f"[INFO] Total Hosts Identified : {summary['total_hosts_found']:.0f}")
print(f"[INFO] Unique Services Detected : {summary['unique_services_identified']:.0f}")
print()
vuln_summary = summary.get('hosts_with_cves', 0)
total_vuln = summary.get('total_vulnerable_hosts', 0)
if vuln_summary > 0:
print(f"[ALERT] Hosts with CVE Detection : {vuln_summary}")
print(f"[CRITICAL] Total Vulnerable Hosts : {total_vuln}")
if total_vuln > 0:
vulnerability_rate = (total_vuln / summary['total_hosts_found'] * 100) if summary['total_hosts_found'] > 0 else 0
print(f"[STAT] Vulnerability Rate : {vulnerability_rate:.2f}%")
elif total_hosts > 0:
print(f"[INFO] No CVEs Detected in {summary['total_subdomains_scanned']} hosts")
print()
print("=" * 70)
print("SCAN COMPLETE")
print("=" * 70)
if __name__ == "__main__":
main()