mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-14 23:14:55 +03:00
Add 5 new cybersecurity skills: AFL++ fuzzing, Sysmon scheduled task detection, ModSecurity WAF logging, MITRE Navigator TTP analysis, PowerShell script block hunting
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Mahipal
|
||||
|
||||
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,45 @@
|
||||
---
|
||||
name: implementing-web-application-logging-with-modsecurity
|
||||
description: >
|
||||
Configure ModSecurity WAF with OWASP Core Rule Set (CRS) for web application logging,
|
||||
tune rules to reduce false positives, analyze audit logs for attack detection, and
|
||||
implement custom SecRules for application-specific threats. The analyst configures
|
||||
SecRuleEngine, SecAuditEngine, and CRS paranoia levels to balance security coverage
|
||||
with operational stability. Activates for requests involving WAF configuration,
|
||||
ModSecurity rule tuning, web application audit logging, or CRS deployment.
|
||||
domain: cybersecurity
|
||||
subdomain: web-application-security
|
||||
tags: [modsecurity, waf, crs, owasp, web-security, audit-logging, rule-tuning]
|
||||
version: "1.0"
|
||||
author: mahipal
|
||||
license: Apache-2.0
|
||||
---
|
||||
# Implementing Web Application Logging with ModSecurity
|
||||
|
||||
## Overview
|
||||
|
||||
ModSecurity is an open-source WAF engine that works with Apache, Nginx, and IIS. The OWASP
|
||||
Core Rule Set (CRS) provides generic attack detection rules covering SQL injection, XSS,
|
||||
RCE, LFI, and other OWASP Top 10 attacks. ModSecurity logs full request/response data in
|
||||
audit logs for forensic analysis and generates alerts that feed into SIEM platforms.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Web server (Apache 2.4+ or Nginx) with ModSecurity v3 module
|
||||
- OWASP CRS v4.x installed
|
||||
- Log aggregation infrastructure (ELK, Splunk, or Wazuh)
|
||||
|
||||
## Steps
|
||||
|
||||
1. Install ModSecurity and configure SecRuleEngine in DetectionOnly mode
|
||||
2. Deploy OWASP CRS v4 and set paranoia level (PL1-PL4)
|
||||
3. Configure SecAuditEngine for relevant-only logging
|
||||
4. Tune false positives with SecRuleRemoveById and rule exclusions
|
||||
5. Switch to blocking mode (SecRuleEngine On) after tuning period
|
||||
6. Forward audit logs to SIEM for correlation and alerting
|
||||
|
||||
## Expected Output
|
||||
|
||||
```
|
||||
ModSecurity: Warning. Pattern match "(?:union\s+select)" [file "/etc/modsecurity/crs/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf"] [line "45"] [id "942100"] [msg "SQL Injection Attack Detected via libinjection"] [severity "CRITICAL"]
|
||||
```
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
# ModSecurity WAF Logging — API Reference
|
||||
|
||||
## Key ModSecurity Directives
|
||||
|
||||
| Directive | Description |
|
||||
|-----------|-------------|
|
||||
| `SecRuleEngine On/Off/DetectionOnly` | Enable/disable rule engine |
|
||||
| `SecAuditEngine On/Off/RelevantOnly` | Configure audit logging scope |
|
||||
| `SecAuditLog /path/to/modsec_audit.log` | Audit log file path |
|
||||
| `SecAuditLogParts ABCDEFHZ` | Audit log sections to include |
|
||||
| `SecRequestBodyAccess On` | Inspect request bodies |
|
||||
| `SecResponseBodyAccess On` | Inspect response bodies |
|
||||
| `SecRuleRemoveById <id>` | Disable specific rule by ID |
|
||||
| `SecRuleUpdateTargetById <id> "!ARGS:param"` | Exclude parameter from rule |
|
||||
|
||||
## Audit Log Sections
|
||||
|
||||
| Section | Contents |
|
||||
|---------|----------|
|
||||
| A | Audit log header (timestamp, transaction ID) |
|
||||
| B | Request headers |
|
||||
| C | Request body |
|
||||
| E | Response body |
|
||||
| F | Response headers |
|
||||
| H | Audit log trailer (rule matches, scores) |
|
||||
| Z | End of entry marker |
|
||||
|
||||
## OWASP CRS Rule ID Ranges
|
||||
|
||||
| Range | Category |
|
||||
|-------|----------|
|
||||
| 911xxx | Method Enforcement |
|
||||
| 920xxx | Protocol Enforcement |
|
||||
| 930xxx | Local File Inclusion |
|
||||
| 932xxx | Remote Code Execution |
|
||||
| 941xxx | Cross-Site Scripting (XSS) |
|
||||
| 942xxx | SQL Injection |
|
||||
| 944xxx | Java/Spring Attack |
|
||||
| 949xxx | Inbound Anomaly Score Blocking |
|
||||
|
||||
## CRS Paranoia Levels
|
||||
|
||||
| Level | Description |
|
||||
|-------|-------------|
|
||||
| PL1 | Default — low false positives, covers common attacks |
|
||||
| PL2 | Moderate — adds more patterns, some tuning needed |
|
||||
| PL3 | High — aggressive detection, significant tuning needed |
|
||||
| PL4 | Extreme — maximum coverage, heavy tuning required |
|
||||
|
||||
## Configuration Example
|
||||
|
||||
```apache
|
||||
SecRuleEngine DetectionOnly
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
|
||||
SecAuditLogParts ABCDEFHZ
|
||||
SecAuditLogType Serial
|
||||
SecAuditLog /var/log/modsec_audit.log
|
||||
```
|
||||
|
||||
## External References
|
||||
|
||||
- [ModSecurity v3 Reference Manual](https://github.com/owasp-modsecurity/ModSecurity/wiki/Reference-Manual-(v3.x))
|
||||
- [OWASP CRS Documentation](https://coreruleset.org/docs/)
|
||||
- [CRS Tuning Guide](https://coreruleset.org/docs/concepts/false_positives_tuning/)
|
||||
@@ -0,0 +1,242 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ModSecurity WAF audit log analysis and rule tuning agent."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import argparse
|
||||
import re
|
||||
from datetime import datetime
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
SECTION_PATTERN = re.compile(r'^--([a-f0-9]+)-([A-Z])--$')
|
||||
|
||||
CRS_CATEGORIES = {
|
||||
"911": "Method Enforcement",
|
||||
"913": "Scanner Detection",
|
||||
"920": "Protocol Enforcement",
|
||||
"921": "Protocol Attack",
|
||||
"930": "Local File Inclusion",
|
||||
"931": "Remote File Inclusion",
|
||||
"932": "Remote Code Execution",
|
||||
"933": "PHP Injection",
|
||||
"934": "Node.js Injection",
|
||||
"941": "XSS Attack",
|
||||
"942": "SQL Injection",
|
||||
"943": "Session Fixation",
|
||||
"944": "Java Attack",
|
||||
"949": "Inbound Blocking",
|
||||
"959": "Outbound Blocking",
|
||||
}
|
||||
|
||||
|
||||
def parse_audit_log(log_path, max_entries=5000):
|
||||
"""Parse ModSecurity serial audit log format."""
|
||||
entries = []
|
||||
current = {}
|
||||
current_section = None
|
||||
|
||||
with open(log_path, "r", errors="replace") as f:
|
||||
for line in f:
|
||||
match = SECTION_PATTERN.match(line.strip())
|
||||
if match:
|
||||
tx_id = match.group(1)
|
||||
section = match.group(2)
|
||||
if section == "A":
|
||||
if current and current.get("tx_id"):
|
||||
entries.append(current)
|
||||
if len(entries) >= max_entries:
|
||||
break
|
||||
current = {"tx_id": tx_id, "sections": {}}
|
||||
current_section = section
|
||||
current["sections"][section] = ""
|
||||
elif current_section and current_section in current.get("sections", {}):
|
||||
current["sections"][current_section] += line
|
||||
|
||||
if current and current.get("tx_id"):
|
||||
entries.append(current)
|
||||
|
||||
parsed = []
|
||||
for entry in entries:
|
||||
record = {"tx_id": entry["tx_id"]}
|
||||
section_a = entry["sections"].get("A", "")
|
||||
if section_a:
|
||||
parts = section_a.strip().split()
|
||||
if len(parts) >= 3:
|
||||
record["timestamp"] = parts[0] if parts else ""
|
||||
record["client_ip"] = parts[1] if len(parts) > 1 else ""
|
||||
|
||||
section_b = entry["sections"].get("B", "")
|
||||
if section_b:
|
||||
first_line = section_b.strip().split("\n")[0]
|
||||
req_parts = first_line.split()
|
||||
if len(req_parts) >= 2:
|
||||
record["method"] = req_parts[0]
|
||||
record["uri"] = req_parts[1]
|
||||
|
||||
section_h = entry["sections"].get("H", "")
|
||||
record["rules_matched"] = []
|
||||
for rule_match in re.finditer(
|
||||
r'\[id "(\d+)"\].*?\[msg "([^"]+)"\].*?\[severity "([^"]+)"\]',
|
||||
section_h
|
||||
):
|
||||
record["rules_matched"].append({
|
||||
"rule_id": rule_match.group(1),
|
||||
"message": rule_match.group(2),
|
||||
"severity": rule_match.group(3),
|
||||
})
|
||||
|
||||
anomaly = re.search(r'Inbound Anomaly Score.*?(\d+)', section_h)
|
||||
if anomaly:
|
||||
record["anomaly_score"] = int(anomaly.group(1))
|
||||
|
||||
parsed.append(record)
|
||||
return parsed
|
||||
|
||||
|
||||
def analyze_rule_frequency(entries):
|
||||
"""Analyze which rules fire most frequently for tuning."""
|
||||
rule_counts = defaultdict(int)
|
||||
rule_msgs = {}
|
||||
for entry in entries:
|
||||
for rule in entry.get("rules_matched", []):
|
||||
rid = rule["rule_id"]
|
||||
rule_counts[rid] += 1
|
||||
rule_msgs[rid] = rule["message"]
|
||||
|
||||
sorted_rules = sorted(rule_counts.items(), key=lambda x: x[1], reverse=True)
|
||||
results = []
|
||||
for rid, count in sorted_rules:
|
||||
category = CRS_CATEGORIES.get(rid[:3], "Other")
|
||||
results.append({
|
||||
"rule_id": rid,
|
||||
"count": count,
|
||||
"message": rule_msgs.get(rid, ""),
|
||||
"category": category,
|
||||
})
|
||||
return results
|
||||
|
||||
|
||||
def identify_false_positive_candidates(entries, threshold=50):
|
||||
"""Identify rules that may be false positives based on frequency and pattern."""
|
||||
rule_ips = defaultdict(set)
|
||||
rule_uris = defaultdict(set)
|
||||
rule_counts = defaultdict(int)
|
||||
|
||||
for entry in entries:
|
||||
for rule in entry.get("rules_matched", []):
|
||||
rid = rule["rule_id"]
|
||||
rule_counts[rid] += 1
|
||||
rule_ips[rid].add(entry.get("client_ip", ""))
|
||||
rule_uris[rid].add(entry.get("uri", ""))
|
||||
|
||||
candidates = []
|
||||
for rid, count in rule_counts.items():
|
||||
if count >= threshold and len(rule_ips[rid]) > 10:
|
||||
candidates.append({
|
||||
"rule_id": rid,
|
||||
"hit_count": count,
|
||||
"unique_ips": len(rule_ips[rid]),
|
||||
"unique_uris": len(rule_uris[rid]),
|
||||
"recommendation": f"SecRuleRemoveById {rid}",
|
||||
"reason": "High frequency across many IPs — likely false positive",
|
||||
})
|
||||
return candidates
|
||||
|
||||
|
||||
def generate_exclusion_rules(candidates):
|
||||
"""Generate ModSecurity rule exclusion configuration."""
|
||||
lines = ["# Auto-generated false positive exclusions"]
|
||||
for c in candidates:
|
||||
lines.append(f"# Rule {c['rule_id']}: {c['hit_count']} hits, "
|
||||
f"{c['unique_ips']} unique IPs")
|
||||
lines.append(f"SecRuleRemoveById {c['rule_id']}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def analyze_attack_summary(entries):
|
||||
"""Summarize detected attacks by category and severity."""
|
||||
category_counts = defaultdict(int)
|
||||
severity_counts = defaultdict(int)
|
||||
top_attackers = defaultdict(int)
|
||||
|
||||
for entry in entries:
|
||||
for rule in entry.get("rules_matched", []):
|
||||
cat = CRS_CATEGORIES.get(rule["rule_id"][:3], "Other")
|
||||
category_counts[cat] += 1
|
||||
severity_counts[rule["severity"]] += 1
|
||||
if entry.get("anomaly_score", 0) >= 5:
|
||||
top_attackers[entry.get("client_ip", "")] += 1
|
||||
|
||||
return {
|
||||
"by_category": dict(sorted(category_counts.items(), key=lambda x: x[1], reverse=True)),
|
||||
"by_severity": dict(severity_counts),
|
||||
"top_attackers": dict(sorted(top_attackers.items(), key=lambda x: x[1], reverse=True)[:20]),
|
||||
}
|
||||
|
||||
|
||||
def run_audit(args):
|
||||
"""Execute ModSecurity audit log analysis."""
|
||||
print(f"\n{'='*60}")
|
||||
print(f" MODSECURITY AUDIT LOG ANALYSIS")
|
||||
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
report = {}
|
||||
|
||||
entries = parse_audit_log(args.audit_log, args.max_entries)
|
||||
report["total_entries"] = len(entries)
|
||||
print(f"Parsed {len(entries)} audit log entries\n")
|
||||
|
||||
attack_summary = analyze_attack_summary(entries)
|
||||
report["attack_summary"] = attack_summary
|
||||
print(f"--- ATTACK SUMMARY ---")
|
||||
for cat, count in list(attack_summary["by_category"].items())[:10]:
|
||||
print(f" {cat}: {count}")
|
||||
print(f"\n Severity: {attack_summary['by_severity']}")
|
||||
print(f"\n--- TOP ATTACKERS ---")
|
||||
for ip, count in list(attack_summary["top_attackers"].items())[:10]:
|
||||
print(f" {ip}: {count} alerts")
|
||||
|
||||
rule_freq = analyze_rule_frequency(entries)
|
||||
report["rule_frequency"] = rule_freq[:20]
|
||||
print(f"\n--- TOP FIRING RULES ---")
|
||||
for r in rule_freq[:15]:
|
||||
print(f" [{r['rule_id']}] {r['count']}x — {r['message'][:60]}")
|
||||
|
||||
if args.tune:
|
||||
fp_candidates = identify_false_positive_candidates(entries, args.fp_threshold)
|
||||
report["false_positive_candidates"] = fp_candidates
|
||||
print(f"\n--- FALSE POSITIVE CANDIDATES ({len(fp_candidates)}) ---")
|
||||
for c in fp_candidates[:10]:
|
||||
print(f" Rule {c['rule_id']}: {c['hit_count']} hits, "
|
||||
f"{c['unique_ips']} IPs — {c['reason']}")
|
||||
if fp_candidates:
|
||||
exclusions = generate_exclusion_rules(fp_candidates)
|
||||
report["exclusion_config"] = exclusions
|
||||
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="ModSecurity Audit Log Agent")
|
||||
parser.add_argument("--audit-log", required=True,
|
||||
help="Path to ModSecurity audit log file")
|
||||
parser.add_argument("--max-entries", type=int, default=5000,
|
||||
help="Max log entries to parse (default: 5000)")
|
||||
parser.add_argument("--tune", action="store_true",
|
||||
help="Identify false positive candidates for tuning")
|
||||
parser.add_argument("--fp-threshold", type=int, default=50,
|
||||
help="Minimum hits for false positive candidate (default: 50)")
|
||||
parser.add_argument("--output", help="Save report to JSON file")
|
||||
args = parser.parse_args()
|
||||
|
||||
report = run_audit(args)
|
||||
if args.output:
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2, default=str)
|
||||
print(f"\n[+] Report saved to {args.output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user