mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 13:44:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
113 lines
4.3 KiB
Python
113 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Pass-the-Hash attack detection agent.
|
|
|
|
Detects NTLM hash reuse attacks by analyzing Windows Security Event ID 4624
|
|
for Type 3 NTLM logons with anomalous patterns across multiple targets.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import re
|
|
from collections import defaultdict
|
|
from datetime import datetime
|
|
|
|
try:
|
|
import Evtx.Evtx as evtx
|
|
except ImportError:
|
|
evtx = None
|
|
|
|
LEGITIMATE_SOURCES = {"127.0.0.1", "::1", "-", ""}
|
|
|
|
|
|
def parse_logon_events(filepath):
|
|
if evtx is None:
|
|
return {"error": "python-evtx not installed: pip install python-evtx"}
|
|
events = []
|
|
with evtx.Evtx(filepath) as log:
|
|
for record in log.records():
|
|
xml = record.xml()
|
|
if "<EventID>4624</EventID>" not in xml:
|
|
continue
|
|
logon_type = re.search(r'<Data Name="LogonType">(\d+)', xml)
|
|
auth_pkg = re.search(r'<Data Name="AuthenticationPackageName">([^<]+)', xml)
|
|
account = re.search(r'<Data Name="TargetUserName">([^<]+)', xml)
|
|
domain = re.search(r'<Data Name="TargetDomainName">([^<]+)', xml)
|
|
src_ip = re.search(r'<Data Name="IpAddress">([^<]+)', xml)
|
|
computer = re.search(r'<Data Name="Computer">([^<]+)', xml)
|
|
time_match = re.search(r'SystemTime="([^"]+)"', xml)
|
|
lt = logon_type.group(1) if logon_type else ""
|
|
ap = auth_pkg.group(1) if auth_pkg else ""
|
|
if lt == "3" and "NTLM" in ap.upper():
|
|
events.append({
|
|
"timestamp": time_match.group(1) if time_match else "",
|
|
"logon_type": int(lt), "auth_package": ap.strip(),
|
|
"account": account.group(1) if account else "",
|
|
"domain": domain.group(1) if domain else "",
|
|
"source_ip": src_ip.group(1) if src_ip else "",
|
|
"computer": computer.group(1) if computer else "",
|
|
})
|
|
return events
|
|
|
|
|
|
def detect_pth_patterns(events, target_threshold=3):
|
|
if isinstance(events, dict) and "error" in events:
|
|
return [events]
|
|
findings = []
|
|
src_targets = defaultdict(lambda: {"computers": set(), "count": 0,
|
|
"source_ip": "", "account": ""})
|
|
for evt in events:
|
|
src = evt.get("source_ip", "")
|
|
if src in LEGITIMATE_SOURCES:
|
|
continue
|
|
key = f"{src}|{evt.get('account', '')}"
|
|
src_targets[key]["computers"].add(evt.get("computer", ""))
|
|
src_targets[key]["count"] += 1
|
|
src_targets[key]["source_ip"] = src
|
|
src_targets[key]["account"] = evt.get("account", "")
|
|
|
|
for key, data in src_targets.items():
|
|
target_count = len(data["computers"])
|
|
if target_count >= target_threshold:
|
|
findings.append({
|
|
"type": "ntlm_type3_multi_target",
|
|
"source_ip": data["source_ip"],
|
|
"account": data["account"],
|
|
"target_count": target_count,
|
|
"targets": list(data["computers"])[:20],
|
|
"total_logons": data["count"],
|
|
"severity": "CRITICAL" if target_count >= 10 else "HIGH",
|
|
"mitre": "T1550.002",
|
|
})
|
|
|
|
admin_sources = defaultdict(int)
|
|
for evt in events:
|
|
if evt.get("account", "").lower() in ("administrator", "admin"):
|
|
admin_sources[evt.get("source_ip", "")] += 1
|
|
for src, count in admin_sources.items():
|
|
if count >= 2 and src not in LEGITIMATE_SOURCES:
|
|
findings.append({
|
|
"type": "admin_ntlm", "source_ip": src,
|
|
"logon_count": count, "severity": "HIGH", "mitre": "T1550.002",
|
|
})
|
|
return findings
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Pass-the-Hash Detector")
|
|
parser.add_argument("--security-log", required=True, help="Windows Security EVTX")
|
|
parser.add_argument("--target-threshold", type=int, default=3)
|
|
args = parser.parse_args()
|
|
events = parse_logon_events(args.security_log)
|
|
findings = detect_pth_patterns(events, args.target_threshold)
|
|
ntlm_count = len(events) if isinstance(events, list) else 0
|
|
results = {
|
|
"timestamp": datetime.utcnow().isoformat() + "Z",
|
|
"total_ntlm_type3_logons": ntlm_count,
|
|
"findings": findings, "total_findings": len(findings),
|
|
}
|
|
print(json.dumps(results, indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|