Files
mukul975 c47eed6a64 Production hardening: security fixes, code quality, 724 skills complete
- Fix 25 shell=True subprocess calls with list-based commands
- Fix 49 verify=False in defensive skills (env-var override)
- Add timeout to 231 HTTP/subprocess/socket calls
- Fix 6 SQL injection patterns with whitelist validation
- Replace 8 __import__() with standard imports
- Remove 701 unused imports across 442 files
- Add authorized-testing disclaimers to all offensive skills
- Complete 11 incomplete skill directories
- Expand 10 stub SKILL.md files with full content
- Fix 2 YAML parse errors in frontmatter
- Fix 5 pre-existing syntax errors
- Convert 22 hardcoded paths/ports to environment variables
- Back up 21 redundant skill pairs to .bak
- Fix 2 global declaration errors
- 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE)
- 0 compile errors across all 724 agent.py files
2026-03-19 13:26:49 +01:00

182 lines
7.1 KiB
Python

#!/usr/bin/env python3
"""Agent for implementing and auditing AppLocker application whitelisting policies."""
import json
import argparse
import re
import xml.etree.ElementTree as ET
from datetime import datetime
from pathlib import Path
APPLOCKER_EVENT_IDS = {
8002: ("EXE/DLL allowed", "INFO"),
8003: ("EXE/DLL denied", "HIGH"),
8004: ("EXE/DLL would be denied (audit)", "MEDIUM"),
8005: ("Script allowed", "INFO"),
8006: ("Script denied", "HIGH"),
8007: ("Script would be denied (audit)", "MEDIUM"),
8020: ("Packaged app allowed", "INFO"),
8021: ("Packaged app denied", "HIGH"),
8022: ("Packaged app would be denied (audit)", "MEDIUM"),
}
def parse_applocker_policy(xml_path):
"""Parse an exported AppLocker policy XML file."""
tree = ET.parse(xml_path)
root = tree.getroot()
ns = {"al": "http://schemas.microsoft.com/windows/2006/applocker"}
rules = []
for collection in root.findall(".//al:RuleCollection", ns):
rule_type = collection.get("Type", "")
mode = collection.get("EnforcementMode", "NotConfigured")
for rule in collection:
rule_data = {
"collection": rule_type,
"enforcement_mode": mode,
"name": rule.get("Name", ""),
"action": rule.get("Action", ""),
"user_or_group": rule.get("UserOrGroupSid", ""),
"type": rule.tag.replace(f"{{{ns.get('al', '')}}}", ""),
}
conditions = rule.findall(".//*")
for cond in conditions:
if "Path" in cond.tag:
rule_data["path"] = cond.get("Path", "")
elif "Publisher" in cond.tag:
rule_data["publisher"] = cond.get("PublisherName", "")
elif "Hash" in cond.tag:
rule_data["hash"] = cond.get("Data", "")
rules.append(rule_data)
return rules
def audit_applocker_rules(rules):
"""Audit AppLocker rules for security weaknesses."""
findings = []
for rule in rules:
if rule.get("enforcement_mode") == "AuditOnly":
findings.append({
"collection": rule["collection"],
"issue": "audit_mode_only",
"severity": "MEDIUM",
"recommendation": "Switch to Enforce mode after validation",
})
if rule.get("enforcement_mode") == "NotConfigured":
findings.append({
"collection": rule["collection"],
"issue": "not_configured",
"severity": "HIGH",
"recommendation": "Enable enforcement for this rule collection",
})
path = rule.get("path", "")
if path and rule.get("action") == "Allow":
risky_paths = [r"\\Users\\", r"\\Temp\\", r"\\Downloads\\",
r"\\AppData\\", r"\\ProgramData\\"]
for rp in risky_paths:
if re.search(rp, path, re.IGNORECASE):
findings.append({
"rule_name": rule["name"],
"path": path,
"issue": "allow_from_user_writable_path",
"severity": "CRITICAL",
})
break
if rule.get("user_or_group") == "S-1-1-0" and rule.get("action") == "Allow":
findings.append({
"rule_name": rule["name"],
"issue": "allow_for_everyone",
"severity": "MEDIUM",
})
return findings
def analyze_applocker_events(log_path):
"""Analyze AppLocker event logs for blocked and audit events."""
events = []
with open(log_path) as f:
for line in f:
try:
entry = json.loads(line)
except json.JSONDecodeError:
continue
event_id = int(entry.get("EventID", entry.get("event_id", 0)))
if event_id in APPLOCKER_EVENT_IDS:
desc, severity = APPLOCKER_EVENT_IDS[event_id]
events.append({
"event_id": event_id,
"description": desc,
"severity": severity,
"timestamp": entry.get("TimeCreated", entry.get("timestamp", "")),
"computer": entry.get("Computer", entry.get("hostname", "")),
"user": entry.get("User", entry.get("user", "")),
"file_path": entry.get("FilePath", entry.get("file_path", "")),
"publisher": entry.get("Publisher", ""),
})
denied = [e for e in events if "denied" in e["description"].lower()]
audit = [e for e in events if "audit" in e["description"].lower()]
return {"total_events": len(events), "denied": denied, "audit_blocks": audit}
def generate_baseline_policy():
"""Generate a baseline AppLocker policy recommendation."""
return {
"exe_rules": {
"enforcement_mode": "Enforce",
"default_rules": [
{"action": "Allow", "path": "%PROGRAMFILES%\\*", "scope": "Everyone"},
{"action": "Allow", "path": "%WINDIR%\\*", "scope": "Everyone"},
{"action": "Allow", "path": "*", "scope": "BUILTIN\\Administrators"},
],
},
"script_rules": {
"enforcement_mode": "Enforce",
"default_rules": [
{"action": "Allow", "path": "%PROGRAMFILES%\\*", "scope": "Everyone"},
{"action": "Allow", "path": "%WINDIR%\\*", "scope": "Everyone"},
],
},
"dll_rules": {
"enforcement_mode": "AuditOnly",
"note": "Start with audit mode due to high volume",
},
}
def main():
parser = argparse.ArgumentParser(description="AppLocker Whitelisting Agent")
parser.add_argument("--policy", help="Exported AppLocker policy XML")
parser.add_argument("--events", help="AppLocker event log (JSON lines)")
parser.add_argument("--output", default="applocker_audit_report.json")
parser.add_argument("--action", choices=["audit", "events", "baseline", "full"],
default="full")
args = parser.parse_args()
report = {"generated_at": datetime.utcnow().isoformat(), "findings": {}}
if args.action in ("audit", "full") and args.policy:
rules = parse_applocker_policy(args.policy)
findings = audit_applocker_rules(rules)
report["findings"]["policy_audit"] = findings
report["findings"]["total_rules"] = len(rules)
print(f"[+] Policy rules: {len(rules)}, Issues: {len(findings)}")
if args.action in ("events", "full") and args.events:
result = analyze_applocker_events(args.events)
report["findings"]["event_analysis"] = result
print(f"[+] Events: {result['total_events']}, Denied: {len(result['denied'])}")
if args.action in ("baseline", "full"):
baseline = generate_baseline_policy()
report["findings"]["baseline_policy"] = baseline
print("[+] Baseline policy generated")
with open(args.output, "w") as fout:
json.dump(report, fout, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
if __name__ == "__main__":
main()