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:
mukul975
2026-03-10 21:02:12 +01:00
parent c74d52fa30
commit 27c6414ca5
1390 changed files with 106806 additions and 0 deletions
@@ -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,52 @@
---
name: implementing-siem-correlation-rules-for-apt
description: >-
Write multi-event correlation rules that detect APT lateral movement by chaining Windows authentication events,
process execution telemetry, and network connection logs across hosts. Uses Splunk SPL and Sigma rule format
to correlate Event IDs 4624, 4648, 4688, and Sysmon Events 1/3 within sliding time windows to surface attack
sequences invisible to single-event detections.
---
## Instructions
1. Install dependencies: `pip install requests pyyaml sigma-cli`
2. Connect to the Splunk REST API and define correlation searches that chain multiple event types across hosts.
3. Build Sigma rules in YAML that express multi-step detection logic for lateral movement patterns:
- RDP logon (4624 LogonType=10) followed by service installation (7045) on same target within 15 minutes
- Pass-the-Hash: NTLM logon (4624 LogonType=3) followed by process creation (4688) of admin tools
- PsExec-style: Named pipe creation (Sysmon 17/18) correlated with remote service creation (7045)
4. Convert Sigma rules to Splunk SPL using `sigma-cli convert`.
5. Deploy correlation searches to Splunk ES via the REST API.
6. Run the agent to generate and install correlation rules, then audit existing rules for coverage gaps.
```bash
python scripts/agent.py --splunk-url https://localhost:8089 --username admin --password changeme --output correlation_report.json
```
## Examples
### Detect RDP Lateral Movement Chain
```
index=wineventlog (EventCode=4624 Logon_Type=10) OR (EventCode=7045)
| transaction Computer maxspan=15m startswith=(EventCode=4624) endswith=(EventCode=7045)
| where eventcount >= 2
| table _time Computer Account_Name ServiceName
```
### Sigma Rule for PsExec Lateral Movement
```yaml
title: PsExec Lateral Movement Detection
logsource:
product: windows
service: sysmon
detection:
pipe_created:
EventID: 17
PipeName|startswith: '\PSEXESVC'
service_installed:
EventID: 7045
ServiceFileName|contains: 'PSEXESVC'
timeframe: 5m
condition: pipe_created | near service_installed
level: high
```
@@ -0,0 +1,61 @@
# API Reference: SIEM Correlation Rules for APT
## Splunk REST API
### Authentication
```
POST /services/auth/login
Body: username=<user>&password=<pass>
Returns: { "sessionKey": "<token>" }
Header: Authorization: Splunk <sessionKey>
```
### Saved Searches (Correlation Rules)
```
POST /services/saved/searches
Parameters: name, search, cron_schedule, dispatch.earliest_time,
dispatch.latest_time, alert.severity, action.notable (1=enabled),
action.notable.param.severity, action.notable.param.security_domain
GET /services/saved/searches?output_mode=json&count=0
```
### Search Jobs
```
POST /services/search/jobs
Body: search=<SPL>, earliest_time, latest_time, output_mode=json
Returns: { "sid": "<job_id>" }
GET /services/search/jobs/<sid>?output_mode=json
GET /services/search/jobs/<sid>/results?output_mode=json&count=<n>
```
## Sigma Rule Format (YAML)
```yaml
title: <string>
status: experimental|test|stable
logsource:
product: windows
service: sysmon|security
detection:
selection: { EventID: [1,3] }
condition: selection
level: low|medium|high|critical
tags: [attack.t1021.001]
```
## sigma-cli Conversion
```bash
sigma convert -t splunk -p sysmon rule.yml
sigma convert -t elastic-eql -p sysmon rule.yml
```
## Key Windows Event IDs for Lateral Movement
| Event ID | Source | Description |
|----------|--------|-------------|
| 4624 | Security | Logon event (Type 3=Network, 10=RDP) |
| 4648 | Security | Explicit credential logon |
| 4688 | Security | Process creation |
| 7045 | System | Service installation |
| 1 | Sysmon | Process creation with hashes |
| 3 | Sysmon | Network connection |
| 10 | Sysmon | Process access (LSASS) |
| 17/18 | Sysmon | Named pipe created/connected |
@@ -0,0 +1,249 @@
#!/usr/bin/env python3
"""SIEM Correlation Rules Agent - Builds and deploys multi-event APT detection rules via Splunk and Sigma."""
import json
import time
import logging
import argparse
from datetime import datetime
import yaml
import requests
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
LATERAL_MOVEMENT_RULES = [
{
"name": "RDP Lateral Movement Chain",
"description": "RDP logon followed by service installation on same host within 15 minutes",
"spl": (
'index=wineventlog (EventCode=4624 Logon_Type=10) OR (EventCode=7045) '
'| transaction Computer maxspan=15m startswith=(EventCode=4624) endswith=(EventCode=7045) '
'| where eventcount >= 2 '
'| table _time Computer Account_Name ServiceName'
),
"severity": "high",
"mitre": "T1021.001",
},
{
"name": "PsExec Service Installation",
"description": "Named pipe PSEXESVC created followed by remote service install",
"spl": (
'index=sysmon (EventCode=17 PipeName="\\\\PSEXESVC*") OR '
'(index=wineventlog EventCode=7045 ServiceFileName="*PSEXESVC*") '
'| transaction Computer maxspan=5m '
'| where eventcount >= 2 '
'| table _time Computer User Image ServiceName'
),
"severity": "high",
"mitre": "T1021.002",
},
{
"name": "NTLM Pass-the-Hash Followed by Admin Tool",
"description": "NTLM network logon followed by admin tool execution within 10 minutes",
"spl": (
'index=wineventlog EventCode=4624 Logon_Type=3 Authentication_Package=NTLM '
'| join Computer maxspan=10m [search index=sysmon EventCode=1 '
'(Image="*\\\\net.exe" OR Image="*\\\\net1.exe" OR Image="*\\\\wmic.exe" '
'OR Image="*\\\\psexec.exe" OR Image="*\\\\powershell.exe")] '
'| table _time Computer Account_Name Image CommandLine'
),
"severity": "critical",
"mitre": "T1550.002",
},
{
"name": "WMI Remote Execution Chain",
"description": "WMI process creation on remote host correlated with network logon",
"spl": (
'index=sysmon EventCode=1 ParentImage="*\\\\WmiPrvSE.exe" '
'| join Computer [search index=wineventlog EventCode=4624 Logon_Type=3] '
'| where Account_Name!="-" '
'| stats count by Computer, Account_Name, Image, CommandLine '
'| where count > 0'
),
"severity": "high",
"mitre": "T1047",
},
{
"name": "Credential Dumping After Lateral Move",
"description": "Network logon followed by LSASS access within 30 minutes",
"spl": (
'index=wineventlog EventCode=4624 Logon_Type=3 '
'| join Computer maxspan=30m [search index=sysmon EventCode=10 '
'TargetImage="*\\\\lsass.exe" GrantedAccess=0x1010] '
'| table _time Computer Account_Name SourceImage GrantedAccess'
),
"severity": "critical",
"mitre": "T1003.001",
},
]
def authenticate_splunk(base_url, username, password):
"""Authenticate to Splunk and return session headers."""
resp = requests.post(
f"{base_url}/services/auth/login",
data={"username": username, "password": password},
verify=False,
)
resp.raise_for_status()
session_key = resp.json()["sessionKey"]
logger.info("Authenticated to Splunk")
return {"Authorization": f"Splunk {session_key}"}
def deploy_correlation_search(base_url, headers, rule):
"""Deploy a correlation search to Splunk ES."""
search_payload = {
"search": f"search {rule['spl']}",
"name": rule["name"],
"description": rule["description"],
"cron_schedule": "*/15 * * * *",
"dispatch.earliest_time": "-15m",
"dispatch.latest_time": "now",
"alert_type": "always",
"alert.severity": "4" if rule["severity"] == "critical" else "3",
"action.notable": "1",
"action.notable.param.security_domain": "threat",
"action.notable.param.severity": rule["severity"],
"action.notable.param.rule_title": rule["name"],
}
resp = requests.post(
f"{base_url}/services/saved/searches",
headers=headers,
data=search_payload,
verify=False,
)
if resp.status_code in (200, 201):
logger.info("Deployed correlation search: %s", rule["name"])
return True
logger.warning("Deploy failed for %s: %d %s", rule["name"], resp.status_code, resp.text[:100])
return False
def generate_sigma_rule(rule):
"""Generate a Sigma-format YAML rule from a correlation definition."""
sigma = {
"title": rule["name"],
"id": None,
"status": "experimental",
"description": rule["description"],
"references": [f"https://attack.mitre.org/techniques/{rule['mitre']}/"],
"logsource": {"product": "windows", "service": "sysmon"},
"detection": {
"selection": {"EventID": [1, 3, 17, 18]},
"condition": "selection",
},
"level": rule["severity"],
"tags": [f"attack.{rule['mitre'].lower()}"],
}
return yaml.dump(sigma, default_flow_style=False, sort_keys=False)
def audit_existing_searches(base_url, headers):
"""Audit existing Splunk saved searches for coverage gaps."""
resp = requests.get(
f"{base_url}/services/saved/searches",
headers=headers,
params={"output_mode": "json", "count": 0},
verify=False,
)
if resp.status_code != 200:
return []
searches = resp.json().get("entry", [])
mitre_covered = set()
for s in searches:
content = s.get("content", {})
search_text = content.get("search", "").lower()
for technique in ["t1021", "t1047", "t1053", "t1550", "t1003"]:
if technique in search_text or technique in s.get("name", "").lower():
mitre_covered.add(technique)
lateral_techniques = {"t1021", "t1047", "t1053", "t1550", "t1003", "t1059", "t1570"}
gaps = lateral_techniques - mitre_covered
logger.info("Coverage: %d/%d lateral movement techniques covered", len(mitre_covered), len(lateral_techniques))
return list(gaps)
def run_test_search(base_url, headers, spl, earliest="-24h"):
"""Execute a correlation search and return matching events."""
resp = requests.post(
f"{base_url}/services/search/jobs",
headers=headers,
data={"search": f"search {spl}", "earliest_time": earliest, "output_mode": "json"},
verify=False,
)
resp.raise_for_status()
sid = resp.json()["sid"]
for _ in range(60):
status = requests.get(
f"{base_url}/services/search/jobs/{sid}",
headers=headers, params={"output_mode": "json"}, verify=False,
).json()
if status["entry"][0]["content"]["isDone"]:
break
time.sleep(2)
results = requests.get(
f"{base_url}/services/search/jobs/{sid}/results",
headers=headers, params={"output_mode": "json", "count": 50}, verify=False,
).json()
return results.get("results", [])
def generate_report(deployed, gaps, test_results):
"""Generate correlation rules deployment report."""
report = {
"timestamp": datetime.utcnow().isoformat(),
"rules_deployed": deployed,
"coverage_gaps": gaps,
"test_results_summary": {r["name"]: len(r.get("hits", [])) for r in test_results},
}
print(f"CORRELATION RULES REPORT: {len(deployed)} deployed, {len(gaps)} gaps")
return report
def main():
parser = argparse.ArgumentParser(description="SIEM Correlation Rules Agent")
parser.add_argument("--splunk-url", default="https://localhost:8089")
parser.add_argument("--username", default="admin")
parser.add_argument("--password", required=True)
parser.add_argument("--deploy", action="store_true", help="Deploy rules to Splunk")
parser.add_argument("--test", action="store_true", help="Test rules against recent data")
parser.add_argument("--sigma-export", help="Export rules as Sigma YAML to directory")
parser.add_argument("--output", default="correlation_report.json")
args = parser.parse_args()
headers = authenticate_splunk(args.splunk_url, args.username, args.password)
deployed = []
test_results = []
if args.deploy:
for rule in LATERAL_MOVEMENT_RULES:
if deploy_correlation_search(args.splunk_url, headers, rule):
deployed.append(rule["name"])
if args.test:
for rule in LATERAL_MOVEMENT_RULES:
hits = run_test_search(args.splunk_url, headers, rule["spl"])
test_results.append({"name": rule["name"], "hits": hits})
logger.info("Rule '%s': %d hits", rule["name"], len(hits))
if args.sigma_export:
import os
os.makedirs(args.sigma_export, exist_ok=True)
for rule in LATERAL_MOVEMENT_RULES:
sigma_yaml = generate_sigma_rule(rule)
fname = rule["name"].lower().replace(" ", "_") + ".yml"
with open(os.path.join(args.sigma_export, fname), "w") as f:
f.write(sigma_yaml)
logger.info("Exported %d Sigma rules", len(LATERAL_MOVEMENT_RULES))
gaps = audit_existing_searches(args.splunk_url, headers)
report = generate_report(deployed, gaps, test_results)
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()