# Agent Skill Package: phishing You are loading a published Agent Skill. Follow SKILL.md exactly. Supporting files from the original zip are inlined below. When SKILL.md says to read `references/...` or `scripts/...`, use the matching FILE section here — do not say the file is missing. Canonical URL: https://skill.hk/s/phishing.md Human page: https://skill.hk/s/phishing Files (4): - SKILL.md - LICENSE - references/api-reference.md - scripts/agent.py ======================================================================== FILE: SKILL.md ======================================================================== --- name: analyzing-certificate-transparency-for-phishing description: Monitor Certificate Transparency logs using crt.sh and Certstream to detect phishing domains, lookalike certificates, and unauthorized certificate issuance targeting your organization. domain: cybersecurity subdomain: threat-intelligence tags: - certificate-transparency - ct-logs - phishing - crt-sh - certstream - ssl - domain-monitoring - threat-intelligence version: '1.0' author: mahipal license: Apache-2.0 atlas_techniques: - AML.T0052 nist_csf: - ID.RA-01 - ID.RA-05 - DE.CM-01 - DE.AE-02 mitre_attack: - T1583.001 - T1583.004 - T1566.002 - T1608.005 - T1596.003 mitre_f3: version: '1.1' tactics: - resource-development - reconnaissance - initial-access techniques: - id: T1583.001 name: 'Acquire Infrastructure: Domains' tactic: resource-development source: attack - id: F1020.002 name: 'Create Fake Materials: Fake Website' tactic: resource-development source: f3 - id: T1593 name: Search Open Websites/Domains tactic: reconnaissance source: attack - id: T1598 name: Phishing for Information tactic: reconnaissance source: attack - id: T1660 name: Phishing tactic: initial-access source: attack --- # Analyzing Certificate Transparency for Phishing ## Overview Certificate Transparency (CT) is an Internet security standard that creates a public, append-only log of all issued SSL/TLS certificates. Monitoring CT logs enables early detection of phishing domains that register certificates mimicking legitimate brands, unauthorized certificate issuance for owned domains, and certificate-based attack infrastructure. This skill covers querying CT logs via crt.sh, real-time monitoring with Certstream, building automated alerting for suspicious certificates, and integrating findings into threat intelligence workflows. ## When to Use - When investigating security incidents that require analyzing certificate transparency for phishing - When building detection rules or threat hunting queries for this domain - When SOC analysts need structured procedures for this analysis type - When validating security monitoring coverage for related attack techniques ## Prerequisites - Python 3.9+ with `requests`, `certstream`, `tldextract`, `Levenshtein` libraries - Access to crt.sh (https://crt.sh/) for historical CT log queries - Certstream (https://certstream.calidog.io/) for real-time monitoring - List of organization domains and brand keywords to monitor - Understanding of SSL/TLS certificate structure and issuance process ## Key Concepts ### Certificate Transparency Logs CT logs are cryptographically assured, publicly auditable, append-only records of TLS certificate issuance. Major CAs (Let's Encrypt, DigiCert, Sectigo, Google Trust Services) submit all issued certificates to multiple CT logs. As of 2025, Chrome and Safari require CT for all publicly trusted certificates. ### Phishing Detection via CT Attackers register lookalike domains and obtain free certificates (often from Let's Encrypt) to make phishing sites appear legitimate with HTTPS. CT monitoring detects these early because the certificate appears in logs before the phishing campaign launches, providing a window for proactive blocking. ### crt.sh Database crt.sh is a free web interface and PostgreSQL database operated by Sectigo that indexes CT logs. It supports wildcard searches (`%.example.com`), direct SQL queries, and JSON API responses. It tracks certificate issuance, expiration, and revocation across all major CT logs. ## Workflow ### Step 1: Query crt.sh for Certificate History ```python 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): """Query crt.sh for certificates matching a domain.""" 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)} certificates for *.{domain}") return certs return [] def find_suspicious_certs(self, domain): """Find certificates that may be phishing attempts.""" 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", "") # Check for exact domain matches (legitimate) extracted = tldextract.extract(common_name) cert_domain = f"{extracted.domain}.{extracted.suffix}" if cert_domain == domain: continue # Legitimate certificate # Flag suspicious patterns flags = [] if domain.replace(".", "") in common_name.replace(".", ""): flags.append("contains target domain string") if any(kw in common_name for kw in self.brand_keywords): flags.append("contains brand keyword") if "let's encrypt" in issuer.lower(): flags.append("free CA (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"[+] Found {len(suspicious)} suspicious certificates") 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']}] Flags: {cert['flags']}") ``` ### Step 2: Real-Time Monitoring with Certstream ```python 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): """Start real-time CT log monitoring.""" print("[*] Starting Certstream monitoring...") print(f" Watching: {self.watched_domains}") print(f" Keywords: {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" [ALERT] {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[+] Monitoring stopped. {len(self.alerts)} alerts collected.") return self.alerts def _is_suspicious(self, domain): """Check if domain is suspicious relative to watched domains.""" for watched in self.watched_domains: # Exact keyword match watched_base = watched.split(".")[0] if watched_base in domain and domain != watched: return True # Levenshtein distance (typosquatting detection) domain_base = tldextract.extract(domain).domain similarity = Levenshtein.ratio(watched_base, domain_base) if similarity >= self.threshold and domain_base != watched_base: return True # Brand keyword match for keyword in self.brand_keywords: if keyword in domain: return True return False def _get_reason(self, domain): """Determine why domain was flagged.""" reasons = [] for watched in self.watched_domains: watched_base = watched.split(".")[0] if watched_base in domain: reasons.append(f"contains '{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"similar to '{watched}' ({similarity:.0%})") for kw in self.brand_keywords: if kw in domain: reasons.append(f"brand keyword '{kw}'") return "; ".join(reasons) if reasons else "unknown" cs_monitor = CertstreamMonitor( watched_domains=["mycompany.com"], brand_keywords=["mycompany", "mybrand"], similarity_threshold=0.75, ) alerts = cs_monitor.start_monitoring(max_alerts=50) ``` ### Step 3: Enumerate Subdomains from CT Logs ```python def enumerate_subdomains_ct(domain): """Discover all subdomains from Certificate Transparency logs.""" 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"[+] CT subdomain enumeration for {domain}: {len(sorted_subs)} subdomains") return sorted_subs subdomains = enumerate_subdomains_ct("example.com") for sub in subdomains[:20]: print(f" {sub}") ``` ### Step 4: Generate CT Intelligence Report ```python def generate_ct_report(suspicious_certs, certstream_alerts, domain): report = f"""# Certificate Transparency Intelligence Report ## Target Domain: {domain} ## Generated: {datetime.now().isoformat()} ## Summary - Suspicious certificates found: {len(suspicious_certs)} - Real-time alerts triggered: {len(certstream_alerts)} ## Suspicious Certificates (crt.sh) | Common Name | Issuer | Flags | crt.sh Link | |------------|--------|-------|-------------| """ for cert in suspicious_certs[:20]: flags = "; ".join(cert.get("flags", [])) report += (f"| {cert['common_name']} | {cert['issuer'][:30]} " f"| {flags} | [View]({cert['crt_sh_url']}) |\n") report += f""" ## Real-Time Certstream Alerts | Domain | Issuer | Reason | Detected | |--------|--------|--------|----------| """ for alert in certstream_alerts[:20]: report += (f"| {alert['domain']} | {alert['issuer']} " f"| {alert['reason']} | {alert['detected_at'][:19]} |\n") report += """ ## Recommendations 1. Add flagged domains to DNS sinkhole / web proxy blocklist 2. Submit takedown requests for confirmed phishing domains 3. Monitor CT logs continuously for new certificate registrations 4. Implement CAA DNS records to restrict certificate issuance for your domains 5. Deploy DMARC to prevent email spoofing from lookalike domains """ with open(f"ct_report_{domain.replace('.','_')}.md", "w") as f: f.write(report) print(f"[+] CT report saved") return report generate_ct_report(suspicious, alerts if 'alerts' in dir() else [], "mycompany.com") ``` ## Validation Criteria - crt.sh queries return certificate data for target domains - Suspicious certificates identified based on lookalike patterns - Certstream real-time monitoring detects new phishing certificates - Subdomain enumeration produces comprehensive list from CT logs - Alerts generated with reason classification - CT intelligence report created with actionable recommendations ## References - [crt.sh Certificate Search](https://crt.sh/) - [Certstream Real-Time CT Monitor](https://certstream.calidog.io/) - [River Security: CT Logs for Attack Surface Discovery](https://riversecurity.eu/finding-attack-surface-and-fraudulent-domains-via-certificate-transparency-logs/) - [Let's Encrypt: Certificate Transparency Logs](https://letsencrypt.org/docs/ct-logs/) - [SSLMate Cert Spotter](https://sslmate.com/certspotter/) - [CyberSierra: CT Logs as Early Warning System](https://cybersierra.co/blog/ssl-certificate-transparency-logs/) ======================================================================== FILE: LICENSE ======================================================================== Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to the Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by the Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding any notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. Please do not remove or change the license header comment from a contributed file except when necessary. Copyright 2026 mukul975 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ======================================================================== FILE: references/api-reference.md ======================================================================== # API Reference: Certificate Transparency Phishing Detection ## crt.sh API ### Search Certificates ```bash # JSON output curl "https://crt.sh/?q=%.example.com&output=json" # Exclude expired curl "https://crt.sh/?q=%.example.com&output=json&exclude=expired" # Exact match curl "https://crt.sh/?q=example.com&output=json" ``` ### Response Fields | Field | Description | |-------|-------------| | `id` | Certificate ID in crt.sh database | | `common_name` | Certificate CN | | `name_value` | All SANs (newline-separated) | | `issuer_name` | Certificate Authority | | `not_before` | Validity start | | `not_after` | Validity end | | `serial_number` | Certificate serial | ## Certstream - Real-time CT Monitoring ### Python Client ```python import certstream def callback(message, context): if message["message_type"] == "certificate_update": data = message["data"] domains = data["leaf_cert"]["all_domains"] for domain in domains: if "example" in domain: print(f"[ALERT] {domain}") certstream.listen_for_events(callback, url="wss://certstream.calidog.io/") ``` ### Message Fields | Field | Path | |-------|------| | Domains | `data.leaf_cert.all_domains` | | Issuer | `data.leaf_cert.issuer.O` | | Subject | `data.leaf_cert.subject.CN` | | Fingerprint | `data.leaf_cert.fingerprint` | | Source | `data.source.name` | ## CT Log Servers | Log | Operator | URL | |-----|----------|-----| | Argon | Google | `ct.googleapis.com/logs/argon2024` | | Xenon | Google | `ct.googleapis.com/logs/xenon2024` | | Nimbus | Cloudflare | `ct.cloudflare.com/logs/nimbus2024` | | Oak | Let's Encrypt | `oak.ct.letsencrypt.org/2024h1` | | Yeti | DigiCert | `yeti2024.ct.digicert.com/log` | ## Phishing Detection Techniques ### Homoglyph / IDN Attacks | Original | Lookalike | Technique | |----------|-----------|-----------| | example.com | examp1e.com | Character substitution (l→1) | | google.com | gооgle.com | Cyrillic о (U+043E) | | paypal.com | paypa1.com | l→1 substitution | | microsoft.com | mіcrosoft.com | Cyrillic і (U+0456) | ### dnstwist Integration ```bash dnstwist -r -f json example.com # Generate and resolve permutations dnstwist -w wordlist.txt example.com # Dictionary-based ``` ## Certificate Details Lookup ```bash # Get full certificate from crt.sh curl "https://crt.sh/?d=" # OpenSSL inspection openssl s_client -connect domain.com:443 -servername domain.com /dev/null | \ openssl x509 -noout -text ``` ## Suspicious Indicators | Pattern | Risk Level | |---------|-----------| | Free CA + new domain + brand keyword | HIGH | | Wildcard cert on recently registered domain | HIGH | | Multiple certs for slight domain variants | MEDIUM | | IDN/punycode domain mimicking brand | HIGH | | Cert issued same day as domain registration | MEDIUM | ======================================================================== FILE: scripts/agent.py ======================================================================== #!/usr/bin/env python3 """Certificate Transparency monitoring agent for phishing detection. Queries crt.sh for certificates matching target domains, detects lookalike certificates, and identifies potential phishing infrastructure. """ import json import sys from collections import defaultdict try: import requests HAS_REQUESTS = True except ImportError: HAS_REQUESTS = False def query_crtsh(domain, wildcard=True, expired=False): """Query crt.sh for certificates matching a domain.""" if not HAS_REQUESTS: return [] query = f"%.{domain}" if wildcard else domain params = {"q": query, "output": "json"} if not expired: params["exclude"] = "expired" try: resp = requests.get("https://crt.sh/", params=params, timeout=30) resp.raise_for_status() return resp.json() except (requests.RequestException, json.JSONDecodeError) as e: return [{"error": str(e)}] def find_lookalike_domains(target_domain, ct_results): """Identify certificates for domains that look similar to the target.""" base = target_domain.split(".")[0].lower() lookalikes = [] for cert in ct_results: cn = cert.get("common_name", "").lower() names = cert.get("name_value", "").lower().split("\n") for name in [cn] + names: name = name.strip() if not name or name == target_domain: continue similarity = calculate_similarity(base, name.split(".")[0]) if similarity > 0.6 and name != target_domain: lookalikes.append({ "domain": name, "similarity": round(similarity, 3), "issuer": cert.get("issuer_name", ""), "not_before": cert.get("not_before", ""), "not_after": cert.get("not_after", ""), "cert_id": cert.get("id"), }) seen = set() unique = [] for l in sorted(lookalikes, key=lambda x: -x["similarity"]): if l["domain"] not in seen: seen.add(l["domain"]) unique.append(l) return unique def calculate_similarity(s1, s2): """Calculate string similarity using Levenshtein-like ratio.""" if s1 == s2: return 1.0 len1, len2 = len(s1), len(s2) if len1 == 0 or len2 == 0: return 0.0 matrix = [[0] * (len2 + 1) for _ in range(len1 + 1)] for i in range(len1 + 1): matrix[i][0] = i for j in range(len2 + 1): matrix[0][j] = j for i in range(1, len1 + 1): for j in range(1, len2 + 1): cost = 0 if s1[i-1] == s2[j-1] else 1 matrix[i][j] = min(matrix[i-1][j] + 1, matrix[i][j-1] + 1, matrix[i-1][j-1] + cost) distance = matrix[len1][len2] return 1.0 - distance / max(len1, len2) HOMOGLYPH_MAP = { "a": ["а", "@", "4"], "e": ["е", "3"], "o": ["о", "0"], "i": ["і", "1", "l"], "l": ["1", "i", "I"], "s": ["5", "$"], "t": ["7"], "g": ["9", "q"], } def detect_homoglyph_domains(target_domain, ct_results): """Detect domains using homoglyph/IDN attacks against target.""" findings = [] base = target_domain.split(".")[0].lower() for cert in ct_results: names = cert.get("name_value", "").lower().split("\n") for name in names: name = name.strip() if not name or name == target_domain: continue name_base = name.split(".")[0] if len(name_base) == len(base): diffs = sum(1 for a, b in zip(base, name_base) if a != b) if 0 < diffs <= 2: findings.append({ "domain": name, "char_differences": diffs, "cert_id": cert.get("id"), "issuer": cert.get("issuer_name", ""), }) return findings def analyze_issuer_patterns(ct_results): """Analyze certificate issuer patterns for anomalies.""" issuer_counts = defaultdict(int) free_cas = ["Let's Encrypt", "ZeroSSL", "Buypass"] for cert in ct_results: issuer = cert.get("issuer_name", "Unknown") issuer_counts[issuer] += 1 free_ca_certs = sum( count for issuer, count in issuer_counts.items() if any(ca.lower() in issuer.lower() for ca in free_cas) ) return { "issuers": dict(issuer_counts), "total_certs": len(ct_results), "free_ca_count": free_ca_certs, "free_ca_ratio": round(free_ca_certs / max(len(ct_results), 1), 3), } def detect_wildcard_abuse(ct_results): """Detect suspicious wildcard certificate patterns.""" wildcards = [] for cert in ct_results: cn = cert.get("common_name", "") if cn.startswith("*."): wildcards.append({ "domain": cn, "issuer": cert.get("issuer_name", ""), "not_before": cert.get("not_before", ""), }) return wildcards def generate_report(target_domain, ct_results): """Generate comprehensive CT monitoring report.""" lookalikes = find_lookalike_domains(target_domain, ct_results) homoglyphs = detect_homoglyph_domains(target_domain, ct_results) issuer_analysis = analyze_issuer_patterns(ct_results) wildcards = detect_wildcard_abuse(ct_results) risk_score = 0 risk_score += min(len(lookalikes) * 10, 40) risk_score += min(len(homoglyphs) * 15, 30) risk_score += 20 if issuer_analysis["free_ca_ratio"] > 0.8 else 0 risk_score = min(risk_score, 100) return { "target_domain": target_domain, "total_certificates": len(ct_results), "lookalike_domains": lookalikes[:20], "homoglyph_domains": homoglyphs[:20], "issuer_analysis": issuer_analysis, "wildcard_certs": wildcards[:10], "risk_score": risk_score, "risk_level": "HIGH" if risk_score >= 60 else "MEDIUM" if risk_score >= 30 else "LOW", } if __name__ == "__main__": print("=" * 60) print("Certificate Transparency Phishing Detection Agent") print("crt.sh queries, lookalike detection, homoglyph analysis") print("=" * 60) domain = sys.argv[1] if len(sys.argv) > 1 else None if not domain: print("\n[DEMO] Usage: python agent.py ") print(" e.g. python agent.py example.com") sys.exit(0) if not HAS_REQUESTS: print("[!] Install requests: pip install requests") sys.exit(1) print(f"\n[*] Querying crt.sh for: {domain}") results = query_crtsh(domain) print(f"[*] Found {len(results)} certificates") report = generate_report(domain, results) print(f"\n--- Lookalike Domains ({len(report['lookalike_domains'])}) ---") for l in report["lookalike_domains"][:10]: print(f" [{l['similarity']:.3f}] {l['domain']} (issuer: {l['issuer'][:40]})") print(f"\n--- Homoglyph Domains ({len(report['homoglyph_domains'])}) ---") for h in report["homoglyph_domains"][:10]: print(f" [diff={h['char_differences']}] {h['domain']}") print(f"\n--- Issuer Analysis ---") for issuer, count in sorted(report["issuer_analysis"]["issuers"].items(), key=lambda x: -x[1])[:5]: print(f" {count:4d} | {issuer[:60]}") print(f"\n[*] Risk Score: {report['risk_score']}/100 ({report['risk_level']})")