Communitygithub.com

Analyse de la transparence des certificats pour la détection de…

Surveiller les logs de transparence des certificats avec crt.sh et Certstream pour détecter les domaines de phishing.

Qu'est-ce que Analyse de la transparence des certificats pour la détection de… ?

Cette compétence permet de surveiller les logs de transparence des certificats (CT) afin de détecter précocement des domaines de phishing qui imitent des marques légitimes. Elle utilise l'API de crt.sh pour les requêtes historiques et Certstream pour une surveillance en temps réel. L'utilisateur peut interroger les logs, identifier des certificats suspects (typosquatting, mots-clés de marque, autorités de certification gratuites), et générer des rapports d'intelligence structurés. Idéale pour les analystes SOC, les chasseurs de menaces et les équipes de sécurité qui veulent automatiser la détection de certificats malveillants avant qu'une campagne de phishing ne soit lancée.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/analyzing-certificate-transparency-for-phishing

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Analyse de la transparence des certificats pour la détection de phishing

Présentation

La transparence des certificats (Certificate Transparency, CT) est un standard de sécurité Internet qui crée un journal public, ajouté uniquement, de tous les certificats SSL/TLS émis. La surveillance des logs CT permet la détection précoce de domaines de phishing qui enregistrent des certificats imitant des marques légitimes, d'émissions non autorisées de certificats pour des domaines possédés, et d'infrastructures d'attaque basées sur des certificats. Cette compétence couvre l'interrogation des logs CT via crt.sh, la surveillance en temps réel avec Certstream, la construction d'alertes automatisées pour les certificats suspects, et l'intégration des résultats dans des workflows de renseignement sur les menaces.

Quand l'utiliser

  • Lors de l'investigation d'incidents de sécurité nécessitant l'analyse de la transparence des certificats pour le phishing
  • Lors de l'élaboration de règles de détection ou de requêtes de chasse aux menaces pour ce domaine
  • Lorsque les analystes SOC ont besoin de procédures structurées pour ce type d'analyse
  • Lors de la validation de la couverture de surveillance de sécurité pour les techniques d'attaque associées

