Files
T
mukul975 27c6414ca5 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
2026-03-10 21:02:12 +01:00

167 lines
5.7 KiB
Python

#!/usr/bin/env python3
"""Agent for detecting spearphishing emails using email gateway log analysis."""
import argparse
import email
import json
import os
import re
import sys
from collections import defaultdict
from datetime import datetime, timezone
from email import policy
EXECUTIVE_TITLES = [
"ceo", "cfo", "cto", "cio", "coo", "president", "director",
"vp", "vice president", "managing director", "partner",
]
URGENCY_KEYWORDS = [
"urgent", "immediate", "asap", "right away", "time sensitive",
"confidential", "do not share", "wire transfer", "bank account",
"update payment", "invoice attached", "past due",
]
SUSPICIOUS_EXTENSIONS = {
".exe", ".scr", ".bat", ".cmd", ".ps1", ".vbs", ".js",
".hta", ".lnk", ".iso", ".img", ".dll", ".msi",
}
def parse_email_headers(eml_path):
"""Extract security-relevant headers from an email."""
with open(eml_path, "rb") as f:
msg = email.message_from_binary_file(f, policy=policy.default)
headers = {
"from": msg.get("From", ""),
"to": msg.get("To", ""),
"subject": msg.get("Subject", ""),
"reply_to": msg.get("Reply-To", ""),
"return_path": msg.get("Return-Path", ""),
"received_spf": msg.get("Received-SPF", ""),
"dkim_signature": msg.get("DKIM-Signature", ""),
"authentication_results": msg.get("Authentication-Results", ""),
"x_mailer": msg.get("X-Mailer", ""),
"message_id": msg.get("Message-ID", ""),
}
return headers, msg
def check_authentication(headers):
"""Verify SPF, DKIM, DMARC authentication results."""
issues = []
auth_results = headers.get("authentication_results", "").lower()
if "spf=fail" in auth_results or "spf=softfail" in auth_results:
issues.append("SPF validation failed")
if "dkim=fail" in auth_results:
issues.append("DKIM validation failed")
if "dmarc=fail" in auth_results:
issues.append("DMARC validation failed")
if not headers.get("dkim_signature"):
issues.append("No DKIM signature present")
from_domain = re.search(r"@([\w.-]+)", headers.get("from", ""))
reply_domain = re.search(r"@([\w.-]+)", headers.get("reply_to", ""))
if from_domain and reply_domain and from_domain.group(1) != reply_domain.group(1):
issues.append(f"Reply-To domain mismatch: {reply_domain.group(1)} vs {from_domain.group(1)}")
return issues
def check_content_indicators(msg):
"""Analyze email body for spearphishing content indicators."""
indicators = []
body = ""
for part in msg.walk():
if part.get_content_type() in ("text/plain", "text/html"):
payload = part.get_payload(decode=True)
if payload:
body += payload.decode("utf-8", errors="replace")
body_lower = body.lower()
for kw in URGENCY_KEYWORDS:
if kw in body_lower:
indicators.append(f"Urgency keyword: '{kw}'")
urls = re.findall(r'https?://[^\s<>"\']+', body)
for url in urls[:10]:
if re.search(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', url):
indicators.append(f"URL with IP address: {url[:80]}")
if len(url) > 100:
indicators.append(f"Unusually long URL: {url[:80]}...")
attachments = []
for part in msg.walk():
fname = part.get_filename()
if fname:
ext = os.path.splitext(fname)[1].lower()
attachments.append(fname)
if ext in SUSPICIOUS_EXTENSIONS:
indicators.append(f"Suspicious attachment: {fname}")
if ".." in fname or ext == ".exe.pdf":
indicators.append(f"Double extension: {fname}")
return indicators, attachments
def analyze_email(eml_path):
"""Full spearphishing analysis of a single email."""
headers, msg = parse_email_headers(eml_path)
auth_issues = check_authentication(headers)
content_indicators, attachments = check_content_indicators(msg)
all_indicators = auth_issues + content_indicators
score = len(all_indicators) * 15
risk = "CRITICAL" if score >= 75 else "HIGH" if score >= 50 else "MEDIUM" if score >= 25 else "LOW"
return {
"file": eml_path,
"from": headers["from"],
"to": headers["to"],
"subject": headers["subject"],
"auth_issues": auth_issues,
"content_indicators": content_indicators,
"attachments": attachments,
"risk_score": min(score, 100),
"risk_level": risk,
}
def main():
parser = argparse.ArgumentParser(
description="Detect spearphishing via email gateway analysis"
)
parser.add_argument("input", help=".eml file or directory")
parser.add_argument("--output", "-o", help="Output JSON report")
parser.add_argument("--verbose", "-v", action="store_true")
args = parser.parse_args()
print("[*] Spearphishing Detection Agent")
results = []
if os.path.isdir(args.input):
for root, _, files in os.walk(args.input):
for f in files:
if f.lower().endswith(".eml"):
results.append(analyze_email(os.path.join(root, f)))
else:
results.append(analyze_email(args.input))
flagged = [r for r in results if r["risk_level"] in ("HIGH", "CRITICAL")]
report = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"emails_scanned": len(results),
"spearphishing_detected": len(flagged),
"results": results,
}
print(f"[*] Scanned {len(results)} emails, {len(flagged)} flagged")
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"[*] Report saved to {args.output}")
else:
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()