npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
Use this skill when:
- SOC teams need to formalize incident tracking beyond SIEM notable event management
- Compliance requirements mandate documented incident lifecycle with timestamps and audit trails
- Multi-team coordination requires ticket-based workflows with assignment and escalation
- SLA tracking needs automated measurement of response and resolution times
- Post-incident reviews require structured data for trend analysis and reporting
Do not use for individual alert triage — ticketing is for confirmed incidents requiring multi-step investigation and remediation, not every SIEM alert.
Prerequisites
- Ticketing platform: ServiceNow ITSM, Jira Service Management, or TheHive
- SIEM integration capability (REST API, webhook, or SOAR connector)
- Incident classification taxonomy (categories, severity levels, escalation paths)
- On-call rotation schedule for analyst assignment
- SLA definitions aligned to incident severity
Workflow
Step 1: Define Incident Classification Taxonomy
Establish standardized incident categories and severity:
incident_taxonomy:
categories:
- malware_infection
- phishing_campaign
- unauthorized_access
- data_exfiltration
- denial_of_service
- ransomware
- insider_threat
- vulnerability_exploitation
- account_compromise
- policy_violation
severity_levels:
critical:
definition: "Active data breach, ransomware, or business-critical system compromise"
response_sla: 15 minutes
resolution_sla: 4 hours
escalation: immediate to Tier 3 + CISO notification
examples: ["Active ransomware", "Domain admin compromise", "Customer data breach"]
high:
definition: "Confirmed compromise of business systems or multiple user accounts"
response_sla: 30 minutes
resolution_sla: 8 hours
escalation: Tier 2 immediate, Tier 3 if unresolved in 2 hours
examples: ["Malware with C2", "Lateral movement detected", "Phishing with credential theft"]
medium:
definition: "Confirmed security event requiring investigation and remediation"
response_sla: 2 hours
resolution_sla: 24 hours
escalation: Tier 2 within 4 hours
examples: ["Single phishing click", "Unauthorized software", "Policy violation"]
low:
definition: "Minor security event with limited impact"
response_sla: 8 hours
resolution_sla: 72 hours
escalation: Tier 1 standard queue
examples: ["Scan attempt", "Failed brute force (no compromise)", "Info disclosure"]Step 2: Automate Ticket Creation from SIEM
ServiceNow Integration via REST API:
import requests
import json
from datetime import datetime
class IncidentTicketManager:
def __init__(self, snow_url, snow_user, snow_password):
self.snow_url = snow_url
self.auth = (snow_user, snow_password)
self.headers = {
"Content-Type": "application/json",
"Accept": "application/json"
}
def create_incident(self, alert_data):
"""Create ServiceNow incident from SIEM alert"""
severity_map = {
"critical": "1",
"high": "2",
"medium": "3",
"low": "4"
}
payload = {
"short_description": f"[SEC] {alert_data['rule_name']} — {alert_data['src']}",
"description": self._build_description(alert_data),
"category": "Security",
"subcategory": alert_data.get("category", "Investigation"),
"urgency": severity_map.get(alert_data["severity"], "3"),
"impact": severity_map.get(alert_data["severity"], "3"),
"assignment_group": self._get_assignment_group(alert_data["severity"]),
"caller_id": "soc_automation",
"u_siem_event_id": alert_data.get("notable_id", ""),
"u_mitre_technique": alert_data.get("mitre_technique", ""),
"u_affected_hosts": ", ".join(alert_data.get("affected_hosts", [])),
"u_iocs": json.dumps(alert_data.get("iocs", {}))
}
response = requests.post(
f"{self.snow_url}/api/now/table/incident",
auth=self.auth,
headers=self.headers,
json=payload
)
result = response.json()["result"]
return {
"ticket_number": result["number"],
"sys_id": result["sys_id"],
"state": result["state"]
}
def _build_description(self, alert_data):
return f"""
SECURITY INCIDENT — Auto-generated from SIEM
================================================
Alert Rule: {alert_data['rule_name']}
SIEM Event ID: {alert_data.get('notable_id', 'N/A')}
Detection Time: {alert_data['detection_time']}
Severity: {alert_data['severity'].upper()}
MITRE ATT&CK: {alert_data.get('mitre_technique', 'N/A')}
Source: {alert_data.get('src', 'N/A')}
Destination: {alert_data.get('dest', 'N/A')}
User: {alert_data.get('user', 'N/A')}
Initial Context:
{alert_data.get('description', 'See SIEM for details.')}
IOCs:
{json.dumps(alert_data.get('iocs', {}), indent=2)}
"""
def _get_assignment_group(self, severity):
if severity in ("critical", "high"):
return "SOC Tier 2"
return "SOC Tier 1"
def update_incident(self, ticket_number, updates):
"""Update an existing incident"""
# First get sys_id from ticket number
response = requests.get(
f"{self.snow_url}/api/now/table/incident",
auth=self.auth,
headers=self.headers,
params={"sysparm_query": f"number={ticket_number}", "sysparm_limit": 1}
)
sys_id = response.json()["result"][0]["sys_id"]
# Update
response = requests.patch(
f"{self.snow_url}/api/now/table/incident/{sys_id}",
auth=self.auth,
headers=self.headers,
json=updates
)
return response.json()["result"]
def add_work_note(self, ticket_number, note):
"""Add investigation note to incident"""
self.update_incident(ticket_number, {"work_notes": note})
def escalate_incident(self, ticket_number, reason):
"""Escalate to next tier"""
self.update_incident(ticket_number, {
"assignment_group": "SOC Tier 3",
"urgency": "1",
"work_notes": f"ESCALATED: {reason}"
})
def resolve_incident(self, ticket_number, resolution):
"""Resolve and close incident"""
self.update_incident(ticket_number, {
"state": "6", # Resolved
"close_code": "Resolved",
"close_notes": resolution,
"u_incident_disposition": resolution.split(":")[0] if ":" in resolution else "Resolved"
})Step 3: Configure TheHive for Security-Focused Ticketing
TheHive Case Creation (alternative to ServiceNow):
import requests
class TheHiveCaseManager:
def __init__(self, thehive_url, api_key):
self.url = thehive_url
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def create_case(self, alert_data):
"""Create case in TheHive from SIEM alert"""
case = {
"title": f"[{alert_data['severity'].upper()}] {alert_data['rule_name']}",
"description": self._build_markdown_description(alert_data),
"severity": {"critical": 4, "high": 3, "medium": 2, "low": 1}.get(
alert_data["severity"], 2
),
"tlp": 2, # TLP:AMBER
"pap": 2, # PAP:AMBER
"tags": [
alert_data.get("mitre_technique", ""),
alert_data.get("category", ""),
f"source:{alert_data.get('src', 'unknown')}"
],
"tasks": self._generate_tasks(alert_data["severity"]),
"customFields": {
"siem-event-id": {"string": alert_data.get("notable_id", "")},
"mitre-technique": {"string": alert_data.get("mitre_technique", "")},
"detection-source": {"string": "Splunk ES"}
}
}
response = requests.post(
f"{self.url}/api/case",
headers=self.headers,
json=case
)
return response.json()
def _generate_tasks(self, severity):
"""Generate investigation tasks based on severity"""
tasks = [
{"title": "Initial Triage", "group": "Phase 1", "description": "Review SIEM alert and validate findings"},
{"title": "IOC Enrichment", "group": "Phase 1", "description": "Enrich all IOCs with VT, AbuseIPDB"},
{"title": "Scope Assessment", "group": "Phase 2", "description": "Determine affected systems and users"},
]
if severity in ("critical", "high"):
tasks.extend([
{"title": "Containment Actions", "group": "Phase 2", "description": "Isolate affected systems"},
{"title": "Evidence Collection", "group": "Phase 3", "description": "Preserve forensic artifacts"},
{"title": "Eradication", "group": "Phase 3", "description": "Remove threat from environment"},
{"title": "Recovery", "group": "Phase 4", "description": "Restore systems to normal operations"},
{"title": "Post-Incident Review", "group": "Phase 4", "description": "Document lessons learned"},
])
else:
tasks.append(
{"title": "Resolution and Documentation", "group": "Phase 2", "description": "Document findings and close"}
)
return tasks
def add_observable(self, case_id, ioc_type, ioc_value, description=""):
"""Add IOC observable to case"""
observable = {
"dataType": ioc_type,
"data": ioc_value,
"message": description,
"tlp": 2,
"ioc": True,
"tags": ["auto-extracted"]
}
response = requests.post(
f"{self.url}/api/case/{case_id}/artifact",
headers=self.headers,
json=observable
)
return response.json()Step 4: Implement SLA Tracking and Escalation
Splunk SLA Monitoring Dashboard:
--- Active incidents approaching SLA breach
index=servicenow sourcetype="snow:incident" category="Security" state IN ("New", "In Progress")
| eval sla_minutes = case(
urgency="1", 15,
urgency="2", 30,
urgency="3", 120,
urgency="4", 480
)
| eval age_minutes = round((now() - strptime(opened_at, "%Y-%m-%d %H:%M:%S")) / 60, 0)
| eval sla_remaining = sla_minutes - age_minutes
| eval sla_status = case(
sla_remaining < 0, "BREACHED",
sla_remaining < sla_minutes * 0.25, "AT RISK",
1=1, "ON TRACK"
)
| where sla_status IN ("BREACHED", "AT RISK")
| sort sla_remaining
| table number, short_description, urgency, assignment_group, assigned_to,
age_minutes, sla_minutes, sla_remaining, sla_statusAuto-Escalation Logic:
def check_sla_breaches(ticket_manager):
"""Check for SLA breaches and auto-escalate"""
open_incidents = ticket_manager.get_open_incidents()
for incident in open_incidents:
age_minutes = (datetime.utcnow() - incident["opened_at"]).total_seconds() / 60
sla_minutes = {"1": 15, "2": 30, "3": 120, "4": 480}[incident["urgency"]]
if age_minutes > sla_minutes and incident["state"] == "New":
ticket_manager.escalate_incident(
incident["number"],
f"SLA BREACH: {int(age_minutes)}min elapsed, {sla_minutes}min SLA. Auto-escalating."
)Step 5: Build Reporting and Metrics
--- Monthly incident metrics
index=servicenow sourcetype="snow:incident" category="Security"
opened_at > "2024-03-01" opened_at < "2024-04-01"
| stats count AS total,
avg(eval((resolved_at - opened_at) / 3600)) AS avg_resolution_hours,
sum(eval(if(urgency="1", 1, 0))) AS critical,
sum(eval(if(urgency="2", 1, 0))) AS high,
sum(eval(if(urgency="3", 1, 0))) AS medium,
sum(eval(if(urgency="4", 1, 0))) AS low
| eval avg_resolution = round(avg_resolution_hours, 1)
--- SLA compliance rate
index=servicenow sourcetype="snow:incident" category="Security" state="Resolved"
| eval sla_target = case(urgency="1", 4, urgency="2", 8, urgency="3", 24, urgency="4", 72)
| eval resolution_hours = (resolved_at - opened_at) / 3600
| eval sla_met = if(resolution_hours <= sla_target, 1, 0)
| stats sum(sla_met) AS met, count AS total
| eval compliance_pct = round(met / total * 100, 1)Key Concepts
| Term | Definition |
|---|---|
| Incident Ticket | Formal tracking record for a confirmed security incident with lifecycle management |
| SLA | Service Level Agreement defining maximum response and resolution times by severity |
| Escalation Path | Defined routing from Tier 1 to Tier 2/3 based on severity, time elapsed, or analyst request |
| Disposition | Final classification of a closed incident (true positive, false positive, duplicate, policy violation) |
| MTTR | Mean Time to Resolve — average time from ticket creation to resolution across all incidents |
| Case Management | Structured approach to managing complex incidents with tasks, observables, and audit trails |
Tools & Systems
- ServiceNow ITSM: Enterprise IT service management platform with security incident module and SLA tracking
- Jira Service Management: Atlassian's service management platform with customizable incident workflows
- TheHive: Open-source security incident response platform with case management and Cortex integration
- PagerDuty: On-call management and incident notification platform for SOC analyst alerting
- Splunk ITSI: IT Service Intelligence module for SLA tracking and service health dashboards
Common Scenarios
- SIEM-to-Ticket Automation: Auto-create ServiceNow ticket for every critical/high notable event in Splunk ES
- Multi-Team Coordination: Route malware incidents to SOC for triage, IT for remediation, Legal for notification
- Compliance Documentation: Generate incident reports from ticket data for PCI DSS, HIPAA audit evidence
- On-Call Alerting: Page on-call analyst via PagerDuty when critical ticket created after hours
- Post-Incident Review: Query closed tickets to identify recurring incident types and systemic gaps
Output Format
INCIDENT TICKET — INC0012567
━━━━━━━━━━━━━━━━━━━━━━━━━━━
Title: [SEC] Cobalt Strike C2 Beacon Detected — WORKSTATION-042
Category: Security > Malware Infection
Severity: Critical (P1)
SLA: Response: 15 min | Resolution: 4 hours
Timeline:
14:23 Ticket created (auto from Splunk ES NE-2024-08921)
14:25 Assigned to analyst_jdoe (Tier 2)
14:28 Work note: "VT confirms Cobalt Strike beacon, hash a1b2c3..."
14:35 Work note: "Host isolated via CrowdStrike, C2 domain blocked"
15:00 Work note: "Enterprise IOC scan — 2 additional hosts found"
15:30 Escalated to Tier 3 for forensic analysis
16:00 Work note: "All affected hosts contained and cleaned"
18:00 Resolved: "Malware eradicated, systems restored, monitoring for 72h"
Metrics:
Time to Acknowledge: 2 minutes
Time to Contain: 12 minutes
Time to Resolve: 3 hours 37 minutes
SLA Status: MET (within 4-hour resolution target)References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.4 KB
API Reference: Implementing Ticketing System for Incidents
Libraries
requests (HTTP Client)
- Install:
pip install requests - Used for ServiceNow REST API and TheHive API
ServiceNow REST API
Incident Table (/api/now/table/incident)
| Method | Endpoint | Description |
|---|---|---|
| GET | /table/incident |
List/query incidents |
| POST | /table/incident |
Create new incident |
| PATCH | /table/incident/{sys_id} |
Update incident |
| DELETE | /table/incident/{sys_id} |
Delete incident |
Key Incident Fields
| Field | Description |
|---|---|
short_description |
Incident title |
description |
Full description |
urgency |
1 (High), 2 (Medium), 3 (Low) |
impact |
1 (High), 2 (Medium), 3 (Low) |
priority |
Auto-calculated from urgency + impact |
state |
1 (New) through 7 (Closed) |
assignment_group |
Team assigned |
work_notes |
Internal analyst notes |
close_code |
Resolution classification |
close_notes |
Resolution description |
Query Parameters
sysparm_query-- Encoded query stringsysparm_limit-- Max resultssysparm_fields-- Comma-separated fields to returnsysparm_display_value-- Return display values
TheHive API (v4/v5)
Cases
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/case |
Create case |
| GET | /api/case/{id} |
Get case details |
| PATCH | /api/case/{id} |
Update case |
| POST | /api/case/_search |
Search cases |
Tasks and Observables
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/case/{id}/task |
Add task to case |
| POST | /api/case/{id}/artifact |
Add observable/IOC |
Severity Levels
- 1: Low, 2: Medium, 3: High, 4: Critical
TLP Levels
- 0: WHITE, 1: GREEN, 2: AMBER, 3: RED
SLA Target Reference
- P1 (Critical): Response 15 min, Resolve 4 hours
- P2 (High): Response 30 min, Resolve 8 hours
- P3 (Medium): Response 4 hours, Resolve 24 hours
- P4 (Low): Response 8 hours, Resolve 72 hours
External References
- ServiceNow REST API: https://developer.servicenow.com/dev.do#!/reference/api/
- TheHive API: https://docs.strangebee.com/thehive/api-docs/
- Jira Service Management: https://developer.atlassian.com/cloud/jira/service-desk/rest/
- NIST Incident Handling: https://csrc.nist.gov/pubs/sp/800/61/r2/final
Scripts 1
agent.py9.8 KB
#!/usr/bin/env python3
"""Incident ticketing system agent supporting ServiceNow and TheHive."""
import json
import sys
import argparse
from datetime import datetime
try:
import requests
except ImportError:
print("Install requests: pip install requests")
sys.exit(1)
class ServiceNowClient:
"""Client for ServiceNow Incident Management REST API."""
def __init__(self, instance, username, password):
self.base_url = f"https://{instance}.service-now.com/api/now"
self.session = requests.Session()
self.session.auth = (username, password)
self.session.headers.update({"Accept": "application/json",
"Content-Type": "application/json"})
def create_incident(self, short_desc, description, urgency=2, impact=2, category="Security"):
"""Create a new security incident in ServiceNow."""
data = {"short_description": short_desc, "description": description,
"urgency": urgency, "impact": impact, "category": category,
"assignment_group": "Security Operations",
"contact_type": "Automated"}
resp = self.session.post(f"{self.base_url}/table/incident", json=data, timeout=30)
resp.raise_for_status()
result = resp.json().get("result", {})
return {"number": result.get("number"), "sys_id": result.get("sys_id"),
"state": result.get("state"), "priority": result.get("priority")}
def update_incident(self, sys_id, update_data):
"""Update an existing incident."""
resp = self.session.patch(f"{self.base_url}/table/incident/{sys_id}", json=update_data, timeout=30)
resp.raise_for_status()
return resp.json().get("result", {})
def get_incident(self, number):
"""Get incident details by number."""
resp = self.session.get(f"{self.base_url}/table/incident",
params={"sysparm_query": f"number={number}"}, timeout=30)
resp.raise_for_status()
results = resp.json().get("result", [])
return results[0] if results else None
def list_open_incidents(self, category="Security", limit=50):
"""List open security incidents."""
query = f"category={category}^state!=7^state!=8"
resp = self.session.get(f"{self.base_url}/table/incident",
params={"sysparm_query": query, "sysparm_limit": limit,
"sysparm_fields": "number,short_description,priority,state,"
"opened_at,assigned_to,urgency"}, timeout=30)
resp.raise_for_status()
return resp.json().get("result", [])
def add_work_note(self, sys_id, note):
"""Add a work note to an incident."""
return self.update_incident(sys_id, {"work_notes": note})
def close_incident(self, sys_id, close_notes, close_code="Solved (Permanently)"):
"""Close an incident with resolution notes."""
return self.update_incident(sys_id, {
"state": "7", "close_code": close_code,
"close_notes": close_notes})
class TheHiveClient:
"""Client for TheHive incident response platform API."""
def __init__(self, base_url, api_key):
self.base_url = base_url.rstrip("/")
self.session = requests.Session()
self.session.headers.update({"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"})
def create_case(self, title, description, severity=2, tlp=2, tags=None):
"""Create a new case in TheHive."""
data = {"title": title, "description": description,
"severity": severity, "tlp": tlp,
"tags": tags or ["security-incident"],
"flag": False, "status": "Open"}
resp = self.session.post(f"{self.base_url}/api/case", json=data, timeout=30)
resp.raise_for_status()
result = resp.json()
return {"id": result.get("_id"), "caseId": result.get("caseId"),
"title": result.get("title"), "status": result.get("status")}
def create_task(self, case_id, title, description="", group="default"):
"""Create a task within a case."""
data = {"title": title, "description": description, "group": group,
"status": "Waiting"}
resp = self.session.post(f"{self.base_url}/api/case/{case_id}/task", json=data, timeout=30)
resp.raise_for_status()
return resp.json()
def add_observable(self, case_id, data_type, data_value, tlp=2, message=""):
"""Add an observable (IOC) to a case."""
obs_data = {"dataType": data_type, "data": data_value, "tlp": tlp,
"message": message, "ioc": True}
resp = self.session.post(f"{self.base_url}/api/case/{case_id}/artifact", json=obs_data, timeout=30)
resp.raise_for_status()
return resp.json()
def list_cases(self, status="Open", limit=50):
"""List cases with optional status filter."""
query = {"query": {"_field": "status", "_value": status}}
resp = self.session.post(f"{self.base_url}/api/case/_search",
json=query, params={"range": f"0-{limit}"}, timeout=30)
resp.raise_for_status()
return resp.json()
def get_case(self, case_id):
"""Get case details."""
resp = self.session.get(f"{self.base_url}/api/case/{case_id}", timeout=30)
resp.raise_for_status()
return resp.json()
def close_case(self, case_id, summary, impact_status="NoImpact"):
"""Close a case with summary."""
data = {"status": "Resolved", "summary": summary,
"impactStatus": impact_status, "resolutionStatus": "TruePositive"}
resp = self.session.patch(f"{self.base_url}/api/case/{case_id}", json=data, timeout=30)
resp.raise_for_status()
return resp.json()
def calculate_sla_metrics(incidents):
"""Calculate SLA compliance metrics from incident data."""
sla_targets = {"1": 60, "2": 240, "3": 480, "4": 1440}
metrics = {"total": len(incidents), "within_sla": 0, "breached": 0,
"avg_response_min": 0, "by_priority": {}}
total_response = 0
for inc in incidents:
priority = str(inc.get("priority", "3"))
opened = inc.get("opened_at", "")
if priority not in metrics["by_priority"]:
metrics["by_priority"][priority] = {"total": 0, "within_sla": 0}
metrics["by_priority"][priority]["total"] += 1
metrics["sla_compliance_pct"] = round(
metrics["within_sla"] / max(metrics["total"], 1) * 100, 1)
return metrics
def run_ticketing_audit(snow_client=None, hive_client=None):
"""Run ticketing system audit."""
print(f"\n{'='*60}")
print(f" INCIDENT TICKETING SYSTEM AUDIT")
print(f" Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
print(f"{'='*60}\n")
report = {}
if snow_client:
incidents = snow_client.list_open_incidents()
print(f"--- SERVICENOW INCIDENTS ({len(incidents)} open) ---")
for inc in incidents[:10]:
print(f" [{inc.get('priority', 'N/A')}] {inc.get('number')}: "
f"{inc.get('short_description', '')[:50]}")
metrics = calculate_sla_metrics(incidents)
print(f"\n--- SLA METRICS ---")
print(f" Total open: {metrics['total']}")
print(f" SLA compliance: {metrics['sla_compliance_pct']}%")
report["servicenow"] = {"open": len(incidents), "metrics": metrics}
if hive_client:
cases = hive_client.list_cases()
print(f"\n--- THEHIVE CASES ({len(cases)} open) ---")
for case in cases[:10]:
print(f" [Sev:{case.get('severity', 'N/A')}] #{case.get('caseId')}: "
f"{case.get('title', '')[:50]}")
report["thehive"] = {"open_cases": len(cases)}
print(f"\n{'='*60}\n")
return report
def main():
parser = argparse.ArgumentParser(description="Incident Ticketing System Agent")
sub = parser.add_subparsers(dest="platform")
snow = sub.add_parser("servicenow")
snow.add_argument("--instance", required=True, help="ServiceNow instance name")
snow.add_argument("--username", required=True)
snow.add_argument("--password", required=True)
snow.add_argument("--audit", action="store_true")
snow.add_argument("--create", nargs=2, metavar=("TITLE", "DESC"), help="Create incident")
hive = sub.add_parser("thehive")
hive.add_argument("--url", required=True, help="TheHive URL")
hive.add_argument("--api-key", required=True)
hive.add_argument("--audit", action="store_true")
hive.add_argument("--create", nargs=2, metavar=("TITLE", "DESC"), help="Create case")
parser.add_argument("--output", help="Save report to JSON")
args = parser.parse_args()
if args.platform == "servicenow":
client = ServiceNowClient(args.instance, args.username, args.password)
if args.audit:
report = run_ticketing_audit(snow_client=client)
elif args.create:
result = client.create_incident(args.create[0], args.create[1])
print(json.dumps(result, indent=2))
return
else:
parser.print_help()
return
elif args.platform == "thehive":
client = TheHiveClient(args.url, args.api_key)
if args.audit:
report = run_ticketing_audit(hive_client=client)
elif args.create:
result = client.create_case(args.create[0], args.create[1])
print(json.dumps(result, indent=2))
return
else:
parser.print_help()
return
else:
parser.print_help()
return
if args.output:
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()