npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
NIST CSF 2.0
MITRE ATLAS
MITRE D3FEND
When to Use
- Investigating a security incident that requires correlation across multiple log sources
- Hunting for adversary activity using known TTPs and IOCs
- Building detection rules for specific attack patterns
- Reconstructing an incident timeline from disparate log sources
- Analyzing authentication anomalies, lateral movement, or data exfiltration patterns
Do not use for real-time packet-level analysis; use Wireshark or Zeek for full packet capture analysis.
Prerequisites
- Splunk Enterprise or Splunk Cloud with Enterprise Security (ES) app installed
- Log sources ingested: Windows Event Logs (via Splunk Universal Forwarder or WEF), firewall, proxy, DNS, EDR, email gateway
- Splunk CIM (Common Information Model) data models configured for normalized field names
- SPL proficiency at intermediate level or higher
- Role-based access with
searchandaccelerate_searchcapabilities in Splunk
Workflow
Step 1: Scope the Investigation in Splunk
Define search parameters based on incident triage data:
| Set initial investigation scope
index=windows OR index=firewall OR index=proxy
earliest="2025-11-14T00:00:00" latest="2025-11-16T00:00:00"
(host="WKSTN-042" OR src_ip="10.1.5.42" OR user="jsmith")
| stats count by index, sourcetype, host
| sort -countThis query establishes which log sources contain relevant data for the investigation timeframe and affected assets.
Step 2: Analyze Authentication Events
Investigate suspicious authentication patterns using Windows Security Event Logs:
| Detect brute force and credential stuffing
index=windows sourcetype="WinEventLog:Security" EventCode=4625
earliest=-24h
| stats count as failed_attempts, values(src_ip) as source_ips,
dc(src_ip) as unique_sources by TargetUserName
| where failed_attempts > 10
| sort -failed_attempts
| Detect pass-the-hash (Logon Type 9 - NewCredentials)
index=windows sourcetype="WinEventLog:Security" EventCode=4624
Logon_Type=9
| table _time, host, TargetUserName, src_ip, LogonProcessName
| Detect lateral movement via RDP
index=windows sourcetype="WinEventLog:Security" EventCode=4624
Logon_Type=10
| stats count, values(host) as targets by TargetUserName, src_ip
| where count > 3
| sort -countStep 3: Trace Process Execution
Use Sysmon logs to reconstruct process execution chains:
| Process creation with parent chain (Sysmon Event ID 1)
index=sysmon EventCode=1 host="WKSTN-042"
earliest="2025-11-15T14:00:00" latest="2025-11-15T15:00:00"
| table _time, ParentImage, ParentCommandLine, Image, CommandLine, User, Hashes
| sort _time
| Detect suspicious PowerShell execution
index=sysmon EventCode=1 Image="*\\powershell.exe"
(CommandLine="*-enc*" OR CommandLine="*-encodedcommand*"
OR CommandLine="*downloadstring*" OR CommandLine="*iex*")
| table _time, host, User, ParentImage, CommandLine
| sort _time
| Detect LSASS credential dumping
index=sysmon EventCode=10 TargetImage="*\\lsass.exe"
GrantedAccess=0x1010
| table _time, host, SourceImage, SourceUser, GrantedAccessStep 4: Analyze Network Activity
Correlate network logs with endpoint events:
| Detect C2 beaconing pattern
index=proxy OR index=firewall dest_ip="185.220.101.42"
| timechart span=1m count by src_ip
| where count > 0
| Detect DNS tunneling (high query volume to single domain)
index=dns
| rex field=query "(?<subdomain>[^\.]+)\.(?<domain>[^\.]+\.[^\.]+)$"
| stats count, avg(len(query)) as avg_query_len by domain, src_ip
| where count > 500 AND avg_query_len > 40
| sort -count
| Detect large data transfers (potential exfiltration)
index=proxy action=allowed
| stats sum(bytes_out) as total_bytes by src_ip, dest_ip, dest_host
| eval total_MB=round(total_bytes/1024/1024,2)
| where total_MB > 100
| sort -total_MBStep 5: Build the Incident Timeline
Reconstruct a unified timeline across all log sources:
| Unified incident timeline
index=windows OR index=sysmon OR index=proxy OR index=firewall
(host="WKSTN-042" OR src_ip="10.1.5.42" OR user="jsmith")
earliest="2025-11-15T14:00:00" latest="2025-11-15T16:00:00"
| eval event_summary=case(
sourcetype=="WinEventLog:Security" AND EventCode==4624, "Logon: ".TargetUserName." from ".src_ip,
sourcetype=="WinEventLog:Security" AND EventCode==4625, "Failed logon: ".TargetUserName,
sourcetype=="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" AND EventCode==1,
"Process: ".Image." by ".User,
sourcetype=="proxy", "Web: ".http_method." ".url,
1==1, sourcetype.": ".EventCode)
| table _time, sourcetype, host, event_summary
| sort _timeStep 6: Create Detection Rules
Convert investigation findings into persistent Splunk correlation searches:
| Correlation search: PowerShell spawned by Office applications
index=sysmon EventCode=1
Image="*\\powershell.exe"
(ParentImage="*\\winword.exe" OR ParentImage="*\\excel.exe"
OR ParentImage="*\\outlook.exe")
| eval severity="high"
| eval mitre_technique="T1059.001"
| collect index=notable_eventsKey Concepts
| Term | Definition |
|---|---|
| SPL (Search Processing Language) | Splunk's query language for searching, filtering, transforming, and visualizing machine data |
| CIM (Common Information Model) | Splunk's field normalization standard that maps vendor-specific field names to common names for cross-source queries |
| Notable Event | An event in Splunk Enterprise Security flagged for analyst review based on a correlation search match |
| Data Model | Structured representation of indexed data in Splunk enabling accelerated searches and pivot-based analysis |
| Sourcetype | Classification label in Splunk that defines the format and parsing rules for a specific log type |
| Correlation Search | Scheduled Splunk search that runs continuously and generates notable events when conditions are met |
| Timechart | SPL command that creates time-series visualizations for identifying patterns, anomalies, and trends |
Tools & Systems
- Splunk Enterprise Security (ES): Premium SIEM application providing correlation searches, risk-based alerting, and investigation workbench
- Splunk SOAR: Orchestration platform integrated with Splunk ES for automated response playbooks
- Sysmon: Microsoft system monitoring tool providing detailed process, network, and file change telemetry ingested into Splunk
- Splunk Attack Analyzer: Automated threat analysis that detonates suspicious files and URLs, feeding results into Splunk
- BOSS of the SOC (BOTS): SANS/Splunk training dataset for practicing incident investigation SPL queries
Common Scenarios
Scenario: Investigating Credential Stuffing Leading to Account Takeover
Context: Security operations receives an alert for multiple successful logins to a single account from geographically dispersed IP addresses within a 30-minute window.
Approach:
- Query Event ID 4624 for the affected account to map all login sources and times
- Correlate login IPs against threat intelligence feeds using a Splunk lookup table
- Check proxy logs for suspicious activity from the authenticated sessions
- Search for lateral movement from the compromised account (Event ID 4624 Type 3 to other hosts)
- Build a timeline showing credential stuffing attempts, successful login, and post-compromise activity
- Create a correlation search to detect similar patterns on other accounts
Pitfalls:
- Searching only the last 24 hours when the credential stuffing may have occurred over weeks
- Not checking for VPN logs that may show the same account authenticating from impossible travel distances
- Failing to normalize timestamps across log sources in different time zones
Output Format
SPLUNK INVESTIGATION REPORT
============================
Incident: INC-2025-1547
Analyst: [Name]
Investigation Period: 2025-11-14 00:00 UTC - 2025-11-16 00:00 UTC
SEARCH SCOPE
Indexes: windows, sysmon, proxy, firewall, dns
Hosts: WKSTN-042, SRV-FILE01
Users: jsmith, svc-backup
Source IPs: 10.1.5.42, 10.1.10.15
KEY FINDINGS
1. [timestamp] - Initial compromise via phishing (Sysmon Event 1)
2. [timestamp] - C2 established (proxy logs, beacon pattern detected)
3. [timestamp] - Credential theft (Sysmon Event 10, LSASS access)
4. [timestamp] - Lateral movement to SRV-FILE01 (Event 4624 Type 3)
5. [timestamp] - Data staging and exfiltration (proxy bytes_out anomaly)
SPL QUERIES USED
[numbered list of key queries with descriptions]
DETECTION GAPS IDENTIFIED
- No Sysmon deployed on SRV-FILE01 (blind spot)
- Proxy logs missing SSL inspection for C2 domain
- PowerShell ScriptBlock logging not enabled
RECOMMENDED DETECTIONS
1. Correlation search for Office-spawned PowerShell
2. Threshold alert for LSASS access patterns
3. Behavioral rule for beacon-interval network trafficReferences and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.5 KB
API Reference: Analyzing Security Logs with Splunk
splunk-sdk (splunklib)
Connection
import splunklib.client as client
service = client.connect(
host="splunk.example.com",
port=8089,
username="admin",
password="secret",
autologin=True,
)Running Searches
import splunklib.results as results
# Blocking (synchronous) search
job = service.jobs.create(
"search index=windows EventCode=4625 | stats count by src_ip",
**{"earliest_time": "-24h", "latest_time": "now", "exec_mode": "blocking"}
)
# Read results as JSON
reader = results.JSONResultsReader(job.results(output_mode="json"))
for row in reader:
if isinstance(row, dict):
print(row)
job.cancel()Oneshot Search (Simple Queries)
result_stream = service.jobs.oneshot(
"search index=windows EventCode=4624 | head 10",
earliest_time="-1h",
output_mode="json",
)
reader = results.JSONResultsReader(result_stream)Saved Searches
# List saved searches
for saved in service.saved_searches:
print(saved.name)
# Run a saved search
saved_search = service.saved_searches["My Alert"]
job = saved_search.dispatch()KV Store Lookups
collection = service.kvstore["threat_intel_iocs"]
# Insert record
collection.data.insert(json.dumps({"ip": "1.2.3.4", "threat": "C2"}))
# Query records
records = collection.data.query(query=json.dumps({"threat": "C2"}))Key SPL Patterns for Security Analysis
| Pattern | SPL |
|---|---|
| Failed logons | index=windows EventCode=4625 | stats count by src_ip |
| Lateral movement | index=windows EventCode=4624 Logon_Type=3 | stats dc(host) by src_ip |
| Process creation | index=sysmon EventCode=1 | table _time, Image, CommandLine |
| C2 beaconing | index=proxy | timechart span=1m count by dest_ip |
| DNS tunneling | index=dns | stats count, avg(len(query)) by domain |
Splunk REST API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/services/search/jobs |
POST | Create a new search job |
/services/search/jobs/{sid}/results |
GET | Retrieve search results |
/services/saved/searches |
GET | List saved searches |
/services/data/indexes |
GET | List available indexes |
/services/authentication/users |
GET | List Splunk users |
References
- splunk-sdk PyPI: https://pypi.org/project/splunk-sdk/
- Splunk REST API docs: https://docs.splunk.com/Documentation/Splunk/latest/RESTREF
- Splunk SDK for Python: https://dev.splunk.com/enterprise/docs/devtools/python/sdk-python/
Scripts 1
agent.py6.4 KB
#!/usr/bin/env python3
"""Agent for analyzing security logs with Splunk using splunk-sdk."""
import os
import json
import time
import argparse
from datetime import datetime
import splunklib.client as client
import splunklib.results as results
def connect_splunk(host, port, username, password):
"""Establish connection to Splunk instance."""
service = client.connect(
host=host,
port=port,
username=username,
password=password,
autologin=True,
)
return service
def run_search(service, query, earliest="-24h", latest="now"):
"""Execute a Splunk search and return parsed results."""
kwargs_search = {
"earliest_time": earliest,
"latest_time": latest,
"search_mode": "normal",
"exec_mode": "blocking",
}
job = service.jobs.create(f"search {query}", **kwargs_search)
reader = results.JSONResultsReader(job.results(output_mode="json"))
rows = [row for row in reader if isinstance(row, dict)]
job.cancel()
return rows
def detect_brute_force(service, threshold=10, earliest="-24h"):
"""Detect brute force attacks via failed logon events (EventCode 4625)."""
query = (
'index=windows sourcetype="WinEventLog:Security" EventCode=4625 '
f"| stats count as failed_attempts, dc(src_ip) as unique_sources, "
f"values(src_ip) as source_ips by TargetUserName "
f"| where failed_attempts > {threshold} "
f"| sort -failed_attempts"
)
return run_search(service, query, earliest=earliest)
def detect_lateral_movement(service, earliest="-24h"):
"""Detect lateral movement via Type 3 network logons to multiple hosts."""
query = (
'index=windows sourcetype="WinEventLog:Security" EventCode=4624 '
"Logon_Type=3 "
"| stats dc(ComputerName) as unique_targets, values(ComputerName) as targets "
"by TargetUserName, src_ip "
"| where unique_targets > 3 "
"| sort -unique_targets"
)
return run_search(service, query, earliest=earliest)
def detect_suspicious_powershell(service, earliest="-24h"):
"""Detect encoded or download-cradle PowerShell execution via Sysmon."""
query = (
'index=sysmon EventCode=1 Image="*\\\\powershell.exe" '
'(CommandLine="*-enc*" OR CommandLine="*-encodedcommand*" '
'OR CommandLine="*downloadstring*" OR CommandLine="*iex*") '
"| table _time, host, User, ParentImage, CommandLine "
"| sort _time"
)
return run_search(service, query, earliest=earliest)
def detect_lsass_access(service, earliest="-24h"):
"""Detect credential dumping via LSASS process access (Sysmon Event 10)."""
query = (
'index=sysmon EventCode=10 TargetImage="*\\\\lsass.exe" '
"GrantedAccess=0x1010 "
"| table _time, host, SourceImage, SourceUser, GrantedAccess"
)
return run_search(service, query, earliest=earliest)
def build_incident_timeline(service, hosts, users, earliest="-24h", latest="now"):
"""Build a unified incident timeline across multiple log sources."""
host_filter = " OR ".join(f'host="{h}"' for h in hosts)
user_filter = " OR ".join(f'user="{u}"' for u in users)
query = (
f"index=windows OR index=sysmon OR index=proxy OR index=firewall "
f"({host_filter} OR {user_filter}) "
'| eval event_summary=case('
' sourcetype=="WinEventLog:Security" AND EventCode==4624, '
' "Logon: ".TargetUserName." from ".src_ip, '
' sourcetype=="WinEventLog:Security" AND EventCode==4625, '
' "Failed logon: ".TargetUserName, '
' EventCode==1, "Process: ".Image." by ".User, '
' 1==1, sourcetype.": ".EventCode) '
"| table _time, sourcetype, host, event_summary "
"| sort _time"
)
return run_search(service, query, earliest=earliest, latest=latest)
def generate_report(findings):
"""Format investigation findings into a structured report."""
report = {
"report_type": "SPLUNK INVESTIGATION REPORT",
"generated_at": datetime.utcnow().isoformat() + "Z",
"findings": findings,
}
return json.dumps(report, indent=2, default=str)
def main():
parser = argparse.ArgumentParser(description="Splunk Security Log Analysis Agent")
parser.add_argument("--host", default=os.getenv("SPLUNK_HOST", "localhost"))
parser.add_argument("--port", type=int, default=int(os.getenv("SPLUNK_PORT", "8089")))
parser.add_argument("--username", default=os.getenv("SPLUNK_USERNAME", "admin"))
parser.add_argument("--password", default=os.getenv("SPLUNK_PASSWORD", ""))
parser.add_argument("--earliest", default="-24h", help="Search earliest time")
parser.add_argument("--action", choices=[
"brute_force", "lateral_movement", "powershell",
"lsass_access", "timeline", "full_investigation"
], default="full_investigation")
parser.add_argument("--hosts", nargs="*", default=[], help="Target hosts for timeline")
parser.add_argument("--users", nargs="*", default=[], help="Target users for timeline")
parser.add_argument("--threshold", type=int, default=10)
args = parser.parse_args()
service = connect_splunk(args.host, args.port, args.username, args.password)
findings = {}
if args.action in ("brute_force", "full_investigation"):
findings["brute_force"] = detect_brute_force(service, args.threshold, args.earliest)
print(f"[+] Brute force: {len(findings['brute_force'])} accounts targeted")
if args.action in ("lateral_movement", "full_investigation"):
findings["lateral_movement"] = detect_lateral_movement(service, args.earliest)
print(f"[+] Lateral movement: {len(findings['lateral_movement'])} suspicious paths")
if args.action in ("powershell", "full_investigation"):
findings["suspicious_powershell"] = detect_suspicious_powershell(service, args.earliest)
print(f"[+] Suspicious PowerShell: {len(findings['suspicious_powershell'])} events")
if args.action in ("lsass_access", "full_investigation"):
findings["lsass_access"] = detect_lsass_access(service, args.earliest)
print(f"[+] LSASS access: {len(findings['lsass_access'])} events")
if args.action == "timeline" and args.hosts:
findings["timeline"] = build_incident_timeline(
service, args.hosts, args.users, args.earliest
)
print(f"[+] Timeline: {len(findings['timeline'])} events")
print(generate_report(findings))
if __name__ == "__main__":
main()