Prérequis

  • Python 3.9+ avec les bibliothèques requests, certstream, tldextract, Levenshtein
  • Accès à crt.sh (https://crt.sh/) pour les requêtes historiques de logs CT
  • Certstream (https://certstream.calidog.io/) pour la surveillance en temps réel
  • Liste des domaines de l'organisation et des mots-clés de marque à surveiller
  • Compréhension de la structure des certificats SSL/TLS et du processus d'émission

Concepts clés

Logs de transparence des certificats

Les logs CT sont des enregistrements cryptographiquement assurés, publiquement audités et ajoutés uniquement de l'émission de certificats TLS. Les principales autorités de certification (Let's Encrypt, DigiCert, Sectigo, Google Trust Services) soumettent tous les certificats émis à plusieurs logs CT. Depuis 2025, Chrome et Safari exigent CT pour tous les certificats publics de confiance.

Détection de phishing via CT

Les attaquants enregistrent des domaines ressemblant à des marques légitimes et obtiennent des certificats gratuits (souvent de Let's Encrypt) pour faire apparaître les sites de phishing comme légitimes avec HTTPS. La surveillance CT détecte ces certificats tôt car ils apparaissent dans les logs avant le lancement de la campagne de phishing, offrant ainsi une fenêtre pour un blocage proactif.

Base de données crt.sh

crt.sh est une interface web gratuite et une base de données PostgreSQL exploitée par Sectigo qui indexe les logs CT. Elle prend en charge les recherches avec joker (%.example.com), les requêtes SQL directes et les réponses API JSON. Elle suit l'émission, l'expiration et la révocation des certificats dans tous les principaux logs CT.

Workflow

Étape 1 : Interroger crt.sh pour l'historique des certificats

import requests
import json
from datetime import datetime
import tldextract

class CTLogMonitor:
    CRT_SH_URL = "https://crt.sh"

    def __init__(self, monitored_domains, brand_keywords):
        self.monitored_domains = monitored_domains
        self.brand_keywords = [k.lower() for k in brand_keywords]

    def query_crt_sh(self, domain, include_expired=False):
        """Interroge crt.sh pour les certificats correspondant à un domaine."""
        params = {
            "q": f"%.{domain}",
            "output": "json",
        }
        if not include_expired:
            params["exclude"] = "expired"

        resp = requests.get(self.CRT_SH_URL, params=params, timeout=30)
        if resp.status_code == 200:
            certs = resp.json()
            print(f"[+] crt.sh : {len(certs)} certificats pour *.{domain}")
            return certs
        return []

    def find_suspicious_certs(self, domain):
        """Trouve les certificats qui pourraient être des tentatives de phishing."""
        certs = self.query_crt_sh(domain)
        suspicious = []

        for cert in certs:
            common_name = cert.get("common_name", "").lower()
            name_value = cert.get("name_value", "").lower()
            issuer = cert.get("issuer_name", "")
            not_before = cert.get("not_before", "")
            not_after = cert.get("not_after", "")

            # Vérifier les correspondances exactes de domaine (légitimes)
            extracted = tldextract.extract(common_name)
            cert_domain = f"{extracted.domain}.{extracted.suffix}"
            if cert_domain == domain:
                continue  # Certificat légitime

            # Signaler les motifs suspects
            flags = []
            if domain.replace(".", "") in common_name.replace(".", ""):
                flags.append("contient la chaîne du domaine cible")
            if any(kw in common_name for kw in self.brand_keywords):
                flags.append("contient un mot-clé de marque")
            if "let's encrypt" in issuer.lower():
                flags.append("AC gratuite (Let's Encrypt)")

            if flags:
                suspicious.append({
                    "common_name": cert.get("common_name", ""),
                    "name_value": cert.get("name_value", ""),
                    "issuer": issuer,
                    "not_before": not_before,
                    "not_after": not_after,
                    "serial": cert.get("serial_number", ""),
                    "flags": flags,
                    "crt_sh_id": cert.get("id", ""),
                    "crt_sh_url": f"https://crt.sh/?id={cert.get('id', '')}",
                })

        print(f"[+] {len(suspicious)} certificats suspects trouvés")
        return suspicious

monitor = CTLogMonitor(
    monitored_domains=["mycompany.com", "mycompany.org"],
    brand_keywords=["mycompany", "mybrand", "myproduct"],
)
suspicious = monitor.find_suspicious_certs("mycompany.com")
for cert in suspicious[:5]:
    print(f"  [{cert['common_name']}] Drapeaux : {cert['flags']}")

Étape 2 : Surveillance en temps réel avec Certstream

import certstream
import Levenshtein
import re
from datetime import datetime

class CertstreamMonitor:
    def __init__(self, watched_domains, brand_keywords, similarity_threshold=0.8):
        self.watched_domains = [d.lower() for d in watched_domains]
        self.brand_keywords = [k.lower() for k in brand_keywords]
        self.threshold = similarity_threshold
        self.alerts = []

    def start_monitoring(self, max_alerts=100):
        """Démarre la surveillance en temps réel des logs CT."""
        print("[*] Démarrage de la surveillance Certstream...")
        print(f"    Surveillance de : {self.watched_domains}")
        print(f"    Mots-clés : {self.brand_keywords}")

        def callback(message, context):
            if message["message_type"] == "certificate_update":
                data = message["data"]
                leaf = data.get("leaf_cert", {})
                all_domains = leaf.get("all_domains", [])

                for domain in all_domains:
                    domain_lower = domain.lower().strip("*.")
                    if self._is_suspicious(domain_lower):
                        alert = {
                            "domain": domain,
                            "all_domains": all_domains,
                            "issuer": leaf.get("issuer", {}).get("O", ""),
                            "fingerprint": leaf.get("fingerprint", ""),
                            "not_before": leaf.get("not_before", ""),
                            "detected_at": datetime.now().isoformat(),
                            "reason": self._get_reason(domain_lower),
                        }
                        self.alerts.append(alert)
                        print(f"  [ALERTE] {domain} - {alert['reason']}")

                        if len(self.alerts) >= max_alerts:
                            raise KeyboardInterrupt

        try:
            certstream.listen_for_events(callback, url="wss://certstream.calidog.io/")
        except KeyboardInterrupt:
            print(f"\n[+] Surveillance arrêtée. {len(self.alerts)} alertes collectées.")
        return self.alerts

    def _is_suspicious(self, domain):
        """Vérifie si le domaine est suspect par rapport aux domaines surveillés."""
        for watched in self.watched_domains:
            # Correspondance exacte du mot-clé
            watched_base = watched.split(".")[0]
            if watched_base in domain and domain != watched:
                return True

            # Distance de Levenshtein (détection de typosquatting)
            domain_base = tldextract.extract(domain).domain
            similarity = Levenshtein.ratio(watched_base, domain_base)
            if similarity >= self.threshold and domain_base != watched_base:
                return True

        # Correspondance de mot-clé de marque
        for keyword in self.brand_keywords:
            if keyword in domain:
                return True

        return False

    def _get_reason(self, domain):
        """Détermine pourquoi le domaine a été signalé."""
        reasons = []
        for watched in self.watched_domains:
            watched_base = watched.split(".")[0]
            if watched_base in domain:
                reasons.append(f"contient '{watched_base}'")
            domain_base = tldextract.extract(domain).domain
            similarity = Levenshtein.ratio(watched_base, domain_base)
            if similarity >= self.threshold and domain_base != watched_base:
                reasons.append(f"similaire à '{watched}' ({similarity:.0%})")
        for kw in self.brand_keywords:
            if kw in domain:
                reasons.append(f"mot-clé de marque '{kw}'")
        return "; ".join(reasons) if reasons else "inconnu"

cs_monitor = CertstreamMonitor(
    watched_domains=["mycompany.com"],
    brand_keywords=["mycompany", "mybrand"],
    similarity_threshold=0.75,
)
alerts = cs_monitor.start_monitoring(max_alerts=50)

Étape 3 : Énumérer les sous-domaines à partir des logs CT

def enumerate_subdomains_ct(domain):
    """Découvre tous les sous-domaines à partir des logs de transparence des certificats."""
    params = {"q": f"%.{domain}", "output": "json"}
    resp = requests.get("https://crt.sh", params=params, timeout=30)

    if resp.status_code != 200:
        return []

    certs = resp.json()
    subdomains = set()
    for cert in certs:
        name_value = cert.get("name_value", "")
        for name in name_value.split("\n"):
            name = name.strip().lower()
            if name.endswith(f".{domain}") or name == domain:
                name = name.lstrip("*.")
                subdomains.add(name)

    sorted_subs = sorted(subdomains)
    print(f"[+] Énumération des sous-domaines CT pour {domain} : {len(sorted_subs)} sous-domaines")
    return sorted_subs

subdomains = enumerate_subdomains_ct("example.com")
for sub in subdomains[:20]:
    print(f"  {sub}")

Étape 4 : Générer un rapport de renseignement CT

def generate_ct_report(suspicious_certs, certstream_alerts, domain):
    report = f"""# Rapport de renseignement sur la transparence des certificats
## Domaine cible : {domain}
## Généré le : {datetime.now().isoformat()}

## Résumé
- Certificats suspects trouvés : {len(suspicious_certs)}
- Alertes en temps réel déclenchées : {len(certstream_alerts)}

## Certificats suspects (crt.sh)
| Nom commun | Émetteur | Drapeaux | Lien crt.sh |
|------------|----------|----------|-------------|
"""
    for cert in suspicious_certs[:20]:
        flags = "; ".join(cert.get("flags", []))
        report += (f"| {cert['common_name']} | {cert['issuer'][:30]} "
                   f"| {flags} | [Voir]({cert['crt_sh_url']}) |\n")

    report += f"""
## Alertes en temps réel Certstream
| Domaine | Émetteur | Raison | Détecté le |
|---------|----------|--------|------------|
"""
    for alert in certstream_alerts[:20]:
        report += (f"| {alert['domain']} | {alert['issuer']} "
                   f"| {alert['reason']} | {alert['detected_at'][:19]} |\n")

    report += """
## Recommandations
1. Ajouter les domaines signalés à la liste de blocage DNS / proxy web
2. Soumettre des demandes de retrait pour les domaines de phishing confirmés
3. Surveiller les logs CT en continu pour les nouveaux enregistrements de certificats
4. Mettre en place des enregistrements DNS CAA pour restreindre l'émission de certificats pour vos domaines
5. Déployer DMARC pour empêcher l'usurpation d'email depuis des domaines similaires
"""
    with open(f"ct_report_{domain.replace('.','_')}.md", "w") as f:
        f.write(report)
    print(f"[+] Rapport CT enregistré")
    return report

generate_ct_report(suspicious, alerts if 'alerts' in dir() else [], "mycompany.com")

Critères de validation

  • Les requêtes crt.sh renvoient des données de certificats pour les domaines cibles
  • Les certificats suspects sont identifiés en fonction de motifs d'imitation
  • La surveillance en temps réel Certstream détecte les nouveaux certificats de phishing
  • L'énumération des sous-domaines produit une liste complète à partir des logs CT
  • Les alertes sont générées avec une classification des raisons
  • Le rapport de renseignement CT est créé avec des recommandations actionnables

Références

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

abusing-dpapi-for-credential-access

Extract and decrypt Windows DPAPI-protected secrets (Credential Manager, browser logins/cookies, Wi-Fi credentials, KeePass keys) online or offline using SharpDPAPI, SharpChrome, Mimikatz, or Impacket

abusing-shadow-credentials-for-privesc

Take over Active Directory accounts by writing attacker-controlled public keys to msDS-KeyCredentialLink (Shadow Credentials) with pyWhisker, Whisker, or Certipy, then authenticate via PKINIT to recover the target

achieving-cmmc-level-2-compliance

>-

acquiring-disk-image-with-dd-and-dcfldd

Create forensically sound bit-for-bit disk images with dd or dcfldd on a Linux forensic workstation, preserving evidence integrity through hash verification (MD5/SHA) during acquisition. Use when imaging a suspect drive, USB device, or memory card for investigation, preserving volatile disk evidence during incident response, or producing a verified copy for legal or law-enforcement proceedings before any destructive analysis.

analyzing-active-directory-acl-abuse

Detect dangerous ACL misconfigurations in Active Directory using ldap3

analyzing-android-malware-with-apktool

Perform static analysis of Android APK malware using apktool for resource decompilation, jadx for Java source recovery, and androguard for manifest inspection, dangerous permission-combination detection, and identification of obfuscated code, dynamic code loading, and reflection-based API calls. Use to statically triage a suspicious APK without executing it or to build mobile malware detection rules.

analyzing-api-gateway-access-logs

Parses API Gateway access logs (AWS API Gateway, Kong, Nginx) to detect

analyzing-apt-group-with-mitre-navigator

Query ATT&CK data with attackcti, mitreattack-python, and stix2, then build MITRE ATT&CK Navigator layers and multi-layer heatmap overlays mapping one or more APT groups

analyzing-azure-activity-logs-for-threats

Queries Azure Monitor activity logs and sign-in logs via azure-monitor-query

analyzing-bootkit-and-rootkit-samples

Analyzes bootkit and advanced rootkit malware infecting the Master

analyzing-browser-forensics-with-hindsight

Parse Chromium-based browser databases with Hindsight to extract and correlate browsing history, downloads, cookies, cached content, autofill data, saved passwords, and extensions from Chrome, Edge, Brave, Opera, and Vivaldi into a unified timeline (XLSX, JSON, or SQLite output). Use during incident response, insider-threat investigations, or criminal cases when you need to reconstruct a user

analyzing-campaign-attribution-evidence

Systematically evaluate cyber-campaign evidence to attribute an operation to a threat actor, using the Diamond Model and Analysis of Competing Hypotheses (ACH) to weigh infrastructure overlaps, TTP consistency, malware code similarity, and timing/language artifacts into confidence-weighted attribution assessments. Use when an incident investigation needs a defensible attribution confidence level.

analyzing-cloud-storage-access-patterns

Detect abnormal access in AWS S3, GCS, and Azure Blob Storage by analyzing CloudTrail Data Events, GCS audit logs, and Azure Storage Analytics for after-hours bulk downloads, new-IP access, and API-call spikes (e.g. GetObject) via statistical baselines and time-series anomaly detection. Use when investigating suspected cloud data exfiltration or building related detection rules.

analyzing-cobalt-strike-beacon-configuration

Extract and analyze Cobalt Strike beacon configuration from PE files

analyzing-cobaltstrike-malleable-c2-profiles

Parse and analyze Cobalt Strike Malleable C2 profiles with dissect.cobaltstrike (profiles and beacon-payload configs) and pyMalleableC2 (AST parsing) to extract HTTP/DNS transforms, URIs, headers, sleep/jitter, and injection behavior, then generate network detection signatures. Use when reverse-engineering a captured malleable profile or building detections against Cobalt Strike Beacon traffic.

analyzing-command-and-control-communication

Analyzes malware C2 communication over HTTP, HTTPS, DNS, and custom

analyzing-cyber-kill-chain

Analyzes intrusion activity against the Lockheed Martin Cyber Kill Chain

analyzing-disk-image-with-autopsy

Perform comprehensive forensic analysis of raw (dd), E01, or AFF disk images with Autopsy and The Sleuth Kit, recovering deleted files, examining metadata and embedded artifacts, keyword searching, and building investigation timelines with visual reports. Use for structured analysis of a forensic disk image or when stakeholders need visual reports from evidence.

analyzing-dns-logs-for-exfiltration

Analyzes DNS query logs to detect data exfiltration via DNS tunneling,

analyzing-docker-container-forensics

Investigate compromised Docker containers by analyzing images, layers,

Skills associés