import sys, json, argparse from datetime import datetime import requests CENSYS_API_BASE = "https://api.platform.censys.io/v3" def search_host_censys(ip_address, token): """ Récupère les détails d'un hôte via l'API Censys avec un Personal Access Token. Parce que les clefs API c'est pour ceux qui raquent. """ url = f"{CENSYS_API_BASE}/global/asset/host/{ip_address}" headers = { "Authorization": f"Bearer {token}", "Accept": "application/json" } try: response = requests.get(url, headers=headers, timeout=10) if response.status_code == 200: data = response.json() services = data.get('services', []) vulnerabilities = data.get('vulnerabilities', []) for srv in services: if isinstance(srv, dict) and srv.get('vulnerabilities'): vulnerabilities.extend(srv['vulnerabilities']) has_cve = len(vulnerabilities) > 0 return { 'ip': ip_address, 'ports': [srv.get('port') for srv in services if isinstance(srv, dict) and srv.get('port')], 'os': data.get('operating_system', {}).get('product', None), 'org': data.get('autonomous_system', {}).get('name', 'Unknown'), 'last_update': datetime.now().isoformat(), 'services': services, 'vulnerabilities': vulnerabilities, 'potentially_vulnerable': has_cve } else: return {'ip': ip_address, 'error': f"HTTP {response.status_code}", 'ports': [], 'services': [], 'potentially_vulnerable': False} except Exception as e: return {'ip': ip_address, 'error': str(e), 'ports': [], 'services': [], 'potentially_vulnerable': False} def scan_domain_censys(domain, token): """ Recherche tous les hôtes liés à un domaine via l'API Censys. """ url = f"{CENSYS_API_BASE}/global/search/query" headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json", "Accept": "application/json" } payload = { "query": f"host.names: {domain}", "page_size": 50 } try: response = requests.post(url, headers=headers, json=payload, timeout=15) if response.status_code != 200: print(f"[-] Erreur API ({response.status_code}): {response.text}", file=sys.stderr) return {'domain': domain, 'hosts': [], 'total_hosts': 0, 'unique_ports': set(), 'vulnerable_hosts': 0} data = response.json() hits = data.get('results', []) hosts = [] unique_ports = set() vulnerable_hosts = 0 for hit in hits: ip = hit.get('ip') or hit.get('host.ip') if not ip: continue host_info = search_host_censys(ip, token) if 'error' in host_info: continue unique_ports.update(str(p) for p in host_info['ports']) if host_info.get('potentially_vulnerable'): vulnerable_hosts += 1 hosts.append(host_info) return { 'domain': domain, 'hosts': hosts, 'total_hosts': len(hosts), 'unique_ports': unique_ports, 'vulnerable_hosts': vulnerable_hosts } except Exception as e: print(f"[-] Erreur réseau : {e}", file=sys.stderr) return {'domain': domain, 'hosts': [], 'total_hosts': 0, 'unique_ports': set(), 'vulnerable_hosts': 0} def main(): parser = argparse.ArgumentParser(description="Scanner de sous-domaines générique pour l'API Censys") parser.add_argument("-d", "--domain", default="example.com", help="Domaine cible à analyser") parser.add_argument("-t", "--token", required=True, help="Votre Censys Personal Access Token") parser.add_argument("-o", "--output", help="Nom du fichier de sortie JSON") args = parser.parse_args() print(f"[*] Démarrage du scan global pour : {args.domain}") result = scan_domain_censys(args.domain, args.token) summary = { 'scan_timestamp': datetime.now().isoformat(), 'domain_scanned': args.domain, 'total_hosts_found': result['total_hosts'], 'vulnerable_hosts_found': result['vulnerable_hosts'] } full_report = { 'summary': summary, 'detailed_results': result['hosts'] } if args.output: with open(args.output, 'w', encoding='utf-8') as f: json.dump(full_report, f, indent=2, ensure_ascii=False) print(f"[+] Rapport enregistré avec succès dans : {args.output}") else: results_print = "RÉSULTATS DE L'AUDIT PASSÉ (CENSYS)" print(" ") print("=" * len(results_print)) print(results_print) print("=" * len(results_print)) print(f"[INFO] Hôtes uniques découverts : {summary['total_hosts_found']}") print(f"[INFO] Hôtes vulnérables découverts : {summary['vulnerable_hosts_found']}") print(f"[INFO] Ports distincts ouverts : {', '.join(result.get('unique_ports', []))}") if __name__ == "__main__": main()