mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-02 09:07:41 +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,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
name: detecting-golden-ticket-attacks
|
||||
description: >-
|
||||
Detect Kerberos golden ticket attacks by analyzing Windows Security event logs for anomalous
|
||||
TGT usage patterns. Parses Event IDs 4624, 4672, and 4768 from EVTX files to identify tickets
|
||||
with abnormal lifetimes, domain SID mismatches, and privilege escalation sequences where
|
||||
non-admin accounts receive admin-level privileges without corresponding group membership changes.
|
||||
---
|
||||
|
||||
## Instructions
|
||||
|
||||
1. Install dependencies: `pip install python-evtx lxml`
|
||||
2. Collect Windows Security EVTX logs from domain controllers.
|
||||
3. Parse Event IDs:
|
||||
- 4768: Kerberos TGT requests (authentication service requests)
|
||||
- 4624: Logon events (look for LogonType 3 with NTLM or Kerberos)
|
||||
- 4672: Special privileges assigned (admin logon indicators)
|
||||
4. Detect golden ticket indicators:
|
||||
- TGT with lifetime >10 hours (default max is 10h)
|
||||
- Event 4672 for accounts not in Domain Admins
|
||||
- Logon events with no corresponding 4768 TGT request
|
||||
- Domain SID inconsistencies in ticket data
|
||||
5. Generate detection report with timeline reconstruction.
|
||||
|
||||
```bash
|
||||
python scripts/agent.py --evtx-file /path/to/Security.evtx --output golden_ticket_report.json
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Detect Anomalous Privilege Assignment
|
||||
Event 4672 for a standard user account receiving SeDebugPrivilege, SeTcbPrivilege, or SeBackupPrivilege indicates potential golden ticket usage.
|
||||
|
||||
### TGT Without Corresponding AS-REQ
|
||||
A logon event (4624) with Kerberos authentication but no matching 4768 (TGT request) on the DC suggests a forged TGT.
|
||||
@@ -0,0 +1,50 @@
|
||||
# API Reference: Detecting Golden Ticket Attacks
|
||||
|
||||
## python-evtx Library
|
||||
```python
|
||||
from Evtx.Evtx import FileHeader
|
||||
with open("Security.evtx", "rb") as f:
|
||||
fh = FileHeader(f)
|
||||
for record in fh.records():
|
||||
xml_string = record.xml()
|
||||
```
|
||||
|
||||
## Key Event IDs
|
||||
|
||||
### Event 4768 - Kerberos TGT Request (AS-REQ)
|
||||
```xml
|
||||
<Data Name="TargetUserName">admin_user</Data>
|
||||
<Data Name="TargetDomainName">CORP.LOCAL</Data>
|
||||
<Data Name="TicketEncryptionType">0x12</Data>
|
||||
<Data Name="PreAuthType">15</Data>
|
||||
<Data Name="IpAddress">::ffff:10.0.0.50</Data>
|
||||
```
|
||||
|
||||
### Event 4624 - Logon Event
|
||||
```xml
|
||||
<Data Name="TargetUserName">user</Data>
|
||||
<Data Name="LogonType">3</Data>
|
||||
<Data Name="AuthenticationPackageName">Kerberos</Data>
|
||||
<Data Name="IpAddress">10.0.0.50</Data>
|
||||
<Data Name="WorkstationName">WKS01</Data>
|
||||
```
|
||||
|
||||
### Event 4672 - Special Privileges Assigned
|
||||
```xml
|
||||
<Data Name="SubjectUserName">user</Data>
|
||||
<Data Name="SubjectDomainName">CORP</Data>
|
||||
<Data Name="PrivilegeList">SeDebugPrivilege SeTcbPrivilege</Data>
|
||||
```
|
||||
|
||||
## Golden Ticket Detection Indicators
|
||||
| Indicator | Evidence |
|
||||
|-----------|----------|
|
||||
| Orphan logon | 4624 Kerberos logon with no 4768 TGT request |
|
||||
| Privilege anomaly | 4672 admin privs for non-admin account |
|
||||
| Abnormal TGT lifetime | TGT valid >10 hours (default max) |
|
||||
| RC4 TGT majority | >50% of TGTs using 0x17 encryption |
|
||||
| Domain SID mismatch | TGT domain SID differs from DC |
|
||||
|
||||
## MITRE ATT&CK
|
||||
- T1558.001 - Golden Ticket
|
||||
- T1550 - Use Alternate Authentication Material
|
||||
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Golden Ticket Detection Agent - Detects forged Kerberos TGTs via Event 4624/4672/4768 analysis."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
|
||||
from Evtx.Evtx import FileHeader
|
||||
from lxml import etree
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
NS = {"evt": "http://schemas.microsoft.com/win/2004/08/events/event"}
|
||||
|
||||
ADMIN_PRIVILEGES = [
|
||||
"SeDebugPrivilege", "SeTcbPrivilege", "SeBackupPrivilege",
|
||||
"SeRestorePrivilege", "SeTakeOwnershipPrivilege", "SeLoadDriverPrivilege",
|
||||
"SeImpersonatePrivilege", "SeAssignPrimaryTokenPrivilege",
|
||||
]
|
||||
|
||||
|
||||
def parse_event_data(root):
|
||||
"""Extract EventData fields from an EVTX XML record."""
|
||||
data = {}
|
||||
for elem in root.findall(".//evt:EventData/evt:Data", NS):
|
||||
data[elem.get("Name", "")] = elem.text or ""
|
||||
time_elem = root.find(".//evt:System/evt:TimeCreated", NS)
|
||||
data["_timestamp"] = time_elem.get("SystemTime", "") if time_elem is not None else ""
|
||||
return data
|
||||
|
||||
|
||||
def parse_security_events(evtx_path):
|
||||
"""Parse Event IDs 4624, 4672, and 4768 from Security EVTX."""
|
||||
events = {"4624": [], "4672": [], "4768": []}
|
||||
target_ids = {"4624", "4672", "4768"}
|
||||
with open(evtx_path, "rb") as f:
|
||||
fh = FileHeader(f)
|
||||
for record in fh.records():
|
||||
try:
|
||||
xml = record.xml()
|
||||
root = etree.fromstring(xml.encode("utf-8"))
|
||||
eid_elem = root.find(".//evt:System/evt:EventID", NS)
|
||||
if eid_elem is None or eid_elem.text not in target_ids:
|
||||
continue
|
||||
data = parse_event_data(root)
|
||||
events[eid_elem.text].append(data)
|
||||
except Exception:
|
||||
continue
|
||||
for eid, evts in events.items():
|
||||
logger.info("Parsed %d events for Event ID %s", len(evts), eid)
|
||||
return events
|
||||
|
||||
|
||||
def detect_orphan_logons(events):
|
||||
"""Detect Kerberos logons (4624) with no corresponding TGT request (4768)."""
|
||||
tgt_accounts = {e.get("TargetUserName", "").lower() for e in events["4768"]}
|
||||
orphan_logons = []
|
||||
for logon in events["4624"]:
|
||||
if logon.get("AuthenticationPackageName", "") == "Kerberos":
|
||||
account = logon.get("TargetUserName", "").lower()
|
||||
if account and account not in tgt_accounts and not account.endswith("$"):
|
||||
orphan_logons.append({
|
||||
"timestamp": logon["_timestamp"],
|
||||
"account": logon.get("TargetUserName", ""),
|
||||
"source_ip": logon.get("IpAddress", ""),
|
||||
"logon_type": logon.get("LogonType", ""),
|
||||
"workstation": logon.get("WorkstationName", ""),
|
||||
"indicator": "Kerberos logon without TGT request (possible golden ticket)",
|
||||
})
|
||||
logger.info("Found %d orphan Kerberos logons", len(orphan_logons))
|
||||
return orphan_logons
|
||||
|
||||
|
||||
def detect_anomalous_privileges(events, known_admins=None):
|
||||
"""Detect non-admin accounts receiving admin privileges (Event 4672)."""
|
||||
if known_admins is None:
|
||||
known_admins = set()
|
||||
anomalous = []
|
||||
for priv_event in events["4672"]:
|
||||
account = priv_event.get("SubjectUserName", "")
|
||||
privileges = priv_event.get("PrivilegeList", "")
|
||||
if account.lower() not in known_admins and not account.endswith("$"):
|
||||
admin_privs = [p for p in ADMIN_PRIVILEGES if p in privileges]
|
||||
if admin_privs:
|
||||
anomalous.append({
|
||||
"timestamp": priv_event["_timestamp"],
|
||||
"account": account,
|
||||
"domain": priv_event.get("SubjectDomainName", ""),
|
||||
"admin_privileges": admin_privs,
|
||||
"indicator": "Non-admin account with admin privileges (golden ticket indicator)",
|
||||
})
|
||||
logger.info("Found %d anomalous privilege assignments", len(anomalous))
|
||||
return anomalous
|
||||
|
||||
|
||||
def detect_abnormal_tgt_patterns(events):
|
||||
"""Detect TGT requests with abnormal encryption types or patterns."""
|
||||
account_tgts = defaultdict(list)
|
||||
for tgt in events["4768"]:
|
||||
account = tgt.get("TargetUserName", "")
|
||||
account_tgts[account].append(tgt)
|
||||
anomalies = []
|
||||
for account, tgts in account_tgts.items():
|
||||
if account.endswith("$"):
|
||||
continue
|
||||
rc4_tgts = [t for t in tgts if t.get("TicketEncryptionType", "") in ("0x17", "0x18")]
|
||||
if rc4_tgts and len(rc4_tgts) > len(tgts) * 0.5:
|
||||
anomalies.append({
|
||||
"account": account,
|
||||
"total_tgts": len(tgts),
|
||||
"rc4_tgts": len(rc4_tgts),
|
||||
"indicator": "Majority RC4 TGT requests (possible ticket forging)",
|
||||
})
|
||||
logger.info("Found %d accounts with abnormal TGT patterns", len(anomalies))
|
||||
return anomalies
|
||||
|
||||
|
||||
def detect_logon_privilege_correlation(events):
|
||||
"""Correlate logon events with privilege assignments for timeline analysis."""
|
||||
priv_accounts = defaultdict(list)
|
||||
for priv in events["4672"]:
|
||||
account = priv.get("SubjectUserName", "").lower()
|
||||
priv_accounts[account].append(priv["_timestamp"])
|
||||
logon_accounts = defaultdict(list)
|
||||
for logon in events["4624"]:
|
||||
account = logon.get("TargetUserName", "").lower()
|
||||
logon_accounts[account].append({
|
||||
"timestamp": logon["_timestamp"],
|
||||
"source_ip": logon.get("IpAddress", ""),
|
||||
"logon_type": logon.get("LogonType", ""),
|
||||
})
|
||||
correlations = []
|
||||
for account in priv_accounts:
|
||||
if account in logon_accounts and not account.endswith("$"):
|
||||
correlations.append({
|
||||
"account": account,
|
||||
"privilege_events": len(priv_accounts[account]),
|
||||
"logon_events": len(logon_accounts[account]),
|
||||
"source_ips": list({l["source_ip"] for l in logon_accounts[account]}),
|
||||
})
|
||||
return correlations
|
||||
|
||||
|
||||
def generate_report(orphan_logons, priv_anomalies, tgt_anomalies, correlations):
|
||||
"""Generate golden ticket detection report."""
|
||||
total = len(orphan_logons) + len(priv_anomalies) + len(tgt_anomalies)
|
||||
severity = "Critical" if orphan_logons and priv_anomalies else "High" if total > 0 else "Low"
|
||||
report = {
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"severity": severity,
|
||||
"orphan_kerberos_logons": orphan_logons[:20],
|
||||
"anomalous_privilege_assignments": priv_anomalies[:20],
|
||||
"abnormal_tgt_patterns": tgt_anomalies,
|
||||
"logon_privilege_correlations": correlations[:20],
|
||||
"total_indicators": total,
|
||||
}
|
||||
print(f"GOLDEN TICKET DETECTION: {total} indicators, Severity: {severity}")
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Golden Ticket Detection Agent")
|
||||
parser.add_argument("--evtx-file", required=True, help="Path to Security EVTX file")
|
||||
parser.add_argument("--known-admins", nargs="*", default=[], help="Known admin account names")
|
||||
parser.add_argument("--output", default="golden_ticket_report.json")
|
||||
args = parser.parse_args()
|
||||
|
||||
events = parse_security_events(args.evtx_file)
|
||||
known_admins = {a.lower() for a in args.known_admins}
|
||||
orphan_logons = detect_orphan_logons(events)
|
||||
priv_anomalies = detect_anomalous_privileges(events, known_admins)
|
||||
tgt_anomalies = detect_abnormal_tgt_patterns(events)
|
||||
correlations = detect_logon_privilege_correlation(events)
|
||||
|
||||
report = generate_report(orphan_logons, priv_anomalies, tgt_anomalies, correlations)
|
||||
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