138 lines
5.2 KiB
Python
138 lines
5.2 KiB
Python
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() |