mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-14 15:04:56 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
DCSync Attack Detection Script
|
||||
Analyzes Windows Security Event 4662 logs to identify non-domain-controller
|
||||
accounts requesting Active Directory replication rights.
|
||||
"""
|
||||
|
||||
import json
|
||||
import csv
|
||||
import argparse
|
||||
import datetime
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
REPLICATION_GUIDS = {
|
||||
"1131f6aa-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes",
|
||||
"1131f6ad-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes-All",
|
||||
"89e95b76-444d-4c62-991a-0facbeda640c": "DS-Replication-Get-Changes-In-Filtered-Set",
|
||||
}
|
||||
|
||||
GUID_PATTERN = re.compile(r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", re.IGNORECASE)
|
||||
|
||||
|
||||
def load_dc_list(dc_file: str) -> set:
|
||||
"""Load known domain controller accounts from file."""
|
||||
dcs = set()
|
||||
if dc_file:
|
||||
path = Path(dc_file)
|
||||
if path.exists():
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#"):
|
||||
dcs.add(line.lower())
|
||||
return dcs
|
||||
|
||||
|
||||
def parse_events(input_path: str) -> list[dict]:
|
||||
"""Parse Windows event log exports (JSON, CSV, EVTX-exported CSV)."""
|
||||
path = Path(input_path)
|
||||
events = []
|
||||
if path.suffix == ".json":
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
events = data if isinstance(data, list) else data.get("events", [])
|
||||
elif path.suffix == ".csv":
|
||||
with open(path, "r", encoding="utf-8-sig") as f:
|
||||
events = [dict(row) for row in csv.DictReader(f)]
|
||||
return events
|
||||
|
||||
|
||||
def detect_dcsync(events: list[dict], known_dcs: set) -> list[dict]:
|
||||
"""Detect DCSync activity from Event 4662 logs."""
|
||||
findings = []
|
||||
for event in events:
|
||||
event_id = str(event.get("EventID", event.get("EventCode", event.get("event_id", ""))))
|
||||
if event_id != "4662":
|
||||
continue
|
||||
|
||||
properties = event.get("Properties", event.get("properties", ""))
|
||||
if not properties:
|
||||
continue
|
||||
|
||||
found_guids = GUID_PATTERN.findall(properties.lower())
|
||||
replication_guids = [g for g in found_guids if g in REPLICATION_GUIDS]
|
||||
if not replication_guids:
|
||||
continue
|
||||
|
||||
subject_user = event.get("SubjectUserName", event.get("subject_user_name", ""))
|
||||
subject_domain = event.get("SubjectDomainName", event.get("subject_domain_name", ""))
|
||||
computer = event.get("Computer", event.get("computer", ""))
|
||||
timestamp = event.get("TimeCreated", event.get("_time", event.get("timestamp", "")))
|
||||
|
||||
# Check if this is a legitimate domain controller
|
||||
is_dc = False
|
||||
subject_lower = subject_user.lower()
|
||||
if subject_lower.endswith("$"):
|
||||
if subject_lower in known_dcs or subject_lower.rstrip("$") in known_dcs:
|
||||
is_dc = True
|
||||
|
||||
if is_dc:
|
||||
continue
|
||||
|
||||
replication_rights = [REPLICATION_GUIDS[g] for g in replication_guids]
|
||||
has_get_changes_all = "DS-Replication-Get-Changes-All" in replication_rights
|
||||
|
||||
severity = "CRITICAL" if has_get_changes_all else "HIGH"
|
||||
|
||||
findings.append({
|
||||
"timestamp": timestamp,
|
||||
"subject_user": subject_user,
|
||||
"subject_domain": subject_domain,
|
||||
"computer": computer,
|
||||
"replication_guids": replication_guids,
|
||||
"replication_rights": replication_rights,
|
||||
"has_get_changes_all": has_get_changes_all,
|
||||
"is_machine_account": subject_user.endswith("$"),
|
||||
"severity": severity,
|
||||
"description": f"Non-DC account '{subject_user}' requested replication rights: {', '.join(replication_rights)}",
|
||||
})
|
||||
|
||||
return sorted(findings, key=lambda x: x.get("timestamp", ""), reverse=True)
|
||||
|
||||
|
||||
def run_hunt(input_path: str, dc_file: str, output_dir: str) -> None:
|
||||
"""Execute DCSync detection hunt."""
|
||||
print(f"[*] DCSync Detection Hunt - {datetime.datetime.now().isoformat()}")
|
||||
|
||||
known_dcs = load_dc_list(dc_file)
|
||||
print(f"[*] Known domain controllers: {len(known_dcs)}")
|
||||
|
||||
events = parse_events(input_path)
|
||||
print(f"[*] Loaded {len(events)} events")
|
||||
|
||||
findings = detect_dcsync(events, known_dcs)
|
||||
print(f"[!] DCSync detections: {len(findings)}")
|
||||
|
||||
output_path = Path(output_dir)
|
||||
output_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(output_path / "dcsync_findings.json", "w", encoding="utf-8") as f:
|
||||
json.dump({
|
||||
"hunt_id": f"TH-DCSYNC-{datetime.date.today().isoformat()}",
|
||||
"total_events": len(events),
|
||||
"findings_count": len(findings),
|
||||
"findings": findings,
|
||||
}, f, indent=2)
|
||||
|
||||
with open(output_path / "dcsync_report.md", "w", encoding="utf-8") as f:
|
||||
f.write("# DCSync Attack Detection Report\n\n")
|
||||
f.write(f"**Date**: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
||||
f.write(f"**Events Analyzed**: {len(events)}\n")
|
||||
f.write(f"**Findings**: {len(findings)}\n\n")
|
||||
for finding in findings:
|
||||
f.write(f"## [{finding['severity']}] {finding['subject_user']}\n")
|
||||
f.write(f"- **Time**: {finding['timestamp']}\n")
|
||||
f.write(f"- **Computer**: {finding['computer']}\n")
|
||||
f.write(f"- **Rights**: {', '.join(finding['replication_rights'])}\n")
|
||||
f.write(f"- **Description**: {finding['description']}\n\n")
|
||||
|
||||
print(f"[+] Results written to {output_dir}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="DCSync Attack Detection")
|
||||
parser.add_argument("--input", "-i", required=True, help="Path to Windows event logs")
|
||||
parser.add_argument("--dc-list", "-d", default="", help="File with known DC accounts")
|
||||
parser.add_argument("--output", "-o", default="./dcsync_hunt_output", help="Output directory")
|
||||
args = parser.parse_args()
|
||||
run_hunt(args.input, args.dc_list, args.output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user