-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWinLogKit.Settings.ps1
More file actions
635 lines (543 loc) · 50.9 KB
/
Copy pathWinLogKit.Settings.ps1
File metadata and controls
635 lines (543 loc) · 50.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
# =============================================================================
# WinLogKit.Settings.ps1
# The settings table every kit script dot-sources.
#
# This is the single source of truth for the kit. Both the enable script and
# the verification script dot-source this file, so they can never disagree
# about what "correct" looks like. If you change a setting, change it here.
#
# Source baselines (extracted 2026-08-31):
# - Yamato Security, EnableWindowsLogSettings
# https://github.com/Yamato-Security/EnableWindowsLogSettings
# (README.md, ConfiguringSecurityLogAuditPolicies.md,
# YamatoSecurityConfigureWinEventLogs.bat)
# - Yamato Security, WELA v2.1.0 (WELA.ps1 configure command)
# https://github.com/Yamato-Security/WELA
#
# Deliberate deviations from those sources are marked "DEVIATION" with the
# reason. Nothing here requires Sysmon or any third party tooling.
#
# Field meanings:
# Tier - Core : applied/tested by default
# HighVolume : material event volume, performance impact, or only
# useful in some environments (v2 folded the old
# Optional tier in here, ADR-002). Only applied
# with -IncludeHighVolume so a human decides, not
# the script.
# Scope - All | DomainController. DomainController items are skipped
# (NOT APPLICABLE) on standalone and member servers.
# Condition - extra runtime requirement, e.g. 'ADCS' = only when the
# Certificate Services role is installed.
# Categories - which behaviour categories the item satisfies.
# Used for the per-category PASS/FAIL rollup in the test script.
# Situational - optional, $true on the HighVolume items that are opt-in
# because they only matter in some environments, not because
# they are loud (the old Optional tier). The Reference page
# labels their volume from the Risk note and does not count
# them as part of Yamato's set.
#
# PowerShell 5.1 compatible. No external module dependencies.
#
# -----------------------------------------------------------------------------
# STABILITY SAFETY - settings this kit deliberately NEVER touches, because
# they can hang, halt or lock out a server:
#
# - CrashOnAuditFail / "Audit: Shut down system immediately if unable to log
# security audits" (HKLM\SYSTEM\CurrentControlSet\Control\Lsa\CrashOnAuditFail).
# With this on, a full Security log halts the machine with
# STOP C0000244 {Audit Failed}, and until reset only Administrators can log
# on (breaks IIS, AD replication, everything using non-admin logons).
# https://learn.microsoft.com/troubleshoot/developer/webapps/iis/health-diagnostic-performance/users-cannot-access-web-sites-when-log-full
# - "Do not overwrite events" retention (LogMode = Retain). Logging silently
# stops when the log fills; combined with CrashOnAuditFail it crashes the
# host. Test-LoggingBaseline flags Retain mode as a FAIL.
# - "Audit the access of global system objects" (AuditBaseObjects) and
# Global Object Access Auditing - blanket SACLs on all kernel/file/registry
# objects; extreme volume and measurable performance degradation.
# - Blanket File System / Registry SACLs - per-object auditing is a scoped
# design decision, never a default.
# - The kit also never SHRINKS a log, never reboots, and never restarts a
# service.
# -----------------------------------------------------------------------------
#
# Optional 'Risk' field on items below: a plain-language stability/performance
# note, shown by New-LoggingBaseline.ps1 so selections are made with eyes open.
# Microsoft rates the WFP subcategories' volume as High; module logging has a
# measurable PowerShell performance cost on script-heavy servers.
# =============================================================================
Set-StrictMode -Version 2.0
# The 16 behaviour categories, in fixed display order.
$script:BaselineCategories = @(
'Authentication'
'Execution'
'Account and access change'
'Privilege use'
'Logging tampered with'
'Software and service install'
'Remote access'
'Scheduled and automated tasks'
'Scripting and command line'
'Persistence'
'Removable and external devices'
'Blocked and denied activity'
'Directory and identity store'
'File and object access'
'Certificates and keys'
'Network flow and sessions'
)
# -----------------------------------------------------------------------------
# 1. EVENT LOG CHANNELS - maximum size and enablement
#
# Sizes follow the Yamato batch script / WELA configure command:
# 1 GB (1073741824) for Security and the PowerShell logs
# 128 MB (134217728) for the other important operational logs
# The enable script only ever RAISES a size, it never shrinks a log.
# 'MustEnable' channels are disabled out of the box and must be switched on.
# -----------------------------------------------------------------------------
$oneGB = 1073741824
$mb128 = 134217728
$script:BaselineChannels = @(
@{ Name = 'Security'; TargetBytes = $oneGB; MustEnable = $false; Tier = 'Core'; DefaultSize = '20 MB'
Categories = @('Authentication','Execution','Account and access change','Privilege use','Logging tampered with','Directory and identity store','File and object access','Certificates and keys','Network flow and sessions','Scheduled and automated tasks','Removable and external devices')
Purpose = 'The main audit log. Almost every behaviour category lands here. 1 GB so evidence is not overwritten within days.' }
@{ Name = 'Microsoft-Windows-PowerShell/Operational'; TargetBytes = $oneGB; MustEnable = $false; Tier = 'Core'; DefaultSize = '15 MB'
Categories = @('Scripting and command line','Execution')
Purpose = 'PowerShell 5.1 module logging (4103) and script block logging (4104) land here. High value, high volume once those are on.' }
@{ Name = 'Windows PowerShell'; TargetBytes = $oneGB; MustEnable = $false; Tier = 'Core'; DefaultSize = '15 MB'
Categories = @('Scripting and command line','Execution')
Purpose = 'Classic PowerShell engine lifecycle log (400/403/600). Older but still used by detections for downgrade attacks.' }
@{ Name = 'PowerShellCore/Operational'; TargetBytes = $oneGB; MustEnable = $true; Tier = 'Core'; DefaultSize = '15 MB'; MayBeAbsent = $true
Categories = @('Scripting and command line','Execution')
Purpose = 'PowerShell 7+ equivalent of the Operational log (4103/4104 from pwsh, with the PS7 policy items). Exists only once PowerShell 7''s event manifest is registered: absent is NOT APPLICABLE without PowerShell 7, and a FAIL when PowerShell 7 is installed but unregistered (run $PSHOME\RegisterManifest.ps1 as admin).' }
@{ Name = 'System'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '20 MB'
Categories = @('Software and service install','Persistence','Logging tampered with')
Purpose = 'Service installs (7045), service stop/start (7036), event log service stop, log cleared (104).' }
@{ Name = 'Application'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '20 MB'
Categories = @('Software and service install')
Purpose = 'MSI installs/uninstalls (MsiInstaller 1040/1034), ESENT database access (NTDS.dit dumping), application crashes.' }
@{ Name = 'Microsoft-Windows-Windows Defender/Operational'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'; MayBeAbsent = $true
Categories = @('Blocked and denied activity','Logging tampered with')
Purpose = 'Defender detections, exclusions being added, tamper protection changes, history deletion.' }
@{ Name = 'Microsoft-Windows-Bits-Client/Operational'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Execution','Persistence')
Purpose = 'BITS transfer jobs. bitsadmin.exe is a common living-off-the-land download/execute channel.' }
@{ Name = 'Microsoft-Windows-Windows Firewall With Advanced Security/Firewall'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Blocked and denied activity','Network flow and sessions')
Purpose = 'Firewall rules added, modified or deleted. Malware adds rules to let C2 traffic through.' }
@{ Name = 'Microsoft-Windows-NTLM/Operational'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Authentication')
Purpose = 'Outgoing NTLM usage, populated once the NTLM audit registry values below are set. Needed to plan NTLM retirement.' }
@{ Name = 'Microsoft-Windows-Security-Mitigations/KernelMode'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Blocked and denied activity')
Purpose = 'Exploit protection / mitigation events (kernel mode).' }
@{ Name = 'Microsoft-Windows-Security-Mitigations/UserMode'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Blocked and denied activity')
Purpose = 'Exploit protection / mitigation events (user mode).' }
@{ Name = 'Microsoft-Windows-PrintService/Admin'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Software and service install')
Purpose = 'Print service errors, including failed driver installs (PrintNightmare class attacks).' }
@{ Name = 'Microsoft-Windows-PrintService/Operational'; TargetBytes = $mb128; MustEnable = $true; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Software and service install')
Purpose = 'Print driver installs and print jobs. DISABLED by default so must be enabled. Note: the Yamato batch sizes this log but never enables it - the kit fixes that.' }
@{ Name = 'Microsoft-Windows-SmbClient/Security'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '8 MB'
Categories = @('Remote access','Network flow and sessions')
Purpose = 'Outbound SMB session failures, rejected guest logons, hidden share mounts.' }
@{ Name = 'Microsoft-Windows-AppLocker/EXE and DLL'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Blocked and denied activity','Execution')
Purpose = 'AppLocker allow/deny decisions for executables and DLLs. Only populates if AppLocker policy is deployed.' }
@{ Name = 'Microsoft-Windows-AppLocker/MSI and Script'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Blocked and denied activity','Execution','Scripting and command line')
Purpose = 'AppLocker decisions for installers and scripts.' }
@{ Name = 'Microsoft-Windows-AppLocker/Packaged app-Deployment'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Blocked and denied activity','Software and service install')
Purpose = 'AppLocker decisions for packaged (Store) app deployment.' }
@{ Name = 'Microsoft-Windows-AppLocker/Packaged app-Execution'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Blocked and denied activity','Execution')
Purpose = 'AppLocker decisions for packaged (Store) app execution.' }
@{ Name = 'Microsoft-Windows-CodeIntegrity/Operational'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Blocked and denied activity','Software and service install')
Purpose = 'Driver loads blocked by code integrity - a failed malicious driver load shows up here.' }
@{ Name = 'Microsoft-Windows-Diagnosis-Scripted/Operational'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Scripting and command line','Execution')
Purpose = 'Diagnostic (diagcab) package execution - abused for social engineering delivery.' }
@{ Name = 'Microsoft-Windows-DriverFrameworks-UserMode/Operational'; TargetBytes = $mb128; MustEnable = $true; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Removable and external devices')
Purpose = 'USB device plug/unplug detail. DISABLED by default so must be enabled.' }
@{ Name = 'Microsoft-Windows-WMI-Activity/Operational'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Execution','Persistence','Scheduled and automated tasks')
Purpose = 'WMI operations. WMI event subscriptions are a common fileless persistence mechanism.' }
@{ Name = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Remote access')
Purpose = 'RDP session connect/disconnect/reconnect (21/24/25) with source address - survives Security log clearing.' }
# Kit additions: the two RDP logs before the session starts. Both are on
# by default at 1 MB, so they wrap within hours on an exposed host.
# Event IDs as their providers define them.
@{ Name = 'Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational'; TargetBytes = $mb128; MustEnable = $true; Tier = 'Core'; DefaultSize = '1 MB'; MayBeAbsent = $true
Categories = @('Remote access','Authentication')
Purpose = 'RDP connections reaching the listener (261) and successful network-level authentication with user and source address (1149), logged before any session or Security-log logon exists.' }
@{ Name = 'Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational'; TargetBytes = $mb128; MustEnable = $true; Tier = 'Core'; DefaultSize = '1 MB'; MayBeAbsent = $true
Categories = @('Remote access','Authentication')
Purpose = 'RDP transport: new connections accepted with the client address (131) and connections failed on a bad user name or password (140), the RDP brute-force signal.' }
@{ Name = 'Microsoft-Windows-TaskScheduler/Operational'; TargetBytes = $mb128; MustEnable = $true; Tier = 'Core'; DefaultSize = '1 MB'
Categories = @('Scheduled and automated tasks','Persistence')
Purpose = 'Task registration, updates and execution. DISABLED by default so must be enabled. Tasks are a top persistence mechanism.' }
@{ Name = 'Microsoft-Windows-SMBServer/Audit'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '8 MB'; MayBeAbsent = $true
Categories = @('Remote access','Network flow and sessions')
Purpose = 'SMB server audit events, including signing/encryption capability auditing on Windows 11 24H2 / Server 2025 and later (3021/3022) - identifies clients that cannot do SMB signing or encryption before you enforce it.' }
@{ Name = 'Microsoft-Windows-SmbClient/Audit'; TargetBytes = $mb128; MustEnable = $false; Tier = 'Core'; DefaultSize = '8 MB'; MayBeAbsent = $true
Categories = @('Remote access','Network flow and sessions')
Purpose = 'SMB client audit events, including signing/encryption capability auditing (31998/31999) and insecure guest logons (31997) on Windows 11 24H2 / Server 2025 and later, and NTLM-blocking diagnostics.' }
# SMB server security and operational events (#72 follow-up). Microsoft's
# insecure-guest-logon page puts event 3023 in SMBServer/Security; the
# provider definition on Windows 11 build 26200 puts it in
# SMBServer/Operational. Both are collected, so it's kept either way.
@{ Name = 'Microsoft-Windows-SMBServer/Security'; TargetBytes = $mb128; MustEnable = $true; Tier = 'Core'; DefaultSize = '8 MB'; MayBeAbsent = $true
Categories = @('Remote access','Authentication')
Purpose = 'SMB server security events: session authentication failures (551), share and anonymous access denied (1006/1007/1009), weak session keys (1906), and insecure guest logons (3023, per Microsoft''s docs).' }
@{ Name = 'Microsoft-Windows-SMBServer/Operational'; TargetBytes = $mb128; MustEnable = $true; Tier = 'Core'; DefaultSize = '8 MB'; MayBeAbsent = $true
Categories = @('Remote access','Authentication')
Purpose = 'SMB server operational events, including insecure guest logons (3023) where the provider writes them here (as current Windows 11 builds do) when the server-side guest-logon audit is on.' }
@{ Name = 'Microsoft-Windows-Crypto-DPAPI/Debug'; TargetBytes = $mb128; MustEnable = $true; Tier = 'HighVolume'; DefaultSize = '1 MB'; MayBeAbsent = $true; Situational = $true
Categories = @('Certificates and keys')
Purpose = 'DPAPI key operations. Added by WELA v2.1 configure. A debug-class channel, so opt-in: enable only if DPAPI theft (e.g. Mimikatz backup key export) is a monitored scenario.'
Risk = 'Debug-class channels carry a small constant tracing overhead and are not designed for always-on production use. Enable deliberately, not by default.' }
)
# -----------------------------------------------------------------------------
# 2. ADVANCED AUDIT POLICY SUBCATEGORIES
#
# GUIDs are used instead of names so the scripts work on any OS language
# (same approach as the Yamato batch). Success/Failure flags are the Yamato
# recommendation. Items commented out of the Yamato batch (Process Termination,
# Token Right Adjusted, Group Membership, Detailed File Share, File System,
# Filtering Platform Packet Drop, Kernel Object, Registry, Authorization
# Policy Change, Filtering Platform Policy Change, MPSSVC Rule-Level Policy
# Change) are deliberately NOT here - see README "Known gaps".
# -----------------------------------------------------------------------------
$script:BaselineAuditSubcategories = @(
# --- Account Logon ---
@{ Name = 'Credential Validation'; Guid = '0CCE923F-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Authentication')
Purpose = 'NTLM authentication results (4776). Catches password spraying and username guessing over NTLM.' }
@{ Name = 'Kerberos Authentication Service'; Guid = '0CCE9242-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'DomainController'; Tier = 'Core'
Categories = @('Authentication','Directory and identity store')
Purpose = 'Kerberos TGT requests (4768) and pre-auth failures (4771). Only generated on domain controllers.' }
@{ Name = 'Kerberos Service Ticket Operations'; Guid = '0CCE9240-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'DomainController'; Tier = 'Core'
Categories = @('Authentication')
Purpose = 'Service ticket requests (4769) - the Kerberoasting detection event. Only generated on domain controllers.' }
# --- Account Management ---
@{ Name = 'Computer Account Management'; Guid = '0CCE9236-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'DomainController'; Tier = 'Core'
Categories = @('Account and access change','Directory and identity store')
Purpose = 'Computer accounts created/changed/deleted (4741-4743). DCShadow detection uses 4742. DC only.' }
@{ Name = 'Distribution Group Management'; Guid = '0CCE9238-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'DomainController'; Tier = 'Core'
Categories = @('Account and access change')
Purpose = 'Distribution group lifecycle. In the WELA configure baseline (not the older batch). DC only in practice.' }
@{ Name = 'Other Account Management Events'; Guid = '0CCE923A-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Account and access change')
Purpose = 'Password hash access (4782) and password policy API checks (4793). Rare, low volume, high signal.' }
@{ Name = 'Security Group Management'; Guid = '0CCE9237-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Account and access change')
Purpose = 'Group create/change/delete and membership changes (4727-4764). "User added to local Administrators" (4732) lives here.' }
@{ Name = 'User Account Management'; Guid = '0CCE9235-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Account and access change')
Purpose = 'User accounts created/enabled/changed/deleted, password resets, lockouts (4720-4767). Backdoor account detection.' }
# --- Detailed Tracking ---
@{ Name = 'Plug and Play'; Guid = '0CCE9248-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Removable and external devices')
Purpose = 'New external device connected (6416), device install blocked/allowed (6419-6424). USB and rogue-device tracking.' }
@{ Name = 'Process Creation'; Guid = '0CCE922B-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'HighVolume'
Categories = @('Execution','Scripting and command line','Persistence')
Purpose = 'Process creation (4688). The single highest value audit setting - roughly half of all Sigma rules need it - but HIGH VOLUME. Pair with the command line registry value below.'
Risk = 'Event volume scales with process churn; heaviest on RDS/Citrix and build servers. Disk and SIEM cost, not a stability risk.' }
@{ Name = 'RPC Events'; Guid = '0CCE922E-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Remote access','Network flow and sessions')
Purpose = 'Inbound RPC connections (5712). Rare event in practice; Microsoft warns it can be busy on heavy RPC servers.'
Risk = 'Usually near-silent, but Microsoft flags high volume on RPC-heavy servers (Exchange, some cluster roles). Deselect if 5712 floods.' }
# --- DS Access ---
@{ Name = 'Directory Service Access'; Guid = '0CCE923B-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'DomainController'; Tier = 'Core'
Categories = @('Directory and identity store')
Purpose = 'AD object access (4661/4662). DCSync and DPAPI backup key theft detection. DC only; needs SACLs on AD objects for full value.' }
@{ Name = 'Directory Service Changes'; Guid = '0CCE923C-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'DomainController'; Tier = 'Core'
Categories = @('Directory and identity store','Persistence')
Purpose = 'AD object modifications with old/new values (5136-5141). AD backdoor and DCShadow detection. DC only.' }
# --- Logon/Logoff ---
@{ Name = 'Account Lockout'; Guid = '0CCE9217-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Authentication','Blocked and denied activity')
Purpose = 'Logons failing because the account is locked out (4625 / 0xC0000234).' }
@{ Name = 'Logoff'; Guid = '0CCE9216-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Authentication')
Purpose = 'Session end (4634/4647). Needed to bound session duration in investigations.' }
@{ Name = 'Logon'; Guid = '0CCE9215-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Authentication','Remote access')
Purpose = 'Logon success/failure and explicit-credential logons (4624/4625/4648). Logon type field distinguishes console, network, RDP.' }
@{ Name = 'Other Logon/Logoff Events'; Guid = '0CCE921C-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Authentication','Remote access')
Purpose = 'RDP session reconnect/disconnect (4778/4779), workstation lock/unlock, CredSSP delegation blocks.' }
@{ Name = 'Special Logon'; Guid = '0CCE921B-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Privilege use','Authentication')
Purpose = 'Logons holding admin-equivalent privileges (4672). Cheap way to see privileged sessions without Sensitive Privilege Use volume.' }
# --- Object Access ---
@{ Name = 'Certification Services'; Guid = '0CCE9221-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Certificates and keys')
Purpose = 'AD CS activity including certificate template events (4898/4899, ESC-class template abuse). Harmless when AD CS absent - simply generates nothing.' }
@{ Name = 'File Share'; Guid = '0CCE9224-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('File and object access','Remote access')
Purpose = 'Share connections (5140, ADMIN$ access), share created/modified/deleted (5142-5144). Busy on file servers and DCs.'
Risk = 'On dedicated file servers and DCs (SYSVOL access) this is a steady event stream. Watch log wrap time during the pilot.' }
@{ Name = 'Filtering Platform Connection'; Guid = '0CCE9226-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'HighVolume'
Categories = @('Network flow and sessions','Blocked and denied activity')
Purpose = 'Per-connection allow/block from Windows Filtering Platform (5156/5157) plus listens and binds. The closest native equivalent to network flow telemetry. HIGH VOLUME.'
Risk = 'Microsoft rates this volume High. On connection-heavy servers (DCs, web, SQL) it can dominate the Security log and add measurable CPU/disk load; can wrap a 1 GB log in hours. Deploy to a pilot host first.' }
@{ Name = 'Other Object Access Events'; Guid = '0CCE9227-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Scheduled and automated tasks','Persistence')
Purpose = 'Scheduled task created/deleted/enabled/disabled/updated (4698-4702) in the Security log. Low volume, high signal.' }
@{ Name = 'Removable Storage'; Guid = '0CCE9245-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Removable and external devices','File and object access')
Purpose = 'Every file access on removable storage (4663), no SACL needed. Volume scales with how much USB storage is actually used.'
Risk = 'A large file copy to USB generates an event per file access. Low on servers where USB is rare; heavy where USB drives are routine.' }
@{ Name = 'SAM'; Guid = '0CCE9220-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Directory and identity store')
Purpose = 'Access to local SAM objects (4661). Detects local account/group reconnaissance. Can be busy on DCs - test there first.'
Risk = 'High event rate on domain controllers. Volume/cost concern only, not stability.' }
# --- Policy Change ---
@{ Name = 'Audit Policy Change'; Guid = '0CCE922F-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Logging tampered with')
Purpose = 'The audit policy itself being changed (4719), SACLs changed (4715/4907), CrashOnAuditFail changed. Core anti-tamper telemetry.' }
@{ Name = 'Authentication Policy Change'; Guid = '0CCE9230-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Account and access change','Authentication')
Purpose = 'Domain/forest trusts added or removed (4706/4707), Kerberos policy changes, logon rights granted (4717).' }
@{ Name = 'Other Policy Change Events'; Guid = '0CCE9234-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Network flow and sessions','Certificates and keys')
Purpose = 'WFP filter changes and CNG crypto operations. NOTE: the Yamato guide text says leave off because event 5447 is noisy, but both Yamato scripts enable it. The kit follows the scripts; drop to save volume if 5447 floods.' }
# --- Privilege Use ---
@{ Name = 'Sensitive Privilege Use'; Guid = '0CCE9228-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'HighVolume'
Categories = @('Privilege use')
Purpose = 'Use of dangerous privileges - SeDebugPrivilege, SeLoadDriverPrivilege, SeTcbPrivilege (4673/4674). Detects credential dumpers and driver loading, but HIGH VOLUME.'
Risk = 'Known to flood on hosts running backup agents and monitoring software (backup/restore privileges fire constantly). Test on one host per server role before fleet rollout.' }
# --- System ---
@{ Name = 'IPsec Driver'; Guid = '0CCE9213-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'HighVolume'; Situational = $true
Categories = @('Network flow and sessions')
Purpose = 'IPsec driver packet events (4960-4963, 4965) and IPsec service start/stop and filter-processing events (5478-5480, 5483-5485). In Microsoft''s baseline recommendation (and the Microsoft_Client baseline in Yamato''s EventLog-Baseline-Guide) but not in the Yamato set, so opt-in: enable where IPsec is actually used.' }
@{ Name = 'Security State Change'; Guid = '0CCE9210-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Logging tampered with')
Purpose = 'System start/shutdown and system time changes (4616). Time tampering breaks forensic timelines.' }
@{ Name = 'Security System Extension'; Guid = '0CCE9211-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Software and service install','Persistence')
Purpose = 'Service installed (4697) and authentication packages / SSPs registered with LSA (4610/4611/4622). Top-tier persistence telemetry.' }
@{ Name = 'System Integrity'; Guid = '0CCE9212-69AE-11D9-BED3-505054503030'; Success = $true; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Logging tampered with')
Purpose = 'Audit events lost (4612), invalid image hashes (5038/6281). Integrity of the logging pipeline itself.' }
@{ Name = 'Other System Events'; Guid = '0CCE9214-69AE-11D9-BED3-505054503030'; Success = $false; Failure = $true; Scope = 'All'; Tier = 'Core'
Categories = @('Logging tampered with','Certificates and keys')
Purpose = 'Firewall service start/stop and crypto key file operations. Failure-only, matching the Yamato batch (success side is noise). WELA sets Success and Failure; either satisfies the failure requirement.' }
)
# -----------------------------------------------------------------------------
# 3. REGISTRY SETTINGS
#
# All values written under HKLM. 'Kind' is a Microsoft.Win32.RegistryValueKind
# name. 'AbsentOk' items compare as PASS when absent AND value optional.
# -----------------------------------------------------------------------------
$script:BaselineRegistrySettings = @(
# -- Process command line capture (pairs with the Process Creation subcategory) --
@{ Id = 'CmdLineAudit'
Path = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit'; Name = 'ProcessCreationIncludeCmdLine_Enabled'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Execution','Scripting and command line')
Purpose = 'Adds the full command line to every 4688 process creation event. Most process-based detections need it. CAUTION: command lines can contain passwords typed by admins - handle the Security log as sensitive.'
Risk = 'No extra event count (enriches 4688), but a privacy/secrets consideration: credentials passed on command lines become log content.' }
# -- PowerShell script block logging (event 4104) --
# DEVIATION: the Yamato batch writes only the Wow6432Node path. Group Policy
# writes the native path, and 64-bit PowerShell reads the native path, so the
# kit sets BOTH to cover 32-bit and 64-bit hosts.
@{ Id = 'ScriptBlock64'
Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging'; Name = 'EnableScriptBlockLogging'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Scripting and command line')
Purpose = 'Logs every PowerShell script block AFTER de-obfuscation (event 4104). Obfuscated malware is logged decoded. Moderate-high volume.'
Risk = 'Moderate volume and small per-script overhead; generally safe fleet-wide. Large scripts fragment into 32 KB event blocks.' }
@{ Id = 'ScriptBlock32'
Path = 'HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging'; Name = 'EnableScriptBlockLogging'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Scripting and command line')
Purpose = 'Same as above for 32-bit PowerShell hosts (the path the Yamato batch sets).' }
# -- PowerShell module logging (event 4103) --
@{ Id = 'ModuleLogging64'
Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging'; Name = 'EnableModuleLogging'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Scripting and command line')
Purpose = 'Logs pipeline execution detail for PowerShell modules (event 4103), including command output. EXTREMELY high volume - a single Mimikatz run produces 2000+ events / ~7 MB.'
Risk = 'The heaviest setting in the kit. Adds measurable PowerShell execution overhead and huge log volume on script-heavy servers (Exchange management, SCCM, heavy automation). Many teams take script block logging and skip this one.' }
@{ Id = 'ModuleLogging32'
Path = 'HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell\ModuleLogging'; Name = 'EnableModuleLogging'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Scripting and command line')
Purpose = 'Same as above for 32-bit PowerShell hosts.' }
@{ Id = 'ModuleNames64'
Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging\ModuleNames'; Name = '*'; Kind = 'String'; Value = '*'
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Scripting and command line')
Purpose = 'Wildcard entry meaning "log all modules". Without this, module logging is enabled but logs nothing.' }
@{ Id = 'ModuleNames32'
Path = 'HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell\ModuleLogging\ModuleNames'; Name = '*'; Kind = 'String'; Value = '*'
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Scripting and command line')
Purpose = 'Same as above for 32-bit PowerShell hosts.' }
# -- PowerShell 7 (pwsh.exe) follows the Windows PowerShell policies above --
# PowerShell 7 reads its own policy keys (...\Policies\Microsoft\PowerShellCore)
# and ignores the Windows PowerShell ones. UseWindowsPowerShellPolicySetting = 1
# under its key makes it read the matching Windows PowerShell key instead
# (PowerShell source: Utils.GetPolicySettingFromGPOImpl), so one setting
# stays the source of truth for both engines (#44). Harmless when
# PowerShell 7 isn't installed. PowerShell 7 writes to
# PowerShellCore/Operational, which only exists once its event manifest is
# registered: the MSI installer offers to, Store and zip installs need
# $PSHOME\RegisterManifest.ps1 run once as admin (Test flags it).
@{ Id = 'PS7ScriptBlock64'
Path = 'HKLM:\SOFTWARE\Policies\Microsoft\PowerShellCore\ScriptBlockLogging'; Name = 'UseWindowsPowerShellPolicySetting'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Scripting and command line')
Purpose = 'Makes PowerShell 7 (pwsh.exe) follow the Windows PowerShell script block logging policy (ScriptBlock64), so pwsh sessions log 4104 too. Without it, running pwsh instead of powershell.exe avoids script block logging.'
Risk = 'Same volume profile as script block logging, for PowerShell 7 sessions. No effect unless PowerShell 7 is installed.' }
@{ Id = 'PS7ScriptBlock32'
Path = 'HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\PowerShellCore\ScriptBlockLogging'; Name = 'UseWindowsPowerShellPolicySetting'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Scripting and command line')
Purpose = 'Same as above for 32-bit PowerShell 7 (follows ScriptBlock32).' }
@{ Id = 'PS7ModuleLogging64'
Path = 'HKLM:\SOFTWARE\Policies\Microsoft\PowerShellCore\ModuleLogging'; Name = 'UseWindowsPowerShellPolicySetting'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Scripting and command line')
Purpose = 'Makes PowerShell 7 (pwsh.exe) follow the Windows PowerShell module logging policy, including its ModuleNames list (ModuleLogging64 + ModuleNames64), so pwsh sessions log 4103 too.'
Risk = 'The heaviest setting in the kit, now for PowerShell 7 sessions as well. Pair it with the Windows PowerShell module logging items or it has nothing to follow.' }
@{ Id = 'PS7ModuleLogging32'
Path = 'HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\PowerShellCore\ModuleLogging'; Name = 'UseWindowsPowerShellPolicySetting'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'HighVolume'; Categories = @('Scripting and command line')
Purpose = 'Same as above for 32-bit PowerShell 7 (follows ModuleLogging32 + ModuleNames32).' }
# PowerShell transcription is deliberately NOT in the kit (removed in
# #34): it writes text files outside the event log, so it needs its own
# folder, ACL, retention and collection path, and without an
# OutputDirectory it fills every user's Documents folder. Script block
# logging (4104) already records the code that ran, in the event log.
# -- NTLM auditing (populates Microsoft-Windows-NTLM/Operational) --
# DEVIATION: WELA configure sets RestrictSendingNTLMTraffic = 2, which is
# "Deny all" - that BLOCKS outgoing NTLM, an enforcement change, not a
# logging change, and can break connectivity. The kit sets 1 ("Audit all"),
# which logs the same traffic without blocking anything.
@{ Id = 'NtlmOutboundAudit'
Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0'; Name = 'RestrictSendingNTLMTraffic'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'Core'; Categories = @('Authentication')
Purpose = 'Audit all outgoing NTLM authentication (1 = audit, nothing blocked). Feeds the NTLM/Operational channel so NTLM retirement can be planned on evidence.' }
@{ Id = 'NtlmInboundAudit'
Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0'; Name = 'AuditReceivingNTLMTraffic'; Kind = 'DWord'; Value = 2
Scope = 'All'; Tier = 'Core'; Categories = @('Authentication')
Purpose = 'Audit incoming NTLM authentication for all accounts (2 = all accounts). Audit-only, nothing blocked.' }
# DEVIATION: WELA sets AuditNTLMInDomain = 2; Microsoft documents 7 as
# "enable auditing for all NTLM authentication in the domain". Only
# meaningful on domain controllers.
@{ Id = 'NtlmDomainAudit'
Path = 'HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters'; Name = 'AuditNTLMInDomain'; Kind = 'DWord'; Value = 7
Scope = 'DomainController'; Tier = 'Core'; Categories = @('Authentication')
Purpose = 'Audit all NTLM authentication passing through this domain controller (7 = all). Audit-only.' }
# Kit addition (#71): not in the Yamato sources. Windows' default is
# already on; setting it explicitly means Test catches a policy that
# turns it off, which would let legacy category-level audit policy
# override every subcategory setting above.
@{ Id = 'ForceSubcategoryAudit'
Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa'; Name = 'SCENoApplyLegacyAuditPolicy'; Kind = 'DWord'; Value = 1
Scope = 'All'; Tier = 'Core'; Categories = @('Logging tampered with')
Purpose = '"Audit: Force audit policy subcategory settings to override audit policy category settings". Stops a category-level (legacy) audit policy, from Group Policy or Local Security Policy, overriding the advanced subcategory settings this kit applies. On by default in Windows; set explicitly so a policy that turns it off is caught.' }
)
# -----------------------------------------------------------------------------
# 3b. SMB AUDITING (Windows 11 24H2 / Windows Server 2025 and later)
#
# Audit which peers cannot do SMB signing or encryption, so enforcement can
# be planned on evidence instead of breaking file shares, and when the SMB
# client logs on as Guest (insecure guest logons, #72). Event IDs as the
# SMBServer / SMBClient providers define them. Configured via Set-SmbServerConfiguration /
# Set-SmbClientConfiguration (documented by Microsoft in "What's new in
# Windows Server 2025"), not registry or auditpol, so these have their own
# item type. On older OSes the properties do not exist and the scripts report
# NOT APPLICABLE. Events land in the SMBServer/Audit and SmbClient/Audit
# channels sized above. Audit-only: nothing is blocked or enforced.
# -----------------------------------------------------------------------------
$script:BaselineSmbAuditSettings = @(
@{ Id = 'AuditClientDoesNotSupportEncryption'; Side = 'Server'; Value = $true; Tier = 'Core'; Scope = 'All'
Categories = @('Remote access','Network flow and sessions')
Purpose = 'SMB server logs clients that cannot do SMB encryption (event 3022 in SMBServer/Audit). Windows 11 24H2 / Server 2025 and later.' }
@{ Id = 'AuditClientDoesNotSupportSigning'; Side = 'Server'; Value = $true; Tier = 'Core'; Scope = 'All'
Categories = @('Remote access','Network flow and sessions')
Purpose = 'SMB server logs clients that cannot do SMB signing (event 3021 in SMBServer/Audit). Windows 11 24H2 / Server 2025 and later.' }
@{ Id = 'AuditServerDoesNotSupportEncryption'; Side = 'Client'; Value = $true; Tier = 'Core'; Scope = 'All'
Categories = @('Remote access','Network flow and sessions')
Purpose = 'SMB client logs servers that cannot do SMB encryption (event 31999 in SmbClient/Audit). Windows 11 24H2 / Server 2025 and later.' }
@{ Id = 'AuditServerDoesNotSupportSigning'; Side = 'Client'; Value = $true; Tier = 'Core'; Scope = 'All'
Categories = @('Remote access','Network flow and sessions')
Purpose = 'SMB client logs servers that cannot do SMB signing (event 31998 in SmbClient/Audit). Windows 11 24H2 / Server 2025 and later.' }
@{ Id = 'AuditInsecureGuestLogon'; Side = 'Client'; Value = $true; Tier = 'Core'; Scope = 'All'
Categories = @('Remote access','Authentication')
Purpose = 'SMB client logs when a share logs it on as the Guest account, an unauthenticated insecure guest logon (event 31997 in SmbClient/Audit). Windows 11 24H2 / Server 2025 and later.' }
# Same cmdlet setting on the server side, so it needs its own Id; Setting
# names the Set-SmbServerConfiguration parameter (defaults to Id).
@{ Id = 'ServerAuditInsecureGuestLogon'; Setting = 'AuditInsecureGuestLogon'; Side = 'Server'; Value = $true; Tier = 'Core'; Scope = 'All'
Categories = @('Remote access','Authentication')
Purpose = 'SMB server logs when a client is logged on as the Guest account, an unauthenticated insecure guest logon (event 3023, in SMBServer/Security or SMBServer/Operational depending on the build). Windows 11 24H2 / Server 2025 and later.' }
)
# -----------------------------------------------------------------------------
# 3c. WEF TRANSPORT DEFAULTS. The subscription-shaping values (ContentFormat,
# batching, heartbeat, SDDL) are consumed by New-WefSubscription.ps1 and
# overridable per run via its parameters; the refresh interval and the
# ForwardedEvents thresholds are guidance/verification values consumed by
# the setup output and Test-LoggingBaseline -WefRole (not parameters).
# -----------------------------------------------------------------------------
$script:BaselineWefDefaults = @{
# Events = binary, locale-independent, smaller on the wire (SIEM-friendly).
# RenderedText adds human-readable message text at higher transport cost.
ContentFormat = 'Events'
# Delivery batching: push a batch when either bound is hit. 30s keeps
# near-real-time visibility; raise for WAN-constrained sources.
MaxLatencySeconds = 30
MaxItems = 500
# Source heartbeat so silently-dead forwarders are noticeable on the
# collector. Low values add chatter fleet-wide.
HeartbeatSeconds = 3600
# Which computers may forward: Microsoft's documented default grants
# Domain Computers and Network Service.
AllowedSourceDomainComputersSddl = 'O:NSG:BAD:P(A;;GA;;;DC)(A;;GA;;;NS)S:'
# How often sources re-read the SubscriptionManager policy (seconds).
# Lower = faster pickup of subscription changes, more policy chatter.
SubscriptionRefreshSeconds = 60
# ForwardedEvents on the collector: verification floor and the size the
# kit recommends. A collector aggregates whole fleets; an undersized
# ForwardedEvents log wraps in minutes and loses forwarded evidence.
ForwardedEventsMinBytes = 134217728
ForwardedEventsRecommendedBytes = 1073741824
}
# -----------------------------------------------------------------------------
# 4. AD CS AUDIT FILTER (conditional - only when Certificate Services installed)
#
# Kept separate from plain registry settings because it needs a CertSvc
# service restart to take effect. The enable script sets the value and WARNS;
# it never restarts the service itself (WELA restarts it automatically - the
# kit deliberately does not).
# -----------------------------------------------------------------------------
$script:BaselineAdcsAuditFilter = @{
Id = 'AdcsAuditFilter'
# Actual path is HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA name>
# and is resolved at runtime from the 'Active' value on the Configuration key.
BasePath = 'HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration'
Name = 'AuditFilter'; Kind = 'DWord'; Value = 127
Scope = 'All'; Tier = 'Core'; Categories = @('Certificates and keys')
Purpose = 'Turns on all seven AD CS audit event groups (127 = full bitmask) so certificate issuance, template changes and CA configuration changes are logged (4886-4899). REQUIRES a CertSvc service restart to take effect.'
}
# -----------------------------------------------------------------------------
# 5. CATEGORY COVERAGE NOTES - honest statements about what native Windows
# logging can and cannot do per category. Rendered by the test script and
# duplicated in README.md.
# -----------------------------------------------------------------------------
$script:BaselineCategoryNotes = @{
'Authentication' = 'Fully covered natively (Security log + NTLM Operational channel).'
'Execution' = 'Covered by 4688 + command line (HighVolume tier). Without Sysmon there are no file hashes or DLL/image load events - accepted gap.'
'Account and access change' = 'Fully covered natively.'
'Privilege use' = 'Covered by Special Logon (Core) and Sensitive Privilege Use (HighVolume tier).'
'Logging tampered with' = 'Covered natively (4719, 1102, 104, 4612, service stop events).'
'Software and service install' = 'Covered natively (7045, 4697, MsiInstaller, CodeIntegrity, PrintService).'
'Remote access' = 'Covered natively (4624 type 3/10, 4778/4779, TS-LocalSessionManager, SmbClient).'
'Scheduled and automated tasks' = 'Fully covered natively (4698-4702 + TaskScheduler Operational).'
'Scripting and command line' = 'Covered by PowerShell logging + 4688 command line (HighVolume tier). Non-PowerShell interpreters (cmd, wscript, python) are visible only through 4688 command lines.'
'Persistence' = 'PARTIAL. Services, tasks, WMI and LSA extensions covered. Registry autorun (Run keys, IFEO) monitoring needs the Registry audit subcategory plus per-key SACLs - not in this baseline; native gap without endpoint tooling.'
'Removable and external devices' = 'Fully covered natively (Plug and Play, Removable Storage, DriverFrameworks-UserMode).'
'Blocked and denied activity' = 'Covered natively (Defender, AppLocker, CodeIntegrity, Security-Mitigations, firewall, failed logons). AppLocker channels only populate if an AppLocker policy is deployed.'
'Directory and identity store' = 'Covered on domain controllers (DS Access/Changes) and locally via SAM auditing. On a standalone server the DC items are NOT APPLICABLE by design.'
'File and object access' = 'PARTIAL. Share-level access covered (5140). Per-file auditing (4663) needs File System subcategory plus SACLs on chosen paths - a per-asset design decision, deliberately not set blanket-wide. Removable storage file access IS fully covered.'
'Certificates and keys' = 'Covered where AD CS is installed (Certification Services + AuditFilter). On hosts without AD CS, native visibility is limited to CNG events in Other Policy Change - accepted limitation.'
'Network flow and sessions' = 'PARTIAL. Best native option is Filtering Platform Connection 5156/5157 (HighVolume tier). Native logging has no byte counts or flow aggregation - true flow telemetry needs network-layer sources (firewall/NetFlow), outside host scope.'
}