mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-20 06:20:58 +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,49 @@
|
||||
# API Reference: Implementing Alert Fatigue Reduction
|
||||
|
||||
## Libraries
|
||||
|
||||
### splunk-sdk (Splunk SDK for Python)
|
||||
- **Install**: `pip install splunk-sdk`
|
||||
- **Docs**: https://dev.splunk.com/enterprise/docs/devtools/python/sdk-python/
|
||||
- `splunklib.client.connect(host, port, username, password)` -- Connect to Splunk
|
||||
- `service.jobs.create(query)` -- Execute a search query
|
||||
- `job.is_done()` -- Check if search job completed
|
||||
- `job.results(output_mode="json")` -- Retrieve results in JSON format
|
||||
- `splunklib.results.JSONResultsReader(stream)` -- Parse JSON results
|
||||
|
||||
### Splunk ES Notable Events API
|
||||
- **Endpoint**: `/services/notable_update`
|
||||
- **Methods**: POST to update notable event status
|
||||
- **Fields**: `status`, `urgency`, `owner`, `comment`, `ruleUIDs`
|
||||
- **Status values**: `0` (Unassigned), `1` (New), `2` (In Progress), `5` (Resolved)
|
||||
|
||||
## Key SPL Queries
|
||||
|
||||
| Purpose | Key Functions |
|
||||
|---------|--------------|
|
||||
| Alert volume analysis | `stats count by rule_name`, `eval fp_rate` |
|
||||
| Risk-based alerting | `collect index=risk`, `eval risk_score` |
|
||||
| Alert consolidation | `dedup src, rule_name span=300` |
|
||||
| Capacity calculation | `bin _time span=1d`, `stats avg(daily_alerts)` |
|
||||
| Tiered routing | `eval routing = case(urgency, ...)` |
|
||||
|
||||
## Risk-Based Alerting (RBA) Framework
|
||||
- Risk contributions replace individual alerts
|
||||
- `index=risk` stores cumulative risk scores per entity
|
||||
- Threshold alert fires only when `total_risk >= 75`
|
||||
- Typical risk score ranges: 5 (low) to 50 (critical)
|
||||
|
||||
## Metrics Targets
|
||||
|
||||
| Metric | Target |
|
||||
|--------|--------|
|
||||
| False Positive Rate | < 30% per production rule |
|
||||
| Alerts/Analyst/Shift | 40-60 (manageable range) |
|
||||
| Signal-to-Noise Ratio | > 1.0 |
|
||||
| MTTD | Under 15 minutes for critical |
|
||||
| MTTR | Under 4 hours for high severity |
|
||||
|
||||
## External References
|
||||
- Splunk ES RBA Docs: https://docs.splunk.com/Documentation/ES/latest/Admin/RBA
|
||||
- Splunk SDK Python: https://github.com/splunk/splunk-sdk-python
|
||||
- MITRE ATT&CK Detection: https://attack.mitre.org/resources/
|
||||
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Alert fatigue reduction agent for SOC operations using Splunk SDK."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import argparse
|
||||
from datetime import datetime, timedelta
|
||||
from collections import defaultdict
|
||||
|
||||
try:
|
||||
import splunklib.client as splunk_client
|
||||
import splunklib.results as splunk_results
|
||||
except ImportError:
|
||||
print("Install splunk-sdk: pip install splunk-sdk")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def connect_splunk(host, port, username, password):
|
||||
"""Connect to Splunk instance."""
|
||||
return splunk_client.connect(host=host, port=port,
|
||||
username=username, password=password)
|
||||
|
||||
|
||||
def get_alert_quality_metrics(service, days=90):
|
||||
"""Query alert disposition data to measure alert quality."""
|
||||
query = f"""search index=notable earliest=-{days}d
|
||||
| stats count AS total_alerts,
|
||||
sum(eval(if(status_label="Resolved - True Positive", 1, 0))) AS tp,
|
||||
sum(eval(if(status_label="Resolved - False Positive", 1, 0))) AS fp,
|
||||
sum(eval(if(status_label="Resolved - Benign", 1, 0))) AS benign,
|
||||
sum(eval(if(status_label="New" OR status_label="In Progress", 1, 0))) AS unresolved
|
||||
by rule_name
|
||||
| eval fp_rate = round(fp / total_alerts * 100, 1)
|
||||
| eval tp_rate = round(tp / total_alerts * 100, 1)
|
||||
| eval snr = round(tp / (fp + 0.01), 2)
|
||||
| sort - total_alerts"""
|
||||
job = service.jobs.create(query)
|
||||
while not job.is_done():
|
||||
pass
|
||||
return [row for row in splunk_results.JSONResultsReader(job.results(output_mode="json"))]
|
||||
|
||||
|
||||
def identify_noisy_rules(metrics, fp_threshold=70, volume_threshold=500):
|
||||
"""Identify rules exceeding false positive or volume thresholds."""
|
||||
noisy = []
|
||||
for rule in metrics:
|
||||
fp_rate = float(rule.get("fp_rate", 0))
|
||||
total = int(rule.get("total_alerts", 0))
|
||||
if fp_rate > fp_threshold or total > volume_threshold:
|
||||
noisy.append({
|
||||
"rule_name": rule.get("rule_name", "unknown"),
|
||||
"total_alerts": total,
|
||||
"fp_rate": fp_rate,
|
||||
"tp_rate": float(rule.get("tp_rate", 0)),
|
||||
"signal_to_noise": float(rule.get("snr", 0)),
|
||||
"recommendation": "TUNE" if fp_rate > fp_threshold else "CONSOLIDATE"
|
||||
})
|
||||
return sorted(noisy, key=lambda x: -x["fp_rate"])
|
||||
|
||||
|
||||
def calculate_analyst_capacity(service, num_analysts=6, days=30):
|
||||
"""Calculate alerts per analyst per shift."""
|
||||
query = f"""search index=notable earliest=-{days}d
|
||||
| bin _time span=1d
|
||||
| stats count AS daily_alerts by _time
|
||||
| stats avg(daily_alerts) AS avg_daily, max(daily_alerts) AS peak_daily"""
|
||||
job = service.jobs.create(query)
|
||||
while not job.is_done():
|
||||
pass
|
||||
results = [r for r in splunk_results.JSONResultsReader(job.results(output_mode="json"))]
|
||||
if results:
|
||||
avg_daily = float(results[0].get("avg_daily", 0))
|
||||
peak_daily = float(results[0].get("peak_daily", 0))
|
||||
per_analyst = round(avg_daily / num_analysts)
|
||||
status = "CRITICAL" if per_analyst > 100 else "WARNING" if per_analyst > 50 else "HEALTHY"
|
||||
return {"avg_daily": avg_daily, "peak_daily": peak_daily,
|
||||
"per_analyst": per_analyst, "status": status}
|
||||
return None
|
||||
|
||||
|
||||
def generate_rba_conversion_plan(noisy_rules):
|
||||
"""Generate a plan to convert threshold alerts to risk-based alerting."""
|
||||
plan = []
|
||||
for rule in noisy_rules[:15]:
|
||||
plan.append({
|
||||
"rule_name": rule["rule_name"],
|
||||
"current_fp_rate": rule["fp_rate"],
|
||||
"action": "Convert to risk contribution",
|
||||
"risk_score_suggestion": 10 if rule["fp_rate"] > 90 else 20 if rule["fp_rate"] > 70 else 30,
|
||||
"estimated_alert_reduction": f"{int(rule['total_alerts'] * rule['fp_rate'] / 100)} alerts/period",
|
||||
})
|
||||
return plan
|
||||
|
||||
|
||||
def generate_tuning_recommendations(noisy_rules):
|
||||
"""Generate tuning recommendations for noisy rules."""
|
||||
recommendations = []
|
||||
for rule in noisy_rules:
|
||||
rec = {"rule_name": rule["rule_name"], "fp_rate": rule["fp_rate"], "actions": []}
|
||||
if rule["fp_rate"] > 90:
|
||||
rec["actions"].append("Disable rule and replace with risk contribution")
|
||||
rec["actions"].append("Investigate top FP sources for whitelist candidates")
|
||||
elif rule["fp_rate"] > 70:
|
||||
rec["actions"].append("Add exclusion list for known legitimate sources")
|
||||
rec["actions"].append("Narrow detection scope with additional filters")
|
||||
else:
|
||||
rec["actions"].append("Review and consolidate with related rules")
|
||||
recommendations.append(rec)
|
||||
return recommendations
|
||||
|
||||
|
||||
def build_fatigue_report(service, num_analysts=6):
|
||||
"""Build comprehensive alert fatigue reduction report."""
|
||||
print(f"\n{'='*60}")
|
||||
print(f" ALERT FATIGUE REDUCTION ANALYSIS")
|
||||
print(f" Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
metrics = get_alert_quality_metrics(service)
|
||||
noisy = identify_noisy_rules(metrics)
|
||||
capacity = calculate_analyst_capacity(service, num_analysts)
|
||||
|
||||
if capacity:
|
||||
print(f"--- ANALYST CAPACITY ---")
|
||||
print(f" Avg Daily Alerts: {capacity['avg_daily']:.0f}")
|
||||
print(f" Peak Daily Alerts: {capacity['peak_daily']:.0f}")
|
||||
print(f" Alerts/Analyst/Shift: {capacity['per_analyst']}")
|
||||
print(f" Status: {capacity['status']}\n")
|
||||
|
||||
print(f"--- TOP NOISY RULES ({len(noisy)} identified) ---")
|
||||
for r in noisy[:10]:
|
||||
print(f" [{r['recommendation']}] {r['rule_name']}")
|
||||
print(f" Volume: {r['total_alerts']} FP Rate: {r['fp_rate']}% SNR: {r['signal_to_noise']}")
|
||||
|
||||
rba_plan = generate_rba_conversion_plan(noisy)
|
||||
print(f"\n--- RBA CONVERSION PLAN ({len(rba_plan)} rules) ---")
|
||||
total_reduction = 0
|
||||
for p in rba_plan:
|
||||
print(f" {p['rule_name']}: risk_score={p['risk_score_suggestion']}, "
|
||||
f"reduction={p['estimated_alert_reduction']}")
|
||||
|
||||
tuning = generate_tuning_recommendations(noisy)
|
||||
print(f"\n--- TUNING RECOMMENDATIONS ---")
|
||||
for t in tuning[:5]:
|
||||
print(f" {t['rule_name']} (FP: {t['fp_rate']}%):")
|
||||
for a in t["actions"]:
|
||||
print(f" -> {a}")
|
||||
|
||||
print(f"\n{'='*60}\n")
|
||||
return {"metrics": metrics, "noisy_rules": noisy, "rba_plan": rba_plan, "tuning": tuning}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Alert Fatigue Reduction Agent")
|
||||
parser.add_argument("--host", default="localhost", help="Splunk host")
|
||||
parser.add_argument("--port", type=int, default=8089, help="Splunk management port")
|
||||
parser.add_argument("--username", default="admin", help="Splunk username")
|
||||
parser.add_argument("--password", required=True, help="Splunk password")
|
||||
parser.add_argument("--analysts", type=int, default=6, help="Number of SOC analysts per shift")
|
||||
parser.add_argument("--output", help="Save report JSON to file")
|
||||
args = parser.parse_args()
|
||||
|
||||
service = connect_splunk(args.host, args.port, args.username, args.password)
|
||||
report = build_fatigue_report(service, args.analysts)
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user