endpoint security

Configuring Windows Event Logging for Detection

Configures Windows Event Logging with advanced audit policies to generate high-fidelity security events for threat detection and forensic investigation. Use when enabling audit policies for logon events, process creation, privilege use, and object access to feed SIEM detection rules. Activates for requests involving Windows audit policy, event log configuration, security logging, or detection-oriented logging.

audit-policydetection-engineeringendpointevent-loggingwindows-security
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

Use this skill when:

  • Configuring Windows Advanced Audit Policy for security monitoring
  • Enabling process creation auditing with command line logging (Event 4688)
  • Setting up logon/logoff auditing for authentication monitoring
  • Sizing event log storage and forwarding to SIEM platforms

Do not use for Sysmon configuration (separate skill) or Linux audit logging.

Prerequisites

  • Windows Server or Windows 10/11 systems with Group Policy management access
  • Active Directory environment with Group Policy Object (GPO) creation privileges
  • SIEM platform configured to receive Windows Event Log forwarding
  • Understanding of Windows security event IDs and audit categories

Workflow

Step 1: Configure Advanced Audit Policy via GPO

Computer Configuration → Windows Settings → Security Settings
  → Advanced Audit Policy Configuration → Audit Policies
 
Recommended settings:
Account Logon:
  - Audit Credential Validation: Success, Failure
  - Audit Kerberos Authentication: Success, Failure
 
Account Management:
  - Audit Security Group Management: Success
  - Audit User Account Management: Success, Failure
 
Logon/Logoff:
  - Audit Logon: Success, Failure
  - Audit Logoff: Success
  - Audit Special Logon: Success
  - Audit Other Logon/Logoff Events: Success, Failure
 
Object Access:
  - Audit File Share: Success, Failure
  - Audit Removable Storage: Success, Failure
  - Audit SAM: Success
 
Policy Change:
  - Audit Audit Policy Change: Success, Failure
  - Audit Authentication Policy Change: Success
 
Privilege Use:
  - Audit Sensitive Privilege Use: Success, Failure
 
Detailed Tracking:
  - Audit Process Creation: Success
  - Audit DPAPI Activity: Success, Failure

Step 2: Enable Command Line in Process Creation Events

# Registry: Enable command line logging in Event 4688
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" `
  -Name ProcessCreationIncludeCmdLine_Enabled -Value 1 -PropertyType DWORD -Force
 
# GPO: Computer Configuration → Administrative Templates → System → Audit Process Creation
# "Include command line in process creation events" → Enabled

Step 3: Configure Event Log Sizes

# Increase Security log to 1 GB (default 20 MB is insufficient)
wevtutil sl Security /ms:1073741824
 
# Increase PowerShell Operational log
wevtutil sl "Microsoft-Windows-PowerShell/Operational" /ms:536870912
 
# Set log retention to overwrite as needed
wevtutil sl Security /rt:false
 
# Configure via GPO:
# Computer Configuration → Administrative Templates → Windows Components
#   → Event Log Service → Security
# Maximum log file size (KB): 1048576

Step 4: Configure Windows Event Forwarding (WEF)

# On collector server:
wecutil qc /q
 
# Create subscription for high-value events:
# Event IDs: 4624 (logon), 4625 (failed logon), 4688 (process create),
# 4672 (special privilege), 4720 (user created), 4728 (group membership),
# 7045 (service installed), 1102 (log cleared)
 
# On source endpoints (GPO):
# Configure WinRM: winrm quickconfig
# Configure event forwarding: Computer Configuration → Admin Templates
#   → Windows Components → Event Forwarding
# Configure target Subscription Manager: Server=http://collector:5985/wsman/SubscriptionManager/WEC

Step 5: Key Event IDs for Detection

Authentication Events:
  4624 - Successful logon (Type 2=Interactive, 3=Network, 10=RemoteInteractive)
  4625 - Failed logon attempt
  4648 - Logon using explicit credentials (RunAs, pass-the-hash indicator)
  4672 - Special privileges assigned (admin logon)
  4776 - NTLM credential validation
 
Process Events:
  4688 - Process creation (with command line if enabled)
  4689 - Process termination
 
Account Events:
  4720 - User account created
  4722 - User account enabled
  4724 - Password reset attempted
  4728 - Member added to security group
  4732 - Member added to local group
  4756 - Member added to universal group
 
Service/System Events:
  7045 - New service installed (persistence indicator)
  1102 - Audit log cleared (evidence tampering)
  4697 - Service installed in the system
 
Lateral Movement Indicators:
  4648 + 4624(Type 3) - Credential-based lateral movement
  5140 - Network share accessed
  5145 - Network share access check (detailed file share)

Key Concepts

