mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-05 15:29:01 +03:00
235 lines
8.0 KiB
Python
235 lines
8.0 KiB
Python
#!/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 os
|
|
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()
|