mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-30 16:06:52 +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,185 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Agent for hunting shadow copy deletion activity indicating ransomware or anti-forensics."""
|
||||
|
||||
import json
|
||||
import argparse
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import Evtx.Evtx as evtx
|
||||
except ImportError:
|
||||
evtx = None
|
||||
|
||||
|
||||
SHADOW_PATTERNS = [
|
||||
r"vssadmin\s+delete\s+shadows",
|
||||
r"vssadmin\.exe.*delete.*shadows",
|
||||
r"wmic\s+shadowcopy\s+delete",
|
||||
r"Get-WmiObject\s+Win32_ShadowCopy.*Delete",
|
||||
r"gwmi\s+Win32_ShadowCopy.*Remove",
|
||||
r"bcdedit.*recoveryenabled.*no",
|
||||
r"bcdedit.*/set.*bootstatuspolicy\s+ignoreallfailures",
|
||||
r"wbadmin\s+delete\s+catalog",
|
||||
r"Win32_ShadowCopy.*\.Delete",
|
||||
r"powershell.*shadowcopy.*delete",
|
||||
]
|
||||
|
||||
RECOVERY_DISABLE_PATTERNS = [
|
||||
r"bcdedit\s+/set\s+\{default\}\s+recoveryenabled\s+no",
|
||||
r"reagentc\s+/disable",
|
||||
r"vssadmin\s+resize\s+shadowstorage.*maxsize=",
|
||||
]
|
||||
|
||||
|
||||
def parse_evtx_file(evtx_path):
|
||||
"""Parse Windows EVTX file for shadow copy deletion events."""
|
||||
if evtx is None:
|
||||
return []
|
||||
events = []
|
||||
with evtx.Evtx(evtx_path) as log:
|
||||
for record in log.records():
|
||||
xml_str = record.xml()
|
||||
try:
|
||||
root = ET.fromstring(xml_str)
|
||||
ns = {"ns": "http://schemas.microsoft.com/win/2004/08/events/event"}
|
||||
event_id_el = root.find(".//ns:EventID", ns)
|
||||
if event_id_el is None:
|
||||
continue
|
||||
event_id = int(event_id_el.text)
|
||||
if event_id in (1, 4688, 4698):
|
||||
data_elements = root.findall(".//ns:Data", ns)
|
||||
event_data = {}
|
||||
for d in data_elements:
|
||||
name = d.get("Name", "")
|
||||
event_data[name] = d.text or ""
|
||||
events.append({
|
||||
"event_id": event_id,
|
||||
"timestamp": record.timestamp().isoformat(),
|
||||
"data": event_data,
|
||||
})
|
||||
except ET.ParseError:
|
||||
continue
|
||||
return events
|
||||
|
||||
|
||||
def scan_command_line(cmd_line):
|
||||
"""Check a command line string against shadow copy deletion patterns."""
|
||||
findings = []
|
||||
for pattern in SHADOW_PATTERNS:
|
||||
if re.search(pattern, cmd_line, re.IGNORECASE):
|
||||
findings.append({"pattern": pattern, "severity": "CRITICAL", "category": "shadow_copy_deletion"})
|
||||
for pattern in RECOVERY_DISABLE_PATTERNS:
|
||||
if re.search(pattern, cmd_line, re.IGNORECASE):
|
||||
findings.append({"pattern": pattern, "severity": "HIGH", "category": "recovery_disable"})
|
||||
return findings
|
||||
|
||||
|
||||
def hunt_evtx(evtx_path):
|
||||
"""Hunt for shadow copy deletion in EVTX logs."""
|
||||
events = parse_evtx_file(evtx_path)
|
||||
results = []
|
||||
for event in events:
|
||||
cmd = event["data"].get("CommandLine", "") or event["data"].get("TaskContent", "")
|
||||
if not cmd:
|
||||
cmd = " ".join(event["data"].values())
|
||||
matches = scan_command_line(cmd)
|
||||
if matches:
|
||||
results.append({
|
||||
"timestamp": event["timestamp"],
|
||||
"event_id": event["event_id"],
|
||||
"command_line": cmd[:500],
|
||||
"user": event["data"].get("SubjectUserName", event["data"].get("User", "")),
|
||||
"computer": event["data"].get("Computer", ""),
|
||||
"findings": matches,
|
||||
})
|
||||
return results
|
||||
|
||||
|
||||
def scan_sysmon_json(log_path):
|
||||
"""Scan JSON-exported Sysmon logs for shadow copy deletion."""
|
||||
results = []
|
||||
with open(log_path) as f:
|
||||
for line in f:
|
||||
try:
|
||||
entry = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
cmd = entry.get("CommandLine", entry.get("command_line", ""))
|
||||
image = entry.get("Image", entry.get("process_name", ""))
|
||||
matches = scan_command_line(cmd)
|
||||
if matches:
|
||||
results.append({
|
||||
"timestamp": entry.get("UtcTime", entry.get("timestamp", "")),
|
||||
"image": image,
|
||||
"command_line": cmd[:500],
|
||||
"parent_image": entry.get("ParentImage", ""),
|
||||
"user": entry.get("User", ""),
|
||||
"hostname": entry.get("Computer", entry.get("hostname", "")),
|
||||
"findings": matches,
|
||||
})
|
||||
return results
|
||||
|
||||
|
||||
def generate_sigma_rule():
|
||||
"""Generate a Sigma detection rule for shadow copy deletion."""
|
||||
return {
|
||||
"title": "Shadow Copy Deletion via Vssadmin or WMIC",
|
||||
"id": "faa6e1e2-5b4c-4e1a-bb2a-5c1f3e5e3f0a",
|
||||
"status": "production",
|
||||
"level": "critical",
|
||||
"logsource": {"category": "process_creation", "product": "windows"},
|
||||
"detection": {
|
||||
"selection_vssadmin": {
|
||||
"Image|endswith": "\\vssadmin.exe",
|
||||
"CommandLine|contains|all": ["delete", "shadows"],
|
||||
},
|
||||
"selection_wmic": {
|
||||
"Image|endswith": "\\wmic.exe",
|
||||
"CommandLine|contains|all": ["shadowcopy", "delete"],
|
||||
},
|
||||
"selection_powershell": {
|
||||
"Image|endswith": ["\\powershell.exe", "\\pwsh.exe"],
|
||||
"CommandLine|contains": "Win32_ShadowCopy",
|
||||
},
|
||||
"condition": "selection_vssadmin or selection_wmic or selection_powershell",
|
||||
},
|
||||
"tags": ["attack.impact", "attack.t1490"],
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Shadow Copy Deletion Hunter")
|
||||
parser.add_argument("--evtx", help="Path to EVTX log file")
|
||||
parser.add_argument("--json-log", help="Path to JSON Sysmon log")
|
||||
parser.add_argument("--output", default="shadow_copy_hunt_report.json")
|
||||
parser.add_argument("--action", choices=["hunt_evtx", "hunt_json", "sigma", "full"],
|
||||
default="full")
|
||||
args = parser.parse_args()
|
||||
|
||||
report = {"generated_at": datetime.utcnow().isoformat(), "findings": {}}
|
||||
|
||||
if args.action in ("hunt_evtx", "full") and args.evtx:
|
||||
results = hunt_evtx(args.evtx)
|
||||
report["findings"]["evtx_hits"] = results
|
||||
print(f"[+] EVTX shadow copy deletion events: {len(results)}")
|
||||
|
||||
if args.action in ("hunt_json", "full") and args.json_log:
|
||||
results = scan_sysmon_json(args.json_log)
|
||||
report["findings"]["sysmon_hits"] = results
|
||||
print(f"[+] Sysmon JSON shadow copy hits: {len(results)}")
|
||||
|
||||
if args.action in ("sigma", "full"):
|
||||
rule = generate_sigma_rule()
|
||||
report["findings"]["sigma_rule"] = rule
|
||||
print("[+] Sigma rule generated")
|
||||
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2, default=str)
|
||||
print(f"[+] Report saved to {args.output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user