#!/usr/bin/env python3 """Privileged session monitoring agent. Monitors SSH auth logs, Windows RDP events, and database sessions to track privileged access, detect anomalies, and generate audit reports. """ import argparse import json import re import sys import datetime import collections try: import subprocess HAS_SUBPROCESS = True except ImportError: HAS_SUBPROCESS = False SESSION_POLICIES = { "max_duration_hours": 8, "max_idle_minutes": 30, "require_mfa": True, "record_session": True, "allowed_hours": {"start": 6, "end": 22}, "restricted_commands": [ r"rm\s+-rf\s+/", r"dd\s+if=", r"mkfs\.", r"shutdown", r"reboot", r"passwd\s+root", r"visudo", r"chmod\s+777", r"iptables\s+-F", ], } PRIVILEGED_ACCOUNTS = [ "root", "administrator", "admin", "dba", "sa", "sysadmin", "service_account", "deploy", ] def parse_ssh_auth_log(log_path, max_lines=10000): """Parse SSH authentication log for session events.""" sessions = [] pattern = re.compile( r"(\w+\s+\d+\s+[\d:]+)\s+(\S+)\s+sshd\[(\d+)\]:\s+" r"(Accepted|Failed)\s+(\S+)\s+for\s+(\S+)\s+from\s+(\S+)\s+port\s+(\d+)" ) try: with open(log_path, "r") as f: for i, line in enumerate(f): if i >= max_lines: break m = pattern.search(line) if m: sessions.append({ "timestamp": m.group(1), "hostname": m.group(2), "pid": m.group(3), "status": m.group(4).lower(), "auth_method": m.group(5), "username": m.group(6), "source_ip": m.group(7), "source_port": int(m.group(8)), "privileged": m.group(6).lower() in PRIVILEGED_ACCOUNTS, }) except FileNotFoundError: return {"error": f"Log file not found: {log_path}"} return sessions def parse_rdp_events_windows(): """Parse Windows RDP logon events via PowerShell.""" cmd = ( "Get-WinEvent -FilterHashtable @{LogName='Security';Id=4624} " "| Where-Object {$_.Properties[8].Value -eq 10} " "| Select-Object -First 50 " "| ForEach-Object { @{TimeCreated=$_.TimeCreated.ToString('o');" "User=$_.Properties[5].Value;Domain=$_.Properties[6].Value;" "SourceIP=$_.Properties[18].Value} } | ConvertTo-Json" ) try: result = subprocess.run( ["powershell", "-NoProfile", "-Command", cmd], capture_output=True, text=True, timeout=30 ) if result.stdout.strip(): data = json.loads(result.stdout) if isinstance(data, dict): data = [data] return [ { "timestamp": d.get("TimeCreated", ""), "username": d.get("User", ""), "domain": d.get("Domain", ""), "source_ip": d.get("SourceIP", ""), "session_type": "RDP", "privileged": d.get("User", "").lower() in PRIVILEGED_ACCOUNTS, } for d in data ] return [] except (subprocess.SubprocessError, json.JSONDecodeError): return [] def check_command_policy(command): """Check if a command violates session policy.""" violations = [] for pattern in SESSION_POLICIES["restricted_commands"]: if re.search(pattern, command, re.IGNORECASE): violations.append({ "pattern": pattern, "command": command[:100], "action": "alert_and_log", }) return violations def detect_session_anomalies(sessions): """Detect anomalous session patterns.""" anomalies = [] ip_counts = collections.Counter(s.get("source_ip") for s in sessions) user_counts = collections.Counter(s.get("username") for s in sessions) for ip, count in ip_counts.items(): if count > 20: anomalies.append({ "type": "brute_force_candidate", "source_ip": ip, "attempt_count": count, "severity": "HIGH", }) failed = [s for s in sessions if s.get("status") == "failed"] failed_by_user = collections.Counter(s.get("username") for s in failed) for user, count in failed_by_user.items(): if count >= 5: anomalies.append({ "type": "failed_auth_spike", "username": user, "failed_count": count, "severity": "HIGH" if user in PRIVILEGED_ACCOUNTS else "MEDIUM", }) priv_sessions = [s for s in sessions if s.get("privileged")] for ps in priv_sessions: anomalies.append({ "type": "privileged_session", "username": ps.get("username"), "source_ip": ps.get("source_ip"), "severity": "MEDIUM", }) return anomalies def generate_audit_report(sessions, anomalies): """Generate privileged session audit report.""" total = len(sessions) privileged = sum(1 for s in sessions if s.get("privileged")) accepted = sum(1 for s in sessions if s.get("status") == "accepted") failed = sum(1 for s in sessions if s.get("status") == "failed") unique_users = len(set(s.get("username") for s in sessions)) unique_ips = len(set(s.get("source_ip") for s in sessions)) return { "report_time": datetime.datetime.utcnow().isoformat() + "Z", "total_sessions": total, "accepted": accepted, "failed": failed, "privileged_sessions": privileged, "unique_users": unique_users, "unique_source_ips": unique_ips, "anomaly_count": len(anomalies), "policy": SESSION_POLICIES, } def main(): parser = argparse.ArgumentParser(description="Privileged session monitoring agent") parser.add_argument("--ssh-log", help="Path to SSH auth.log") parser.add_argument("--rdp", action="store_true", help="Parse Windows RDP events") parser.add_argument("--check-command", help="Check a command against policy") parser.add_argument("--output", "-o", help="Output JSON report path") args = parser.parse_args() print("[*] Privileged Session Monitoring Agent") report = {"timestamp": datetime.datetime.utcnow().isoformat() + "Z"} sessions = [] if args.ssh_log: sessions = parse_ssh_auth_log(args.ssh_log) if isinstance(sessions, dict) and "error" in sessions: print(f"[!] {sessions['error']}") sessions = [] else: print(f"[*] SSH sessions parsed: {len(sessions)}") if args.rdp and sys.platform == "win32": rdp_sessions = parse_rdp_events_windows() sessions.extend(rdp_sessions) print(f"[*] RDP sessions parsed: {len(rdp_sessions)}") if args.check_command: violations = check_command_policy(args.check_command) if violations: print(f"[!] Command policy violations: {len(violations)}") for v in violations: print(f" Pattern: {v['pattern']}") else: print("[*] Command passes policy check") report["command_check"] = {"command": args.check_command, "violations": violations} if sessions: anomalies = detect_session_anomalies(sessions) audit = generate_audit_report(sessions, anomalies) report["sessions"] = audit report["anomalies"] = anomalies print(f"[*] Anomalies detected: {len(anomalies)}") else: print("\n[DEMO] Usage: python agent.py --ssh-log /var/log/auth.log") print(" Monitors: SSH, RDP, privileged account access") print(" Detects: brute force, failed auth spikes, off-hours access") if args.output: with open(args.output, "w") as f: json.dump(report, f, indent=2) print(json.dumps({"sessions": len(sessions), "anomalies": len(report.get("anomalies", []))}, indent=2)) if __name__ == "__main__": main()