npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
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:
- Start with a known malicious domain (Entity: Domain)
- Run "To IP Address [DNS]" → identifies hosting IPs
- Run "To Shared Hosting" → identifies co-hosted domains (potentially same threat actor)
- Run "To DNS Name [Reverse DNS]" → identifies PTR records
- Run "To Whois" → identifies registrant email/organization
- 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.jsonKey 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.
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.jsonKey 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
#!/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()