Files
T
mukul975 c21af3347e Complete folder anatomy for all 649 cybersecurity skills + update LICENSE to Mahipal
- Add scripts/agent.py and references/api-reference.md to all remaining skills
- Update all 648 LICENSE files: copyright now reads 'Mahipal'
- Add implementing-security-monitoring-with-datadog (new skill with full anatomy)
- All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
2026-03-11 00:22:12 +01:00

164 lines
5.9 KiB
Python

#!/usr/bin/env python3
"""Agent for detecting suspicious PowerShell execution patterns."""
import argparse
import json
import os
import re
import subprocess
import sys
from collections import Counter
from datetime import datetime, timezone
SUSPICIOUS_CMDLETS = [
"Invoke-Expression", "IEX", "Invoke-WebRequest", "Invoke-RestMethod",
"Start-Process", "New-Object Net.WebClient", "DownloadString",
"DownloadFile", "System.Reflection.Assembly", "FromBase64String",
"Invoke-Mimikatz", "Invoke-Shellcode", "Invoke-DllInjection",
"Invoke-ReflectivePEInjection", "Get-Keystrokes", "Get-GPPPassword",
"Invoke-CredentialInjection", "Invoke-TokenManipulation",
"Add-Exfiltration", "Get-TimedScreenshot",
]
OBFUSCATION_PATTERNS = [
(r'\-[eE][nN][cC]\s', "Encoded command (-enc)"),
(r'[Ff][Rr][Oo][Mm][Bb][Aa][Ss][Ee]64', "Base64 decoding"),
(r'\$\{[^}]+\}', "Variable obfuscation ${...}"),
(r"'[^']*'\s*\+\s*'[^']*'", "String concatenation obfuscation"),
(r'\-[Ww]indow[Ss]tyle\s+[Hh]idden', "Hidden window execution"),
(r'\-[Nn]o[Pp]rofile', "NoProfile flag"),
(r'\-[Ee]xecution[Pp]olicy\s+[Bb]ypass', "Execution policy bypass"),
(r'[Ss]et-[Mm]pPreference.*-[Dd]isable', "Defender bypass attempt"),
(r'[Aa][Mm][Ss][Ii]', "AMSI reference"),
]
def parse_script_block_logs():
"""Parse PowerShell script block logging events (Event ID 4104)."""
events = []
if sys.platform != "win32":
return events
ps_cmd = (
"Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational';"
"Id=4104} -MaxEvents 200 | Select-Object TimeCreated,"
"@{N='ScriptBlock';E={$_.Properties[2].Value}},"
"@{N='Path';E={$_.Properties[4].Value}} | ConvertTo-Json -Depth 3"
)
try:
result = subprocess.check_output(
["powershell", "-NoProfile", "-Command", ps_cmd],
text=True, errors="replace", timeout=30
)
data = json.loads(result) if result.strip() else []
return data if isinstance(data, list) else [data]
except (subprocess.SubprocessError, json.JSONDecodeError):
return []
def analyze_script_content(script_text):
"""Analyze a PowerShell script for suspicious patterns."""
findings = []
if not script_text:
return findings
for cmdlet in SUSPICIOUS_CMDLETS:
if cmdlet.lower() in script_text.lower():
findings.append({"type": "suspicious_cmdlet", "cmdlet": cmdlet})
for pattern, desc in OBFUSCATION_PATTERNS:
if re.search(pattern, script_text):
findings.append({"type": "obfuscation", "pattern": desc})
b64_match = re.findall(r'[A-Za-z0-9+/]{40,}={0,2}', script_text)
for b64 in b64_match[:3]:
try:
import base64
decoded = base64.b64decode(b64).decode("utf-8", errors="replace")
if any(c.lower() in decoded.lower() for c in SUSPICIOUS_CMDLETS[:10]):
findings.append({"type": "encoded_payload", "preview": decoded[:100]})
except Exception:
pass
return findings
def analyze_log_file(log_path):
"""Analyze a text file containing PowerShell commands."""
findings = []
try:
with open(log_path, "r", errors="replace") as f:
content = f.read()
results = analyze_script_content(content)
if results:
findings.append({
"file": log_path,
"indicators": results,
"indicator_count": len(results),
})
except FileNotFoundError:
print(f"[!] File not found: {log_path}")
return findings
def main():
parser = argparse.ArgumentParser(
description="Detect suspicious PowerShell execution patterns"
)
parser.add_argument("--event-logs", action="store_true",
help="Parse Windows PowerShell event logs")
parser.add_argument("--script", help="Analyze a PowerShell script file")
parser.add_argument("--log-dir", help="Directory of PS log files to scan")
parser.add_argument("--output", "-o", help="Output JSON report")
parser.add_argument("--verbose", "-v", action="store_true")
args = parser.parse_args()
print("[*] Suspicious PowerShell Execution Detection Agent")
report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": []}
if args.event_logs:
events = parse_script_block_logs()
for evt in events:
script = evt.get("ScriptBlock", "")
indicators = analyze_script_content(script)
if indicators:
report["findings"].append({
"source": "event_log",
"time": evt.get("TimeCreated", ""),
"path": evt.get("Path", ""),
"indicators": indicators,
"preview": script[:200] if args.verbose else "",
})
print(f"[*] Analyzed {len(events)} script block events")
if args.script:
findings = analyze_log_file(args.script)
report["findings"].extend(findings)
if args.log_dir and os.path.isdir(args.log_dir):
for root, _, files in os.walk(args.log_dir):
for f in files:
if f.lower().endswith((".ps1", ".psm1", ".psd1", ".log", ".txt")):
findings = analyze_log_file(os.path.join(root, f))
report["findings"].extend(findings)
report["total_suspicious"] = len(report["findings"])
report["risk_level"] = (
"CRITICAL" if len(report["findings"]) >= 10
else "HIGH" if len(report["findings"]) >= 5
else "MEDIUM" if report["findings"]
else "LOW"
)
print(f"[*] Suspicious findings: {len(report['findings'])}")
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"[*] Report saved to {args.output}")
else:
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()