mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-29 07:30:59 +03:00
Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills: - scripts/agent.py: 80-150 line Python agents using real libraries (impacket, boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.) - references/api-reference.md: real API documentation with method signatures - LICENSE: MIT license for all skill folders
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Phishing Incident Response Agent - Analyzes phishing emails and automates response actions."""
|
||||
|
||||
import json
|
||||
import re
|
||||
import email
|
||||
import hashlib
|
||||
import logging
|
||||
import argparse
|
||||
from email import policy
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def parse_email_file(eml_path):
|
||||
"""Parse an EML file and extract header and body information."""
|
||||
with open(eml_path, "rb") as f:
|
||||
msg = email.message_from_binary_file(f, policy=policy.default)
|
||||
parsed = {
|
||||
"subject": msg["Subject"],
|
||||
"from": msg["From"],
|
||||
"to": msg["To"],
|
||||
"date": msg["Date"],
|
||||
"message_id": msg["Message-ID"],
|
||||
"return_path": msg["Return-Path"],
|
||||
"reply_to": msg["Reply-To"],
|
||||
"received_headers": msg.get_all("Received", []),
|
||||
"authentication_results": msg.get("Authentication-Results", ""),
|
||||
"spf": "",
|
||||
"dkim": "",
|
||||
"dmarc": "",
|
||||
}
|
||||
auth_results = parsed["authentication_results"]
|
||||
if "spf=pass" in auth_results:
|
||||
parsed["spf"] = "pass"
|
||||
elif "spf=fail" in auth_results:
|
||||
parsed["spf"] = "fail"
|
||||
if "dkim=pass" in auth_results:
|
||||
parsed["dkim"] = "pass"
|
||||
elif "dkim=fail" in auth_results:
|
||||
parsed["dkim"] = "fail"
|
||||
if "dmarc=pass" in auth_results:
|
||||
parsed["dmarc"] = "pass"
|
||||
elif "dmarc=fail" in auth_results:
|
||||
parsed["dmarc"] = "fail"
|
||||
|
||||
logger.info("Parsed email: Subject='%s' From='%s'", parsed["subject"], parsed["from"])
|
||||
return parsed, msg
|
||||
|
||||
|
||||
def extract_urls(msg):
|
||||
"""Extract all URLs from email body."""
|
||||
body = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
if part.get_content_type() in ("text/plain", "text/html"):
|
||||
body += part.get_content()
|
||||
else:
|
||||
body = msg.get_content()
|
||||
urls = re.findall(r'https?://[^\s"\'<>]+', body)
|
||||
unique_urls = list(set(urls))
|
||||
logger.info("Extracted %d unique URLs", len(unique_urls))
|
||||
return unique_urls
|
||||
|
||||
|
||||
def extract_attachments(msg):
|
||||
"""Extract and hash email attachments."""
|
||||
attachments = []
|
||||
for part in msg.walk():
|
||||
if part.get_content_disposition() == "attachment":
|
||||
filename = part.get_filename()
|
||||
content = part.get_payload(decode=True)
|
||||
if content:
|
||||
sha256 = hashlib.sha256(content).hexdigest()
|
||||
md5 = hashlib.md5(content).hexdigest()
|
||||
attachments.append({
|
||||
"filename": filename,
|
||||
"content_type": part.get_content_type(),
|
||||
"size": len(content),
|
||||
"sha256": sha256,
|
||||
"md5": md5,
|
||||
})
|
||||
logger.info("Attachment: %s (SHA256: %s)", filename, sha256[:16])
|
||||
return attachments
|
||||
|
||||
|
||||
def check_url_virustotal(url, api_key):
|
||||
"""Check URL reputation on VirusTotal."""
|
||||
import base64
|
||||
url_id = base64.urlsafe_b64encode(url.encode()).decode().strip("=")
|
||||
vt_url = f"https://www.virustotal.com/api/v3/urls/{url_id}"
|
||||
headers = {"x-apikey": api_key}
|
||||
resp = requests.get(vt_url, headers=headers, timeout=30)
|
||||
if resp.status_code == 200:
|
||||
stats = resp.json()["data"]["attributes"]["last_analysis_stats"]
|
||||
return {
|
||||
"url": url,
|
||||
"malicious": stats.get("malicious", 0),
|
||||
"suspicious": stats.get("suspicious", 0),
|
||||
"harmless": stats.get("harmless", 0),
|
||||
}
|
||||
return {"url": url, "error": resp.status_code}
|
||||
|
||||
|
||||
def check_url_urlscan(url):
|
||||
"""Submit URL to urlscan.io for analysis."""
|
||||
resp = requests.post(
|
||||
"https://urlscan.io/api/v1/scan/",
|
||||
json={"url": url, "visibility": "private"},
|
||||
headers={"Content-Type": "application/json"},
|
||||
timeout=30,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
return resp.json()
|
||||
return {"url": url, "error": resp.status_code}
|
||||
|
||||
|
||||
def check_hash_virustotal(file_hash, api_key):
|
||||
"""Check file hash reputation on VirusTotal."""
|
||||
url = f"https://www.virustotal.com/api/v3/files/{file_hash}"
|
||||
headers = {"x-apikey": api_key}
|
||||
resp = requests.get(url, headers=headers, timeout=30)
|
||||
if resp.status_code == 200:
|
||||
attrs = resp.json()["data"]["attributes"]
|
||||
return {
|
||||
"hash": file_hash,
|
||||
"malicious": attrs["last_analysis_stats"].get("malicious", 0),
|
||||
"threat_name": attrs.get("popular_threat_classification", {}).get("suggested_threat_label", ""),
|
||||
}
|
||||
return {"hash": file_hash, "status": "not_found"}
|
||||
|
||||
|
||||
def assess_phishing_severity(parsed_email, url_results, attachment_results):
|
||||
"""Assess overall severity of the phishing email."""
|
||||
severity = "Low"
|
||||
indicators = []
|
||||
if parsed_email.get("spf") == "fail":
|
||||
indicators.append("SPF failed")
|
||||
severity = "Medium"
|
||||
if parsed_email.get("dkim") == "fail":
|
||||
indicators.append("DKIM failed")
|
||||
severity = "Medium"
|
||||
if parsed_email.get("dmarc") == "fail":
|
||||
indicators.append("DMARC failed")
|
||||
severity = "Medium"
|
||||
for url_result in url_results:
|
||||
if url_result.get("malicious", 0) > 0:
|
||||
indicators.append(f"Malicious URL: {url_result['url'][:50]}")
|
||||
severity = "Critical"
|
||||
for att_result in attachment_results:
|
||||
if att_result.get("malicious", 0) > 0:
|
||||
indicators.append(f"Malicious attachment: {att_result['hash'][:16]}")
|
||||
severity = "Critical"
|
||||
return {"severity": severity, "indicators": indicators}
|
||||
|
||||
|
||||
def generate_phishing_report(parsed_email, urls, attachments, url_results, att_results, assessment):
|
||||
"""Generate phishing incident response report."""
|
||||
report = {
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"email_headers": parsed_email,
|
||||
"urls_found": urls,
|
||||
"attachments": attachments,
|
||||
"url_analysis": url_results,
|
||||
"attachment_analysis": att_results,
|
||||
"severity_assessment": assessment,
|
||||
}
|
||||
print(f"PHISHING IR REPORT - Severity: {assessment['severity']}")
|
||||
print(f"URLs: {len(urls)}, Attachments: {len(attachments)}, Indicators: {len(assessment['indicators'])}")
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Phishing Incident Response Agent")
|
||||
parser.add_argument("--eml", required=True, help="Path to EML file")
|
||||
parser.add_argument("--vt-key", help="VirusTotal API key")
|
||||
parser.add_argument("--output", default="phishing_ir_report.json")
|
||||
args = parser.parse_args()
|
||||
|
||||
parsed, msg = parse_email_file(args.eml)
|
||||
urls = extract_urls(msg)
|
||||
attachments = extract_attachments(msg)
|
||||
|
||||
url_results = []
|
||||
if args.vt_key:
|
||||
for url in urls[:10]:
|
||||
url_results.append(check_url_virustotal(url, args.vt_key))
|
||||
|
||||
att_results = []
|
||||
if args.vt_key:
|
||||
for att in attachments:
|
||||
att_results.append(check_hash_virustotal(att["sha256"], args.vt_key))
|
||||
|
||||
assessment = assess_phishing_severity(parsed, url_results, att_results)
|
||||
report = generate_phishing_report(parsed, urls, attachments, url_results, att_results, assessment)
|
||||
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
logger.info("Report saved to %s", args.output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user