mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 21:54:56 +03:00
c47eed6a64
- 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
144 lines
5.3 KiB
Python
144 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Host-based intrusion detection agent using OSSEC/Wazuh API and osquery."""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import argparse
|
|
import subprocess
|
|
from datetime import datetime
|
|
|
|
try:
|
|
import requests
|
|
requests.packages.urllib3.disable_warnings()
|
|
except ImportError:
|
|
print("Install: pip install requests")
|
|
sys.exit(1)
|
|
|
|
|
|
class WazuhClient:
|
|
"""Wazuh API client for HIDS management."""
|
|
|
|
def __init__(self, base_url, username, password):
|
|
self.url = base_url.rstrip("/")
|
|
self.token = self._authenticate(username, password)
|
|
|
|
def _authenticate(self, username, password):
|
|
resp = requests.post(f"{self.url}/security/user/authenticate",
|
|
auth=(username, password),
|
|
verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30) # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
|
|
resp.raise_for_status()
|
|
return resp.json()["data"]["token"]
|
|
|
|
def _get(self, endpoint, params=None):
|
|
resp = requests.get(f"{self.url}/{endpoint}",
|
|
headers={"Authorization": f"Bearer {self.token}"},
|
|
params=params,
|
|
verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30) # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
|
|
resp.raise_for_status()
|
|
return resp.json()
|
|
|
|
def list_agents(self, status=None):
|
|
params = {}
|
|
if status:
|
|
params["status"] = status
|
|
return self._get("agents", params)
|
|
|
|
def get_agent_alerts(self, agent_id, limit=20):
|
|
return self._get(f"alerts", {"agent.id": agent_id, "limit": limit})
|
|
|
|
def get_sca_results(self, agent_id):
|
|
return self._get(f"sca/{agent_id}")
|
|
|
|
def get_rootcheck(self, agent_id):
|
|
return self._get(f"rootcheck/{agent_id}")
|
|
|
|
|
|
def run_osquery_check(query):
|
|
"""Execute osquery for host inspection."""
|
|
cmd = ["osqueryi", "--json", query]
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
return json.loads(result.stdout) if result.stdout.strip() else []
|
|
except (FileNotFoundError, json.JSONDecodeError):
|
|
return [{"error": "osquery not available"}]
|
|
|
|
|
|
def check_file_integrity(paths):
|
|
"""Check file integrity for key system files."""
|
|
checks = []
|
|
import hashlib, os
|
|
for path in paths:
|
|
if os.path.exists(path):
|
|
with open(path, "rb") as f:
|
|
sha256 = hashlib.sha256(f.read()).hexdigest()
|
|
stat = os.stat(path)
|
|
checks.append({
|
|
"path": path,
|
|
"sha256": sha256,
|
|
"size": stat.st_size,
|
|
"modified": datetime.fromtimestamp(stat.st_mtime).isoformat(),
|
|
"status": "present",
|
|
})
|
|
else:
|
|
checks.append({"path": path, "status": "missing", "severity": "HIGH"})
|
|
return checks
|
|
|
|
|
|
def run_audit(wazuh_url=None, username=None, password=None, agent_id=None):
|
|
"""Execute HIDS audit."""
|
|
print(f"\n{'='*60}")
|
|
print(f" HOST-BASED INTRUSION DETECTION AUDIT")
|
|
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
|
|
print(f"{'='*60}\n")
|
|
|
|
if wazuh_url and username and password:
|
|
client = WazuhClient(wazuh_url, username, password)
|
|
agents = client.list_agents()
|
|
data = agents.get("data", {})
|
|
items = data.get("affected_items", [])
|
|
print(f"--- WAZUH AGENTS ({data.get('total_affected_items', 0)}) ---")
|
|
for a in items[:10]:
|
|
print(f" {a.get('name', 'N/A')} ({a.get('id', '')}): {a.get('status', '')}")
|
|
|
|
if agent_id:
|
|
sca = client.get_sca_results(agent_id)
|
|
sca_data = sca.get("data", {}).get("affected_items", [])
|
|
print(f"\n--- SCA RESULTS (agent {agent_id}) ---")
|
|
for s in sca_data[:5]:
|
|
print(f" {s.get('name', '')}: pass={s.get('pass', 0)} fail={s.get('fail', 0)}")
|
|
|
|
system_files = ["/etc/passwd", "/etc/shadow", "/etc/sudoers", "/etc/ssh/sshd_config"]
|
|
integrity = check_file_integrity(system_files)
|
|
print(f"\n--- FILE INTEGRITY CHECK ---")
|
|
for f in integrity:
|
|
print(f" {f['path']}: {f['status']}")
|
|
|
|
processes = run_osquery_check("SELECT name, pid, uid FROM processes WHERE uid = 0")
|
|
print(f"\n--- ROOT PROCESSES ({len(processes)}) ---")
|
|
for p in processes[:10]:
|
|
if "error" not in p:
|
|
print(f" PID {p.get('pid', '')}: {p.get('name', '')}")
|
|
|
|
return {"integrity": integrity, "processes": processes}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="HIDS Audit Agent")
|
|
parser.add_argument("--wazuh-url", help="Wazuh API URL (https://host:55000)")
|
|
parser.add_argument("--username", help="Wazuh API username")
|
|
parser.add_argument("--password", help="Wazuh API password")
|
|
parser.add_argument("--agent-id", help="Specific agent ID to audit")
|
|
parser.add_argument("--output", help="Save report to JSON file")
|
|
args = parser.parse_args()
|
|
|
|
report = run_audit(args.wazuh_url, args.username, args.password, args.agent_id)
|
|
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()
|