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:
mukul975
2026-03-11 00:41:37 +01:00
parent 546f1ae6ef
commit aea97ff9ff
20 changed files with 1857 additions and 0 deletions
@@ -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"]
```
@@ -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()