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

159 lines
6.4 KiB
Python

#!/usr/bin/env python3
"""DEP/ASLR Memory Protection Agent - audits processes and binaries for memory protection mitigations."""
import json
import argparse
import logging
import subprocess
import os
from datetime import datetime
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
def check_windows_dep_policy():
"""Check Windows DEP/NX policy via bcdedit."""
cmd = ["bcdedit", "/enum", "{current}"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
dep_policy = "unknown"
for line in result.stdout.split("\n"):
if "nx" in line.lower():
dep_policy = line.split()[-1] if line.split() else "unknown"
return {"dep_policy": dep_policy, "recommended": "AlwaysOn"}
def check_windows_process_mitigations():
"""Check process mitigation policies using PowerShell Get-ProcessMitigation."""
cmd = ["powershell", "-Command",
"Get-Process | ForEach-Object { try { $m = Get-ProcessMitigation -Id $_.Id -ErrorAction Stop; "
"[PSCustomObject]@{Name=$_.Name;PID=$_.Id;DEP=$m.DEP.Enable;ASLR=$m.ASLR.ForceRelocateImages;"
"CFG=$m.CFG.Enable;StrictHandle=$m.StrictHandle.Enable} } catch {} } | ConvertTo-Json"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
try:
processes = json.loads(result.stdout) if result.stdout else []
if isinstance(processes, dict):
processes = [processes]
return processes
except json.JSONDecodeError:
return []
def check_linux_aslr():
"""Check Linux ASLR configuration."""
try:
with open("/proc/sys/kernel/randomize_va_space") as f:
value = int(f.read().strip())
levels = {0: "disabled", 1: "partial", 2: "full"}
return {"aslr_level": value, "status": levels.get(value, "unknown"), "recommended": 2}
except (FileNotFoundError, ValueError):
return {"aslr_level": -1, "status": "unknown"}
def check_linux_nx_support():
"""Check NX bit support on Linux."""
result = subprocess.run(["grep", "nx", "/proc/cpuinfo"], capture_output=True, text=True, timeout=120)
return {"nx_supported": "nx" in result.stdout.lower()}
def check_elf_pie_relro(binary_path):
"""Check ELF binary for PIE, RELRO, stack canary, and NX using readelf/checksec."""
findings = {"binary": binary_path, "pie": False, "relro": "none", "nx": False, "canary": False}
readelf_cmd = subprocess.run(["readelf", "-h", binary_path], capture_output=True, text=True, timeout=120)
if "DYN" in readelf_cmd.stdout:
findings["pie"] = True
readelf_d = subprocess.run(["readelf", "-d", binary_path], capture_output=True, text=True, timeout=120)
if "BIND_NOW" in readelf_d.stdout:
findings["relro"] = "full"
elif "GNU_RELRO" in readelf_d.stdout:
findings["relro"] = "partial"
readelf_s = subprocess.run(["readelf", "-s", binary_path], capture_output=True, text=True, timeout=120)
if "__stack_chk_fail" in readelf_s.stdout:
findings["canary"] = True
readelf_l = subprocess.run(["readelf", "-l", binary_path], capture_output=True, text=True, timeout=120)
for line in readelf_l.stdout.split("\n"):
if "GNU_STACK" in line and "RWE" not in line:
findings["nx"] = True
score = sum([findings["pie"], findings["relro"] == "full", findings["nx"], findings["canary"]])
findings["protection_score"] = f"{score}/4"
return findings
def scan_directory_binaries(directory, extensions=None):
"""Scan directory for binaries and check protections."""
if extensions is None:
extensions = [""]
results = []
for root, dirs, files in os.walk(directory):
for fname in files:
fpath = os.path.join(root, fname)
if os.path.isfile(fpath) and os.access(fpath, os.X_OK):
try:
result = check_elf_pie_relro(fpath)
results.append(result)
except Exception:
continue
if len(results) >= 100:
break
return results
def generate_report(system_checks, binary_checks):
weak_binaries = [b for b in binary_checks if not b.get("pie") or b.get("relro") == "none"]
report = {
"timestamp": datetime.utcnow().isoformat(),
"system_protections": system_checks,
"binaries_scanned": len(binary_checks),
"weak_binaries": len(weak_binaries),
"protection_summary": {
"pie_enabled": sum(1 for b in binary_checks if b.get("pie")),
"full_relro": sum(1 for b in binary_checks if b.get("relro") == "full"),
"nx_enabled": sum(1 for b in binary_checks if b.get("nx")),
"canary_present": sum(1 for b in binary_checks if b.get("canary")),
},
"weak_binary_details": weak_binaries[:20],
}
return report
def main():
parser = argparse.ArgumentParser(description="DEP/ASLR Memory Protection Audit Agent")
parser.add_argument("--scan-dir", default="/usr/bin", help="Directory to scan binaries")
parser.add_argument("--platform", choices=["linux", "windows", "auto"], default="auto")
parser.add_argument("--output", default="memory_protection_report.json")
args = parser.parse_args()
platform = args.platform
if platform == "auto":
platform = "windows" if os.name == "nt" else "linux"
system_checks = {}
if platform == "linux":
system_checks["aslr"] = check_linux_aslr()
system_checks["nx"] = check_linux_nx_support()
binary_checks = scan_directory_binaries(args.scan_dir)
else:
system_checks["dep"] = check_windows_dep_policy()
process_mitigations = check_windows_process_mitigations()
binary_checks = []
for proc in process_mitigations:
binary_checks.append({
"binary": proc.get("Name", ""),
"pid": proc.get("PID", 0),
"pie": bool(proc.get("ASLR")),
"nx": bool(proc.get("DEP")),
"canary": False,
"relro": "n/a",
})
report = generate_report(system_checks, binary_checks)
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
logger.info("Scanned %d binaries, %d with weak protections",
report["binaries_scanned"], report["weak_binaries"])
print(json.dumps(report, indent=2, default=str))
if __name__ == "__main__":
main()