mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-01 00:37:42 +03:00
feat: add 5 new cybersecurity skills - yara hunting, devsecops scanning, amcache, LOtL, privileged session monitoring
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user