Files
prox0959-MemGuard/memguard.py
T

267 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
r"""
MemGuard: Zero-Dependency LSASS Memory Dump Detector & EDR Hook Shield.
Protects Windows credentials against Mimikatz, ProcDump, and LOLBin dump attacks.
Author: prox0959 (Çınar)
License: MIT
Repository: https://github.com/prox0959/MemGuard
# TR: MemGuard: Sıfır Bağımlılıklı LSASS Bellek Dökümü Dedektörü ve EDR Kalkanı.
# Windows kimlik bilgilerini Mimikatz, ProcDump ve LOLBin saldırılarına karşı korur.
"""
import sys
import os
import time
import json
import argparse
# TR: Windows 11 konsolu UTF-8 desteği (Türkçe Windows cp1254 uyumluluğu)
if sys.platform == "win32":
try:
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')
except Exception:
pass
# Add local directory to path for core imports
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from core.win_api import (
is_user_admin,
enable_debug_privilege,
get_process_snapshot,
find_lsass_process,
suspend_process
)
from core.handle_scanner import scan_lsass_handles
from core.process_auditor import audit_processes_and_cmdlines
from core.honey_dmp import scan_dump_artifacts
# ==============================================================================
# ANSI Color Codes
# ==============================================================================
RED = "\033[91m"
GREEN = "\033[92m"
YELLOW = "\033[93m"
CYAN = "\033[96m"
MAGENTA = "\033[95m"
BOLD = "\033[1m"
DIM = "\033[2m"
RESET = "\033[0m"
# ==============================================================================
# Localization Dictionary (EN / TR)
# ==============================================================================
I18N = {
"en": {
"title": "MemGuard - Zero-Dependency LSASS Memory Shield & EDR Hook Detector",
"mitre": "MITRE ATT&CK: T1003.001 (OS Credential Dumping: LSASS Memory)",
"admin_status": "Privilege Level",
"admin_true": "Elevated (Administrator) - Full Kernel Handle Access",
"admin_false": "Standard User (Non-Elevated) - Run as Admin for full handle auditing",
"debug_priv": "SeDebugPrivilege Status",
"enabled": "Enabled Successfully",
"disabled": "Not Assigned / Inactive",
"lsass_found": "Target Security Process Found",
"lsass_not_found": "LSASS process could not be identified!",
"sec_handles": "--- LSASS Handle Table Audit (NtQuerySystemInformation) ---",
"sec_procs": "--- Process Heuristics & LOLBin CommandLine Inspection ---",
"sec_dumps": "--- Dump File Artifacts & Honeypot Tripwire ---",
"no_threat_handles": "No unauthorized or suspicious handles targeting LSASS detected.",
"no_threat_procs": "No credential dumping processes or LOLBin signatures found.",
"no_threat_dumps": "No rogue memory dump (.dmp) files identified in triage directories.",
"holder": "Process",
"pid": "PID",
"handle": "Handle",
"access": "Access Mask",
"severity": "Severity",
"flags": "Granted Rights",
"action_taken": "Action Taken",
"suspended": "SUSPENDED (Frozen via NtSuspendProcess)",
"report_saved": "Forensic audit report saved to",
"monitoring": "MemGuard Real-Time Protection Active. Monitoring interval: {}s. Press Ctrl+C to stop.",
"threat_detected": "CRITICAL THREAT DETECTED!",
"summary": "Audit Summary: {} handle threats, {} process threats, {} dump artifacts."
},
"tr": {
"title": "MemGuard - Sıfır Bağımlılıklı LSASS Bellek Kalkanı ve EDR Dedektörü",
"mitre": "MITRE ATT&CK: T1003.001 (İşletim Sistemi Kimlik Bilgisi Çalma: LSASS Belleği)",
"admin_status": "Yetki Seviyesi",
"admin_true": "Yönetici (Administrator) - Tam Çekirdek Handle Erişimi Aktif",
"admin_false": "Standart Kullanıcı - Tam handle denetimi için Yönetici olarak çalıştırın",
"debug_priv": "SeDebugPrivilege Durumu",
"enabled": "Başarıyla Etkinleştirildi",
"disabled": "Atanmadı / Pasif",
"lsass_found": "Hedef Güvenlik Süreci Tespit Edildi",
"lsass_not_found": "LSASS süreci tespit edilemedi!",
"sec_handles": "--- LSASS Handle Tablosu Denetimi (NtQuerySystemInformation) ---",
"sec_procs": "--- Süreç Sezgisel Analizi ve LOLBin Komut Satırı İncelemesi ---",
"sec_dumps": "--- Bellek Dökümü (.dmp) Dosyaları ve Tuzak Denetimi ---",
"no_threat_handles": "LSASS sürecini hedef alan yetkisiz veya şüpheli açık handle bulunamadı.",
"no_threat_procs": "Şüpheli şifre çalma süreci veya LOLBin komut satırı imzası tespit edilmedi.",
"no_threat_dumps": "Geçici dizinlerde yetkisiz bellek dökümü (.dmp) dosyası bulunamadı.",
"holder": "Süreç",
"pid": "PID",
"handle": "Handle",
"access": "Erişim Maskesi",
"severity": "Tehdit Seviyesi",
"flags": "Verilen Yetkiler",
"action_taken": "Uygulanan Eylem",
"suspended": "ASKIYA ALINDI (NtSuspendProcess ile donduruldu)",
"report_saved": "Adli bilişim denetim raporu kaydedildi:",
"monitoring": "MemGuard Gerçek Zamanlı Koruma Aktif. Kontrol aralığı: {}s. Durdurmak için Ctrl+C.",
"threat_detected": "KRİTİK TEHDİT TESPİT EDİLDİ!",
"summary": "Denetim Özeti: {} handle tehdidi, {} süreç tehdidi, {} döküm dosyası."
}
}
def print_banner(lang: str):
"""Print ASCII logo and architectural header."""
t = I18N[lang]
banner = f"""
{CYAN}{BOLD}███╗ ███╗███████╗███╗ ███╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗
████╗ ████║██╔════╝████╗ ████║██╔════╝ ██║ ██║██╔══██╗██╔══██╗██╔══██╗
██╔████╔██║█████╗ ██╔████╔██║██║ ███╗██║ ██║███████║██████╔╝██║ ██║
██║╚██╔╝██║██╔══╝ ██║╚██╔╝██║██║ ██║██║ ██║██╔══██║██╔══██╗██║ ██║
██║ ╚═╝ ██║███████╗██║ ╚═╝ ██║╚██████╔╝╚██████╔╝██║ ██║██║ ██║██████╔╝
╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ {RESET}
{DIM}Zero-Dependency LSASS Memory Dump Shield & EDR Hook Detector | Pure Python{RESET}
{YELLOW}► {t['mitre']}{RESET}
"""
print(banner)
def run_audit(lang: str, auto_suspend: bool = False) -> dict:
"""
Execute a full security audit across handles, processes, and memory artifacts.
# TR: Handle'lar, süreçler ve bellek dosyaları üzerinde kapsamlı güvenlik denetimi yapar.
"""
t = I18N[lang]
is_admin = is_user_admin()
debug_priv = enable_debug_privilege() if is_admin else False
print(f"[*] {t['admin_status']}: {GREEN + t['admin_true'] if is_admin else YELLOW + t['admin_false']}{RESET}")
print(f"[*] {t['debug_priv']}: {GREEN + t['enabled'] if debug_priv else DIM + t['disabled']}{RESET}")
# 1. Snapshot processes
proc_map = get_process_snapshot()
lsass_info = find_lsass_process(proc_map)
if lsass_info:
print(f"[*] {t['lsass_found']}: {CYAN}lsass.exe{RESET} (PID: {BOLD}{lsass_info['pid']}{RESET}) | Path: {lsass_info.get('path', 'Protected')}")
else:
print(f"{RED}[!] {t['lsass_not_found']}{RESET}")
print()
# 2. System Handle Table Audit
print(f"{BOLD}{t['sec_handles']}{RESET}")
handle_threats = []
if lsass_info and is_admin:
raw_handles = scan_lsass_handles(lsass_info["pid"], proc_map)
for h in raw_handles:
# Filter unauthorized processes
if not h["is_whitelisted"]:
handle_threats.append(h)
sev_color = RED if h["severity"] == "CRITICAL" else (YELLOW if h["severity"] == "HIGH" else CYAN)
print(f" {sev_color}[{h['severity']}]{RESET} {h['holder_name']} (PID: {h['holder_pid']}) -> Handle: {h['handle_value']} | Mask: {h['access_mask']}")
print(f" {DIM}Rights: {', '.join(h['flags'])}{RESET}")
# Active mitigation if flag provided
if auto_suspend and h["is_dump_capable"]:
if suspend_process(h["holder_pid"]):
print(f" {RED}{BOLD}► {t['action_taken']}: {t['suspended']}{RESET}")
h["action"] = "SUSPENDED"
if not handle_threats:
print(f" {GREEN}✓ {t['no_threat_handles']}{RESET}")
elif not is_admin:
print(f" {YELLOW}[i] Skipped full kernel handle audit (Requires Administrator elevation).{RESET}")
print()
# 3. Process Heuristic & LOLBin Audit
print(f"{BOLD}{t['sec_procs']}{RESET}")
proc_threats = audit_processes_and_cmdlines(proc_map, lsass_info)
for p in proc_threats:
sev_color = RED if p["severity"] == "CRITICAL" else YELLOW
print(f" {sev_color}[{p['severity']}]{RESET} {p['name']} (PID: {p['pid']}) - {p['technique']}")
print(f" Reason: {p['reason']}")
if p["cmdline"]:
print(f" {DIM}CmdLine: {p['cmdline'][:120]}...{RESET}")
if auto_suspend:
if suspend_process(p["pid"]):
print(f" {RED}{BOLD}► {t['action_taken']}: {t['suspended']}{RESET}")
p["action"] = "SUSPENDED"
if not proc_threats:
print(f" {GREEN}✓ {t['no_threat_procs']}{RESET}")
print()
# 4. Dump Artifact Audit
print(f"{BOLD}{t['sec_dumps']}{RESET}")
dump_artifacts = scan_dump_artifacts()
for d in dump_artifacts:
sev_color = RED if d["severity"] == "CRITICAL" else YELLOW
print(f" {sev_color}[{d['severity']}]{RESET} Found: {d['filename']} ({d['size_mb']} MB) in {os.path.dirname(d['path'])}")
print(f" {DIM}Modified: {d['modified']}{RESET}")
if not dump_artifacts:
print(f" {GREEN}✓ {t['no_threat_dumps']}{RESET}")
print()
print(f"{BOLD}{t['summary'].format(len(handle_threats), len(proc_threats), len(dump_artifacts))}{RESET}")
return {
"timestamp": time.time(),
"is_admin": is_admin,
"lsass_info": lsass_info,
"handle_threats": handle_threats,
"process_threats": proc_threats,
"dump_artifacts": dump_artifacts
}
def main():
parser = argparse.ArgumentParser(
description="MemGuard: Zero-Dependency LSASS Memory Shield & EDR Hook Detector",
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("--scan", action="store_true", help="Perform an immediate one-shot security audit")
parser.add_argument("--monitor", action="store_true", help="Run in continuous real-time monitoring mode")
parser.add_argument("--interval", type=int, default=3, help="Polling interval in seconds for monitor mode (default: 3)")
parser.add_argument("--suspend", action="store_true", help="Automatically suspend offending processes with dump capability")
parser.add_argument("--json", type=str, metavar="FILE", help="Export audit results to a JSON report")
parser.add_argument("--lang", choices=["en", "tr"], default="en", help="Interface language: en (English) or tr (Turkish)")
args = parser.parse_args()
print_banner(args.lang)
# Default to --scan if no mode selected
if not args.scan and not args.monitor:
args.scan = True
if args.scan:
report = run_audit(args.lang, auto_suspend=args.suspend)
if args.json:
with open(args.json, "w", encoding="utf-8") as f:
json.dump(report, f, indent=2)
print(f"\n[+] {I18N[args.lang]['report_saved']} {args.json}")
elif args.monitor:
t = I18N[args.lang]
print(f"{GREEN}[*] {t['monitoring'].format(args.interval)}{RESET}\n")
try:
while True:
os.system('cls' if os.name == 'nt' else 'clear')
print_banner(args.lang)
run_audit(args.lang, auto_suspend=args.suspend)
time.sleep(args.interval)
except KeyboardInterrupt:
print(f"\n{YELLOW}[*] Monitor stopped by user.{RESET}")
if __name__ == "__main__":
main()