Term Definition
Advanced Audit Policy Granular audit subcategories (58 subcategories vs. 9 basic categories)
Event ID 4688 Process creation event; essential for tracking execution on endpoints
WEF Windows Event Forwarding; centralized log collection without third-party agents
Logon Type Numeric code indicating authentication method (2=interactive, 3=network, 10=RDP)

Tools & Systems

  • Windows Event Forwarding (WEF): Built-in centralized log collection
  • NXLog: Open-source log forwarding agent for Windows events
  • Winlogbeat: Elastic Agent for shipping Windows event logs to Elasticsearch
  • Palantir WEF Configuration: Open-source WEF subscription templates

Common Pitfalls

  • Using basic audit policy instead of advanced: Basic and advanced audit policies conflict. Always use advanced audit policy exclusively.
  • Default log size too small: 20 MB Security log fills in minutes on busy servers. Set minimum 1 GB.
  • Missing command line logging: Event 4688 without command line content has minimal detection value. Always enable ProcessCreationIncludeCmdLine_Enabled.
  • Not forwarding logs: Local event logs are lost when endpoints are wiped by ransomware. Forward to centralized SIEM immediately.
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md1.5 KB

Windows Event Logging for Detection — API Reference

Key PowerShell Cmdlets

Cmdlet Description
auditpol /get /category:* View advanced audit policy
auditpol /set /subcategory:"Process Creation" /success:enable Enable audit subcategory
Get-WinEvent -ListLog * List available event logs
wevtutil sl Security /ms:1073741824 Set Security log max size to 1 GB

Critical Event IDs for Detection

Event ID Log Description
4624/4625 Security Successful/failed logon
4662 Security Directory service object access
4688 Security Process creation (with command line)
4698 Security Scheduled task created
4720 Security User account created
4732 Security Member added to security group
4768/4769 Security Kerberos TGT/service ticket
1 Sysmon Process creation with hashes
3 Sysmon Network connection
7 Sysmon Image loaded (DLL)
11 Sysmon File creation
4104 PowerShell Script block logging

Recommended Log Sizes

Log Minimum Size
Security 1 GB
Sysmon/Operational 512 MB
PowerShell/Operational 256 MB
System 256 MB

External References

standards.md0.4 KB

Standards & References

workflows.md0.3 KB

Workflows

Event Logging Deployment

[Audit current logging configuration] → [Enable Advanced Audit Policy via GPO]
  → [Enable command line logging] → [Increase log sizes]
  → [Configure WEF or agent-based forwarding] → [Verify events in SIEM]
  → [Build detection rules from high-value events] → [Quarterly logging audit]

Scripts 2

