threat intelligence

Collecting Open-Source Intelligence

Collects and synthesizes open-source intelligence (OSINT) about threat actors, malicious infrastructure, and attack campaigns using publicly available data sources, passive reconnaissance tools, and dark web monitoring. Use when investigating external threat actor infrastructure, performing pre-engagement reconnaissance for authorized red team assessments, or enriching CTI reports with publicly available adversary context. Activates for requests involving Maltego, Shodan, OSINT framework, SpiderFoot, or infrastructure reconnaissance.

att&ck-t1591maltegonist-csfosintrecon-ngshodanspiderfootthreat-intelligence
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

Use this skill when:

  • Investigating external infrastructure associated with a phishing campaign targeting your organization
  • Enriching threat actor profiles with publicly observable indicators (WHOIS, ASN data, SSL certificates)
  • Conducting authorized attack surface discovery to understand your organization's external exposure

Do not use this skill for active scanning against targets without explicit written authorization — OSINT collection must remain passive (no packets sent to target systems) unless scope permits active recon.

Prerequisites

  • Maltego CE or commercial license for graph-based link analysis
  • Shodan API key (https://shodan.io) for internet-wide device/service discovery
  • OSINT Framework familiarity (https://osintframework.com) for tool selection
  • SpiderFoot HX or open-source SpiderFoot for automated OSINT correlation

Workflow

Step 1: Define Collection Requirements

Establish the intelligence requirement (IR) before collecting. Document:

  • Target: threat actor group, malicious domain, IP range, or organization
  • Priority Intelligence Requirements (PIRs): What specific questions need answering?
  • Legal authority: Passive OSINT is legal; active probing requires authorization
  • Data handling: TLP classification for collected intelligence

Step 2: Passive DNS and WHOIS Investigation

# Passive DNS via SecurityTrails API
curl "https://api.securitytrails.com/v1/domain/evil-domain.com/dns/a" \
  -H "apikey: YOUR_KEY"
 
# WHOIS history via ARIN / RIPE
whois -h whois.arin.net evil-domain.com
 
# Certificate transparency logs (no API key required)
curl "https://crt.sh/?q=%.evil-domain.com&output=json" | jq '.[].name_value'

Certificate transparency logs reveal all subdomains for a target domain, often exposing staging, VPN, or internal infrastructure inadvertently made public.

Step 3: Shodan Infrastructure Mapping

import shodan
 
api = shodan.Shodan("YOUR_SHODAN_API_KEY")
 
# Search for specific C2 framework signatures (Cobalt Strike beacon)
results = api.search('product:"Cobalt Strike" port:443')
for r in results['matches']:
    print(r['ip_str'], r['port'], r['org'], r.get('ssl', {}).get('cert', {}).get('subject', ''))
 
# Find infrastructure associated with a known threat actor's ASN
results = api.search('asn:AS12345 http.title:"Redirector"')

Correlate Shodan results with passive DNS to build infrastructure clusters.

Step 4: Maltego Graph Analysis

In Maltego, use these built-in transforms for threat actor infrastructure mapping:

  1. Start with a known malicious domain (Entity: Domain)
  2. Run "To IP Address [DNS]" → identifies hosting IPs
  3. Run "To Shared Hosting" → identifies co-hosted domains (potentially same threat actor)
  4. Run "To DNS Name [Reverse DNS]" → identifies PTR records
  5. Run "To Whois" → identifies registrant email/organization
  6. Pivot on registrant email → "To Domains [Registrant Email]" → expands to all domains registered with same email

Maltego Maltego Cyber threat intelligence transforms (VirusTotal, Shodan, PassiveTotal, URLScan) extend graph coverage.

Step 5: Dark Web and Paste Site Monitoring

Use SpiderFoot HX or manual searches for:

  • Paste sites (Pastebin, Ghostbin): search for leaked credentials, IOCs, malware configs
  • Dark web forums: via Tor browser with appropriate operational security
  • GitHub/GitLab: search for exposed credentials or organization-specific strings
# SpiderFoot CLI for automated OSINT
python sf.py -s evil-domain.com -m sfp_shodan,sfp_virustotal,sfp_passivetotal \
  -o TF -R result.json

Key Concepts

Term Definition
Passive OSINT Intelligence collection that does not send any packets to target systems — uses public databases, search engines, cached data
PIR Priority Intelligence Requirement — specific question the intelligence collection must answer, preventing unfocused data gathering
Certificate Transparency Public log of all SSL/TLS certificates issued by CAs, enabling discovery of subdomains via crt.sh
Pivoting Using one data point (IP, email, registrant name) to discover related infrastructure or accounts
ASN Autonomous System Number — block of IP addresses under a single routing policy; useful for clustering threat actor infrastructure
Co-hosted Domains Multiple domains resolving to the same IP, potentially indicating shared attacker infrastructure

Tools & Systems

  • Maltego: Graph-based link analysis platform with 50+ data source transforms for IP, domain, email, and social media analysis
  • Shodan: Internet-wide scanner database with 1B+ indexed devices; supports banner, port, SSL certificate, and vulnerability searches
  • SpiderFoot: Automated OSINT tool with 200+ modules covering DNS, WHOIS, dark web, breach data, and social media
  • Recon-ng: Python-based OSINT framework with modular design for domain, email, and social media reconnaissance
  • crt.sh: Free certificate transparency search engine for subdomain and certificate discovery
  • OSINT Framework (osintframework.com): Curated directory of OSINT tools organized by intelligence category

Common Pitfalls

  • Leaving digital footprints: Visiting a threat actor's website or Shodan-queried IP can alert the adversary. Use Tor or VPN with a dedicated OSINT VM.
  • Confirmation bias in graph analysis: Maltego graphs can create false connections. Verify each pivot independently before treating as confirmed.
  • Outdated data: WHOIS privacy services and bulletproof hosting rotate frequently. Always check data timestamps — 6-month-old passive DNS may no longer be valid.
  • Attribution overconfidence: Infrastructure overlap does not guarantee same threat actor. False flag operations deliberately share indicators across groups.
  • Legal boundaries: Some OSINT tools perform active scans (port scanning, banner grabbing). Confirm tool behavior before use against external targets without authorization.
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 1

api-reference.md2.0 KB

API Reference: OSINT Collection Agent

Overview

Gathers open-source intelligence on target domains using Shodan, certificate transparency logs (crt.sh), RDAP WHOIS, SecurityTrails, and GitHub code search. For authorized assessments only.

Dependencies

Package Version Purpose
shodan >=1.28 Shodan API for internet-wide device search
requests >=2.28 HTTP API calls

CLI Usage

python agent.py --domain example.com --shodan-key <key> --github-token <token> --output report.json

Key Functions

search_shodan(api_key, query, max_results)

Searches Shodan for hosts matching a query string, returning IP, ports, org, OS, SSL cert subjects.

shodan_host_lookup(api_key, ip_address)

Looks up detailed information about a specific IP including open ports and known vulnerabilities.

query_crtsh(domain)

Queries certificate transparency logs via crt.sh to discover subdomains from issued SSL certificates.

whois_lookup(domain)

Performs WHOIS lookup using RDAP protocol, returning registration status, nameservers, and event dates.

query_securitytrails(api_key, domain)

Queries SecurityTrails API for current DNS records, historical DNS data, and Alexa ranking.

search_github_exposure(query, github_token)

Searches GitHub for exposed credentials, API keys, or sensitive data related to the target domain.

generate_osint_report(domain, subdomains, shodan_results, whois_data, github_results)

Consolidates all gathered OSINT into a structured JSON report.

External APIs Used

API Endpoint Auth Purpose
Shodan api.shodan.io API key Internet-wide device search
crt.sh https://crt.sh/?q=...&output=json None Certificate transparency
RDAP https://rdap.org/domain/ None WHOIS lookup
SecurityTrails https://api.securitytrails.com/v1/ API key DNS history
GitHub https://api.github.com/search/code Token Code search for exposures

Scripts 1

agent.py6.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
# For authorized penetration testing and lab environments only
"""OSINT Collection Agent - Gathers open-source intelligence on targets using Shodan and crt.sh."""

import json
import logging
import argparse
from datetime import datetime

import requests
import shodan

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)


def search_shodan(api_key, query, max_results=100):
    """Search Shodan for hosts matching a query."""
    api = shodan.Shodan(api_key)
    results = api.search(query, limit=max_results)
    hosts = []
    for match in results["matches"]:
        hosts.append({
            "ip": match["ip_str"],
            "port": match["port"],
            "org": match.get("org", ""),
            "os": match.get("os", ""),
            "hostnames": match.get("hostnames", []),
            "product": match.get("product", ""),
            "version": match.get("version", ""),
            "country": match.get("location", {}).get("country_name", ""),
            "ssl_subject": match.get("ssl", {}).get("cert", {}).get("subject", {}),
        })
    logger.info("Shodan returned %d results for query: %s", len(hosts), query)
    return hosts


def shodan_host_lookup(api_key, ip_address):
    """Lookup a specific host on Shodan for detailed information."""
    api = shodan.Shodan(api_key)
    host = api.host(ip_address)
    return {
        "ip": host["ip_str"],
        "org": host.get("org", ""),
        "os": host.get("os", ""),
        "ports": host.get("ports", []),
        "vulns": host.get("vulns", []),
        "hostnames": host.get("hostnames", []),
        "country": host.get("country_name", ""),
        "city": host.get("city", ""),
        "asn": host.get("asn", ""),
    }


def query_crtsh(domain):
    """Query certificate transparency logs via crt.sh for subdomain discovery."""
    url = f"https://crt.sh/?q=%.{domain}&output=json"
    resp = requests.get(url, timeout=30)
    if resp.status_code != 200:
        logger.warning("crt.sh query failed for %s: %d", domain, resp.status_code)
        return []
    entries = resp.json()
    subdomains = set()
    for entry in entries:
        name_value = entry.get("name_value", "")
        for name in name_value.split("\n"):
            name = name.strip().lower()
            if name and "*" not in name:
                subdomains.add(name)
    logger.info("crt.sh found %d unique subdomains for %s", len(subdomains), domain)
    return sorted(subdomains)


def whois_lookup(domain):
    """Perform WHOIS lookup via RDAP (Registration Data Access Protocol)."""
    url = f"https://rdap.org/domain/{domain}"
    resp = requests.get(url, timeout=30)
    if resp.status_code == 200:
        data = resp.json()
        return {
            "domain": domain,
            "status": data.get("status", []),
            "nameservers": [ns.get("ldhName", "") for ns in data.get("nameservers", [])],
            "events": [
                {"action": e["eventAction"], "date": e["eventDate"]}
                for e in data.get("events", [])
            ],
        }
    return {"domain": domain, "error": resp.status_code}


def query_securitytrails(api_key, domain):
    """Query SecurityTrails API for DNS history."""
    url = f"https://api.securitytrails.com/v1/domain/{domain}"
    headers = {"apikey": api_key}
    resp = requests.get(url, headers=headers, timeout=30)
    if resp.status_code == 200:
        data = resp.json()
        return {
            "domain": domain,
            "current_dns": data.get("current_dns", {}),
            "alexa_rank": data.get("alexa_rank"),
            "hostname": data.get("hostname"),
        }
    return {"domain": domain, "error": resp.status_code}


def search_github_exposure(query, github_token=None):
    """Search GitHub for exposed credentials or sensitive data."""
    headers = {"Accept": "application/vnd.github.v3+json"}
    if github_token:
        headers["Authorization"] = f"token {github_token}"
    url = "https://api.github.com/search/code"
    resp = requests.get(url, headers=headers, params={"q": query, "per_page": 20}, timeout=30)
    if resp.status_code == 200:
        items = resp.json().get("items", [])
        results = []
        for item in items:
            results.append({
                "repo": item["repository"]["full_name"],
                "path": item["path"],
                "url": item["html_url"],
            })
        logger.info("GitHub search found %d results for: %s", len(results), query)
        return results
    return []


def generate_osint_report(domain, subdomains, shodan_results, whois_data, github_results):
    """Generate a consolidated OSINT report."""
    report = {
        "target": domain,
        "timestamp": datetime.utcnow().isoformat(),
        "subdomains": subdomains,
        "subdomain_count": len(subdomains),
        "shodan_hosts": shodan_results,
        "whois": whois_data,
        "github_exposure": github_results,
    }
    lines = [
        f"OSINT REPORT - {domain}",
        "=" * 40,
        f"Subdomains discovered: {len(subdomains)}",
        f"Shodan hosts found: {len(shodan_results)}",
        f"GitHub exposures: {len(github_results)}",
    ]
    print("\n".join(lines))
    return report


def main():
    parser = argparse.ArgumentParser(description="OSINT Collection Agent")
    parser.add_argument("--domain", required=True, help="Target domain for OSINT")
    parser.add_argument("--shodan-key", help="Shodan API key")
    parser.add_argument("--shodan-query", help="Custom Shodan search query")
    parser.add_argument("--github-token", help="GitHub personal access token")
    parser.add_argument("--output", default="osint_report.json")
    args = parser.parse_args()

    subdomains = query_crtsh(args.domain)
    whois_data = whois_lookup(args.domain)

    shodan_results = []
    if args.shodan_key:
        query = args.shodan_query or f"hostname:{args.domain}"
        shodan_results = search_shodan(args.shodan_key, query)

    github_results = []
    if args.github_token:
        github_results = search_github_exposure(
            f'"{args.domain}" password OR secret OR api_key', args.github_token
        )

    report = generate_osint_report(
        args.domain, subdomains, shodan_results, whois_data, github_results
    )
    with open(args.output, "w") as f:
        json.dump(report, f, indent=2)
    logger.info("OSINT report saved to %s", args.output)


if __name__ == "__main__":
    main()
Keep exploring