mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-22 04:30:59 +03:00
- 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
239 lines
8.9 KiB
Python
239 lines
8.9 KiB
Python
#!/usr/bin/env python3
|
|
"""AIDE (Advanced Intrusion Detection Environment) configuration generator and check runner."""
|
|
|
|
import os
|
|
import json
|
|
import re
|
|
import subprocess
|
|
import argparse
|
|
from datetime import datetime
|
|
|
|
AIDE_RULE_SETS = {
|
|
"critical_binaries": {
|
|
"paths": ["/bin", "/sbin", "/usr/bin", "/usr/sbin"],
|
|
"rule": "p+i+n+u+g+s+b+m+c+sha256+xattrs",
|
|
"description": "Monitor all attributes and SHA-256 hash for system binaries",
|
|
},
|
|
"config_files": {
|
|
"paths": ["/etc"],
|
|
"rule": "p+i+u+g+sha256",
|
|
"description": "Monitor permissions, inode, ownership, and hash for config files",
|
|
},
|
|
"boot_files": {
|
|
"paths": ["/boot"],
|
|
"rule": "p+i+n+u+g+s+b+m+c+sha256",
|
|
"description": "Full attribute monitoring for boot files and kernel images",
|
|
},
|
|
"library_files": {
|
|
"paths": ["/lib", "/lib64", "/usr/lib"],
|
|
"rule": "p+i+n+u+g+s+b+sha256",
|
|
"description": "Monitor shared libraries for unauthorized modifications",
|
|
},
|
|
"log_files": {
|
|
"paths": ["/var/log"],
|
|
"rule": "p+u+g+i",
|
|
"description": "Monitor log file permissions and ownership (not content)",
|
|
},
|
|
}
|
|
|
|
AIDE_EXCLUSIONS = [
|
|
"!/var/log/.*", "!/var/spool/.*", "!/var/cache/.*",
|
|
"!/proc", "!/sys", "!/dev", "!/run", "!/tmp",
|
|
"!/var/lib/dpkg/.*", "!/var/lib/apt/.*",
|
|
]
|
|
|
|
|
|
def generate_aide_config(rule_sets=None, db_path="/var/lib/aide/aide.db",
|
|
db_new_path="/var/lib/aide/aide.db.new",
|
|
log_path="/var/log/aide/aide.log"):
|
|
"""Generate aide.conf configuration file content."""
|
|
if rule_sets is None:
|
|
rule_sets = list(AIDE_RULE_SETS.keys())
|
|
|
|
lines = [
|
|
"# AIDE Configuration - Generated by agent.py",
|
|
f"# Generated: {datetime.utcnow().isoformat()}",
|
|
"",
|
|
f"database_in=file:{db_path}",
|
|
f"database_out=file:{db_new_path}",
|
|
f"database_new=file:{db_new_path}",
|
|
"",
|
|
"# Gzip output database",
|
|
"gzip_dbout=yes",
|
|
"",
|
|
"# Report settings",
|
|
"report_url=stdout",
|
|
f"report_url=file:{log_path}",
|
|
"",
|
|
"# Rule definitions",
|
|
"NORMAL = p+i+n+u+g+s+b+m+c+sha256",
|
|
"PERMS = p+i+u+g",
|
|
"LOG = p+u+g+i",
|
|
"FULL = p+i+n+u+g+s+b+m+c+sha256+xattrs",
|
|
"",
|
|
"# Exclusions",
|
|
]
|
|
|
|
for excl in AIDE_EXCLUSIONS:
|
|
lines.append(excl)
|
|
|
|
lines.append("")
|
|
lines.append("# Monitored paths")
|
|
|
|
for rs_name in rule_sets:
|
|
rs = AIDE_RULE_SETS.get(rs_name)
|
|
if not rs:
|
|
continue
|
|
lines.append(f"# {rs['description']}")
|
|
for path in rs["paths"]:
|
|
lines.append(f"{path} {rs['rule']}")
|
|
lines.append("")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
def initialize_baseline():
|
|
"""Run aide --init to create the baseline database."""
|
|
result = subprocess.run(
|
|
["aide", "--init", "--config=/etc/aide/aide.conf"],
|
|
capture_output=True, text=True, timeout=600
|
|
)
|
|
if result.returncode == 0:
|
|
subprocess.run(
|
|
["cp", "/var/lib/aide/aide.db.new", "/var/lib/aide/aide.db"],
|
|
capture_output=True, text=True,
|
|
timeout=120,
|
|
)
|
|
return {"status": "success", "output": result.stdout[:500]}
|
|
return {"status": "error", "stderr": result.stderr[:500]}
|
|
|
|
|
|
def run_integrity_check():
|
|
"""Run aide --check and parse the results."""
|
|
result = subprocess.run(
|
|
["aide", "--check", "--config=/etc/aide/aide.conf"],
|
|
capture_output=True, text=True, timeout=600
|
|
)
|
|
return parse_aide_output(result.stdout, result.returncode)
|
|
|
|
|
|
def parse_aide_output(output, return_code):
|
|
"""Parse AIDE check output into structured findings."""
|
|
findings = {"added": [], "removed": [], "changed": [], "summary": {}}
|
|
|
|
section = None
|
|
for line in output.splitlines():
|
|
line = line.strip()
|
|
if "Added entries:" in line or "added:" in line.lower():
|
|
section = "added"
|
|
elif "Removed entries:" in line or "removed:" in line.lower():
|
|
section = "removed"
|
|
elif "Changed entries:" in line or "changed:" in line.lower():
|
|
section = "changed"
|
|
elif line.startswith("f") or line.startswith("d") or line.startswith("l"):
|
|
match = re.match(r"^[fdl!]\s+(.+)", line)
|
|
if match and section:
|
|
filepath = match.group(1).strip()
|
|
severity = _classify_severity(filepath, section)
|
|
findings[section].append({
|
|
"path": filepath, "severity": severity, "change_type": section,
|
|
})
|
|
elif "Number of entries" in line:
|
|
match = re.match(r"Number of entries:\s*(\d+)", line)
|
|
if match:
|
|
findings["summary"]["total_entries"] = int(match.group(1))
|
|
|
|
findings["summary"]["added_count"] = len(findings["added"])
|
|
findings["summary"]["removed_count"] = len(findings["removed"])
|
|
findings["summary"]["changed_count"] = len(findings["changed"])
|
|
findings["summary"]["return_code"] = return_code
|
|
findings["summary"]["integrity_status"] = "clean" if return_code == 0 else "changes_detected"
|
|
return findings
|
|
|
|
|
|
def _classify_severity(filepath, change_type):
|
|
"""Classify severity based on file path and change type."""
|
|
critical_paths = ["/bin/", "/sbin/", "/usr/bin/", "/usr/sbin/", "/boot/", "/etc/shadow",
|
|
"/etc/passwd", "/etc/sudoers", "/etc/ssh/"]
|
|
high_paths = ["/etc/", "/lib/", "/lib64/", "/usr/lib/"]
|
|
|
|
if change_type == "removed" and any(filepath.startswith(p) for p in critical_paths):
|
|
return "critical"
|
|
if any(filepath.startswith(p) for p in critical_paths):
|
|
return "critical" if change_type != "added" else "high"
|
|
if any(filepath.startswith(p) for p in high_paths):
|
|
return "high"
|
|
return "medium"
|
|
|
|
|
|
def generate_cron_config(schedule="0 5 * * *", email=None):
|
|
"""Generate cron job for automated AIDE integrity checks."""
|
|
cron_script = "#!/bin/bash\n"
|
|
cron_script += "# AIDE automated integrity check\n"
|
|
cron_script += "LOGFILE=/var/log/aide/aide-check-$(date +%Y%m%d).log\n"
|
|
cron_script += "aide --check --config=/etc/aide/aide.conf > $LOGFILE 2>&1\n"
|
|
cron_script += "EXIT_CODE=$?\n"
|
|
cron_script += "if [ $EXIT_CODE -ne 0 ]; then\n"
|
|
if email:
|
|
cron_script += f' mail -s "AIDE Alert: Integrity changes detected" {email} < $LOGFILE\n'
|
|
cron_script += ' logger -t aide "Integrity check found changes (exit code $EXIT_CODE)"\n'
|
|
cron_script += "fi\n"
|
|
|
|
cron_entry = f"{schedule} root /usr/local/bin/aide-check.sh"
|
|
return {"script": cron_script, "cron_entry": cron_entry, "schedule": schedule}
|
|
|
|
|
|
def generate_report(config_content, baseline_status, check_findings, cron_config):
|
|
"""Generate AIDE deployment and check report."""
|
|
return {
|
|
"report_time": datetime.utcnow().isoformat(),
|
|
"config_lines": len(config_content.splitlines()),
|
|
"monitored_rule_sets": list(AIDE_RULE_SETS.keys()),
|
|
"exclusion_count": len(AIDE_EXCLUSIONS),
|
|
"baseline_status": baseline_status,
|
|
"integrity_check": check_findings,
|
|
"cron_schedule": cron_config,
|
|
}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="AIDE File Integrity Monitoring Agent")
|
|
parser.add_argument("--action", choices=["generate", "init", "check", "full"],
|
|
default="generate", help="Action to perform")
|
|
parser.add_argument("--config-output", default="/etc/aide/aide.conf", help="Config output path")
|
|
parser.add_argument("--alert-email", help="Email for cron alert notifications")
|
|
parser.add_argument("--output", default="aide_report.json")
|
|
parser.add_argument("--rule-sets", nargs="+", default=None,
|
|
choices=list(AIDE_RULE_SETS.keys()), help="Rule sets to enable")
|
|
args = parser.parse_args()
|
|
|
|
config_content = generate_aide_config(args.rule_sets)
|
|
baseline_status = {}
|
|
check_findings = {}
|
|
|
|
if args.action in ("generate", "full"):
|
|
os.makedirs(os.path.dirname(args.config_output), exist_ok=True)
|
|
with open(args.config_output, "w") as f:
|
|
f.write(config_content)
|
|
print(f"[+] AIDE config written to {args.config_output}")
|
|
|
|
if args.action in ("init", "full"):
|
|
baseline_status = initialize_baseline()
|
|
print(f"[+] Baseline init: {baseline_status['status']}")
|
|
|
|
if args.action in ("check", "full"):
|
|
check_findings = run_integrity_check()
|
|
s = check_findings.get("summary", {})
|
|
print(f"[+] Check: added={s.get('added_count', 0)} removed={s.get('removed_count', 0)} "
|
|
f"changed={s.get('changed_count', 0)}")
|
|
|
|
cron_config = generate_cron_config(email=args.alert_email)
|
|
report = generate_report(config_content, baseline_status, check_findings, cron_config)
|
|
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()
|