agent.py5.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Windows event logging configuration audit agent."""

import json
import argparse
import subprocess
from datetime import datetime


CRITICAL_AUDIT_POLICIES = {
    "Logon/Logoff": {"Logon": "Success,Failure", "Logoff": "Success"},
    "Account Logon": {"Credential Validation": "Success,Failure", "Kerberos Authentication Service": "Success,Failure"},
    "Object Access": {"File System": "Success,Failure", "Registry": "Success,Failure"},
    "Privilege Use": {"Sensitive Privilege Use": "Success,Failure"},
    "Process Tracking": {"Process Creation": "Success"},
    "DS Access": {"Directory Service Access": "Success,Failure"},
    "Policy Change": {"Audit Policy Change": "Success,Failure", "Authentication Policy Change": "Success"},
}


def get_audit_policy():
    """Get current advanced audit policy configuration."""
    cmd = ["auditpol", "/get", "/category:*"]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
        lines = result.stdout.strip().split("\n")
        policies = {}
        current_category = ""
        for line in lines:
            stripped = line.strip()
            if not stripped or "Machine Name" in stripped or "Category" in stripped:
                continue
            if not stripped.startswith("  "):
                current_category = stripped
                policies[current_category] = {}
            else:
                parts = stripped.rsplit("  ", 1)
                if len(parts) == 2:
                    policies[current_category][parts[0].strip()] = parts[1].strip()
        return policies
    except (FileNotFoundError, subprocess.TimeoutExpired) as e:
        return {"error": str(e)}


def check_sysmon_installed():
    """Check if Sysmon is installed and running."""
    cmd = ["powershell", "-Command", "Get-Service Sysmon* | ConvertTo-Json"]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
        if result.stdout.strip():
            service = json.loads(result.stdout)
            if isinstance(service, list):
                service = service[0]
            return {"installed": True, "status": service.get("Status", ""),
                    "name": service.get("Name", "")}
        return {"installed": False, "severity": "HIGH",
                "recommendation": "Install Sysmon with SwiftOnSecurity config"}
    except (FileNotFoundError, json.JSONDecodeError):
        return {"installed": False}


def check_log_sizes():
    """Check event log maximum sizes."""
    logs = ["Security", "System", "Application", "Microsoft-Windows-Sysmon/Operational",
            "Microsoft-Windows-PowerShell/Operational"]
    results = []
    for log_name in logs:
        cmd = ["powershell", "-Command",
               f"(Get-WinEvent -ListLog '{log_name}' -ErrorAction SilentlyContinue).MaximumSizeInBytes"]
        try:
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            size_bytes = int(result.stdout.strip()) if result.stdout.strip() else 0
            size_mb = round(size_bytes / (1024 * 1024), 1)
            results.append({
                "log": log_name,
                "max_size_mb": size_mb,
                "severity": "MEDIUM" if size_mb < 100 else "INFO",
            })
        except (ValueError, subprocess.TimeoutExpired):
            results.append({"log": log_name, "error": "Cannot query"})
    return results


def check_powershell_logging():
    """Check PowerShell script block logging and transcription."""
    checks = {}
    for name, path in [
        ("ScriptBlockLogging", r"HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"),
        ("Transcription", r"HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription"),
    ]:
        cmd = ["powershell", "-Command", f"Get-ItemProperty -Path '{path}' -ErrorAction SilentlyContinue | ConvertTo-Json"]
        try:
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            checks[name] = json.loads(result.stdout) if result.stdout.strip() else {"enabled": False}
        except (json.JSONDecodeError, subprocess.TimeoutExpired):
            checks[name] = {"enabled": False}
    return checks


def run_audit():
    """Execute Windows event logging audit."""
    print(f"\n{'='*60}")
    print(f"  WINDOWS EVENT LOGGING AUDIT")
    print(f"  Generated: {datetime.utcnow().isoformat()} UTC")
    print(f"{'='*60}\n")

    sysmon = check_sysmon_installed()
    print(f"--- SYSMON ---")
    print(f"  Installed: {sysmon.get('installed', False)}")
    print(f"  Status: {sysmon.get('status', 'N/A')}")

    logs = check_log_sizes()
    print(f"\n--- LOG SIZES ---")
    for l in logs:
        if "error" not in l:
            print(f"  {l['log']}: {l['max_size_mb']} MB [{l['severity']}]")

    ps_logging = check_powershell_logging()
    print(f"\n--- POWERSHELL LOGGING ---")
    for name, config in ps_logging.items():
        enabled = config.get("EnableScriptBlockLogging", config.get("EnableTranscripting", False))
        print(f"  {name}: {'Enabled' if enabled else 'Disabled'}")

    return {"sysmon": sysmon, "log_sizes": logs, "powershell": ps_logging}


def main():
    parser = argparse.ArgumentParser(description="Windows Event Logging Audit Agent")
    parser.add_argument("--audit", action="store_true", help="Run full audit")
    parser.add_argument("--output", help="Save report to JSON file")
    args = parser.parse_args()

    if args.audit:
        report = run_audit()
        if args.output:
            with open(args.output, "w") as f:
                json.dump(report, f, indent=2, default=str)
            print(f"\n[+] Report saved to {args.output}")
    else:
        parser.print_help()


if __name__ == "__main__":
    main()
process.py2.0 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Windows Event Logging Auditor - Checks current audit policy configuration."""

import json, subprocess, sys, os
from datetime import datetime


def get_audit_policy() -> dict:
    """Query current advanced audit policy via auditpol."""
    try:
        result = subprocess.run(
            ["auditpol", "/get", "/category:*"],
            capture_output=True, text=True, timeout=15,
        )
        if result.returncode != 0:
            return {"error": result.stderr}

        policies = {}
        current_category = ""
        for line in result.stdout.splitlines():
            line = line.strip()
            if not line:
                continue
            if "  " not in line and line.endswith(":"):
                continue
            parts = line.rsplit("  ", 1)
            if len(parts) == 2:
                name = parts[0].strip()
                setting = parts[1].strip()
                policies[name] = setting
        return policies
    except FileNotFoundError:
        return {"error": "auditpol not available (requires Windows)"}


RECOMMENDED = {
    "Credential Validation": "Success and Failure",
    "Security Group Management": "Success",
    "User Account Management": "Success and Failure",
    "Logon": "Success and Failure",
    "Logoff": "Success",
    "Special Logon": "Success",
    "Process Creation": "Success",
    "Audit Policy Change": "Success",
    "Sensitive Privilege Use": "Success and Failure",
}


if __name__ == "__main__":
    policies = get_audit_policy()
    if "error" in policies:
        print(f"Error: {policies['error']}")
        sys.exit(1)

    compliant = 0
    total = len(RECOMMENDED)
    for setting, expected in RECOMMENDED.items():
        actual = policies.get(setting, "No Auditing")
        status = "PASS" if expected in actual else "FAIL"
        if status == "PASS":
            compliant += 1
        print(f"[{status}] {setting}: {actual} (expected: {expected})")

    print(f"\nScore: {compliant}/{total} ({round(compliant/total*100)}%)")

Assets 1

template.mdtext/markdown · 0.5 KB
Keep exploring