mirror of
https://github.com/Yamato-Security/WELA.git
synced 2026-10-13 09:45:30 +02:00
Create new disabled, unlinked GPOs from reviewed native audit backups (#427)
* Add guarded creation of disabled unlinked audit GPOs * Reference PR 427 in GPO creation changelogs * Accept only inert native ADM placeholders and fix PS5 JSON fixture * Preserve fractional UTC strings in existing probe fixtures
This commit is contained in:
1 parent
610d27e8ff
commit
f1ed90d189
15 files changed
+893
-46
No files matched your search
@@ -58,3 +58,5 @@ Only built-in advanced Security audit profiles and the precedence template are s
|
||||
The offline suite covers shared source/role/build selection, every mode/mask translation, exact-zero/default refusal, optional/role omissions, source fingerprint drift, CSV/template contents, tampering even with updated hashes, fresh-directory collisions, dry-run, filesystem guards and public CLI option boundaries. The Windows workflow targets Server 2022/2025 under PowerShell 5.1 and 7, verifies cross-edition package compatibility, calls native `secedit /validate` on the generated template and checks unchanged effective audit masks/precedence. It does not apply audit CSV or create a domain GPO.
|
||||
|
||||
Accepted file syntax and package round-trips do not establish domain import, exact-disable behavior, GPO propagation or event generation. Genuine backup preparation, create-unlinked/import/readback, client/member/DC/AD CS lab application and benign event/collector evidence remain pending. Issue #2 therefore retains deployment acceptance work beyond this package feature.
|
||||
|
||||
The separate opt-in [`gpo-create`](gpo-creation.md) command can create a new disabled, unlinked candidate from a reviewed genuine narrow backup and matching package. Package export does not invoke it; positive AD/SYSVOL deployment acceptance remains separate.
|
||||
@@ -0,0 +1,85 @@
|
||||
# Create a disabled, unlinked audit GPO
|
||||
|
||||
`gpo-create` validates a genuine, narrowly scoped GPMC backup against a current WELA `gpo-package`, then optionally creates one **new GPO with both policy sides disabled and no links**. It never overwrites an existing GPO, activates policy, links an OU/domain/site, changes delegation/filtering, refreshes clients, or deletes a failed candidate. Scope is built-in Windows advanced system audit policy plus DWORD `SCENoApplyLegacyAuditPolicy=1`; Sysmon and other WELA controls are excluded.
|
||||
|
||||
This command requires Windows PowerShell 5.1 or PowerShell 7 on Windows, installed GPMC/GroupPolicy management tools, an authenticated account authorized to create GPOs, and a host joined to the explicitly selected domain. Production code installs no tools. Only **single-domain forests** are supported: domain/OU and forest-site links can then be checked through one explicitly pinned writable DC. Workgroup hosts, RODCs, aliases, IP literals, mismatched domain GUIDs, unknown permissions and multi-domain forests are refused.
|
||||
|
||||
## Prepare genuine inputs
|
||||
|
||||
1. Use `gpo-package` to export and review the intended built-in source profile, role/build, omissions and exact masks. A package is not itself importable. One-sided minimum masks require explicit `PromoteToBoth`; unvalidated zero-mask deployment remains blocked.
|
||||
2. Follow [source preparation](gpo-package-deployment.md) on an isolated authorized domain. Create an unlinked source GPO and configure **only** the selected advanced audit GUIDs/masks and audit precedence. Leave all User settings empty. Do not add scripts, registry policy files, rights, security options, WMI filters or other extensions.
|
||||
3. Disable **both Computer and User settings on that source GPO before making its genuine Backup-GPO/GPMC backup**. Do not patch `Backup.xml`, strip unwanted files or fabricate a backup from WELA components. The source backup must already declare both sides disabled; import does not provide an assumption that enabled flags are preserved.
|
||||
4. Retain the complete genuine backup directory, backup-instance ID (distinct from the original GPO GUID), and WELA package on ordinary local fixed-drive paths. No UNC/device/stream/reparse input paths are accepted. Keep the inputs protected against concurrent editing.
|
||||
|
||||
The validator checks cached and native GPMC reports, actual `audit.csv` GUID/mask rows, the typed security template, backup core registrations, metadata and filesystem copy directives, and every selected-backup file/directory. Only the two audit/precedence payloads plus native metadata and known empty directories are supported. The exact absent legacy-ADM wildcard placeholder retained by genuine GPMC backups is allowed only without a Location/callback or any ADM files; Registry.pol and registry policy registration remain refused. Localized display labels do not control policy comparisons. Unknown data is refused rather than silently filtered. Broader SCT/LGPO backups normally fail this narrow validation; a genuine source GPO must be prepared separately.
|
||||
|
||||
## Review, plan and create
|
||||
|
||||
Save an explicit config, for example `C:\Review\gpo-create.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"SchemaVersion": 1,
|
||||
"PackagePath": "C:\\Review\\audit-components",
|
||||
"BackupRoot": "C:\\Review\\genuine-gpo-backups",
|
||||
"BackupId": "11111111-1111-1111-1111-111111111111",
|
||||
"Domain": "lab.example.test",
|
||||
"DomainGuid": "22222222-2222-2222-2222-222222222222",
|
||||
"Dc": "dc01.lab.example.test",
|
||||
"Name": "WELA Audit - reviewed candidate",
|
||||
"ReviewedSha256": ""
|
||||
}
|
||||
```
|
||||
|
||||
Use actual reviewed IDs. `DomainGuid` is the directory domain object's `objectGUID`, not its SID or a source backup ID. Paths may be absolute or relative to this config. Fields are strictly checked; unknown/duplicate JSON properties are rejected. `Name` must be a new plain 2–128 character name and cannot be a default policy name.
|
||||
|
||||
```powershell
|
||||
# Native backup/package review only; no domain connection or output writes.
|
||||
.\WELA.ps1 gpo-create -GpoCreateConfigPath C:\Review\gpo-create.json
|
||||
```
|
||||
|
||||
Review the returned profile and source/backup identity. Copy the resulting lowercase `ReviewedSha256` into that config. The fingerprint includes every selected backup file, directory, current WELA package file and existing native backup-root manifest. It is an integrity/review binding, not proof of a trusted publisher or valid AD deployment.
|
||||
|
||||
```powershell
|
||||
# Adds actual domain/DC identity and unique-name checks; remains read-only.
|
||||
.\WELA.ps1 gpo-create -GpoCreateAction Plan -GpoCreateConfigPath C:\Review\gpo-create.json
|
||||
|
||||
# No output or GPO creation; still performs real prerequisite reads.
|
||||
.\WELA.ps1 gpo-create -GpoCreateAction Create -GpoCreateConfigPath C:\Review\gpo-create.json `
|
||||
-BackupPath C:\Review\candidate-receipts -DryRun
|
||||
|
||||
# Prompts before creating the new candidate. -Auto supplies unattended consent.
|
||||
.\WELA.ps1 gpo-create -GpoCreateAction Create -GpoCreateConfigPath C:\Review\gpo-create.json `
|
||||
-BackupPath C:\Review\candidate-receipts
|
||||
```
|
||||
|
||||
`BackupPath` must be a fresh directory with an existing local parent. The directory receives an owner/SYSTEM/Administrators ACL. WELA writes a reviewed plan and creation-intent receipt, holds reviewed input files against write/delete, and copies the genuine backup **unchanged** into this protected directory. It revalidates those copied bytes; no fake native metadata is generated. The protected copy is the native import source.
|
||||
|
||||
The shared configuration runner provides dry-run, consent, before-state journal and final verification. WELA calls `New-GPO` without a starter GPO and records the returned GUID immediately using a new, flushed receipt. It then checks that the exact new object is empty and unlinked, disables both sides, captures a full blank-target receipt, and freshly repeats identity/content/link/permission/version checks before native GPMC import. Both the COM operation and its `GPMResult.OverallStatus()` must succeed. Import targets only the returned GUID and uses no migration table. The readback compares native report and actual pinned-DC SYSVOL payloads, disabled flags, domain/site links, owner/group/DACL report, object identity, and coherent AD/SYSVOL versions. Final readback must still match.
|
||||
|
||||
Native creation initially returns an **empty, unlinked** GPO; disabling happens immediately after its durable identity receipt and empty-object checks. If that receipt cannot be persisted, import and further changes are refused. The precreation marker/name receipt and returned GUID identify this empty residual object. WELA never claims a failed run left a verified disabled candidate.
|
||||
|
||||
## Evidence and recovery
|
||||
|
||||
A successful result is `DisabledUnlinkedCandidateVerified` on the pinned DC at that time. `DeploymentVerified` remains false and Sigma EVTX credit remains zero. The package's declared role/build is not a generated WMI/security filter and does not constrain future linking. Security filtering/delegation stays at the new GPO's native defaults; review it separately before any later enabling or linking.
|
||||
|
||||
Retain `reviewed-plan.json`, `creation-intent.json`, `created-gpo.json`, `blank-target.json`, `import-intent.json`, `before.jsonl`, `result.json`, and the copied genuine backup. Failure stops the workflow and preserves available receipts; it does not retry into an existing GPO or automatically delete/restore anything. If native creation succeeded but returned no identity or saving the receipt failed, search the exact selected DC/name and unique comment marker from `creation-intent.json`. Inspect the object and all current links before any separately authorized cleanup. Existing evidence paths are never reused.
|
||||
|
||||
These checks are **not a transaction or compare-and-swap lock across AD and SYSVOL**. Another authorized administrator can race between creation, name/flags/link checks, native import and readback. A fresh/final mismatch is a failed candidate, not automatic rollback authority. Coordinated change control and subsequent replication checks remain necessary. Readback establishes neither replication to other DCs nor client policy processing, precedence after refresh, persistence, event generation, forwarding or detection success.
|
||||
|
||||
## Validation boundary
|
||||
|
||||
Safe fixtures exercise the public orchestration with native domain adapters mocked: source/payload drift, unrelated policies, duplicate names, domain changes, blank-target changes, receipt failures, import failures, permissions/content/link mismatches, final drift, dry-run and decline. Public CLI tests check option dispatch and negative exit behavior.
|
||||
|
||||
Windows Server 2022/2025 CI exercises real GPMC backup/report/OverallStatus using Microsoft's unchanged **Windows Server 2022 Security Baseline** archive from the [Security Compliance Toolkit](https://www.microsoft.com/en-us/download/details.aspx?id=55319), pinned to SHA-256 `49590cc694626d171fc934fafea6494f13ecd3843086704b7a5b98355909b8e0`. Its broad policy is deliberately refused. Actual workgroup-host refusal and unchanged native local audit/precedence state are checked in PowerShell 5.1 and 7. The test can explicitly install GPMC only on disposable GitHub-hosted runners; it creates no domain and performs no domain policy writes.
|
||||
|
||||
**Positive creation/import from a genuine narrow backup into AD/SYSVOL remains pending isolated-domain acceptance.** Required follow-up: collect the real source backup and typed native results, confirm both sides disabled and no domain/OU/site links before/after import, review permissions and versions, test failure/recovery with concurrent administrators, then separately stage representative Windows 11, member server, DC and AD CS client-policy/event/arrival checks. Hosted workgroup evidence is not a substitute for these steps. Issue #2 remains related work until acceptance is complete.
|
||||
|
||||
## Microsoft sources
|
||||
|
||||
- [New-GPO: creates an unlinked GPO and rejects duplicate names](https://learn.microsoft.com/en-us/powershell/module/grouppolicy/new-gpo?view=windowsserver2025-ps)
|
||||
- [Native backup handling and archive preservation](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-policy/group-policy-backup-restore)
|
||||
- [GPMC GetDomain: explicit DC with flags 0](https://learn.microsoft.com/en-us/windows/win32/api/gpmgmt/nf-gpmgmt-igpm-getdomain)
|
||||
- [GPMBackup report generation](https://learn.microsoft.com/en-us/windows/win32/api/gpmgmt/nf-gpmgmt-igpmbackup-generatereport)
|
||||
- [Native GPO import: settings replacement and destination ACL/link preservation](https://learn.microsoft.com/en-us/windows/win32/api/gpmgmt/nf-gpmgmt-igpmgpo-import)
|
||||
- [OverallStatus must be checked as well as the native operation](https://learn.microsoft.com/en-us/windows/win32/api/gpmgmt/nf-gpmgmt-igpmresult-overallstatus)
|
||||
@@ -7,7 +7,7 @@ This WELA folder contains **deployment components, not a GPO backup**. Do not pa
|
||||
1. Verify the component package with the same reviewed WELA version. Read `review.md`, including every omitted/expanded row and object/service prerequisites. Confirm the intended target role, build, scope and source version; these are declared package inputs, not observations of a domain's computers.
|
||||
2. On a disposable, snapshotted lab, use GPMC to create a **new unlinked source GPO**. Leave existing GPOs, default domain policies and links untouched. In the Group Policy Management Editor, enter only the exported rows under Computer Configuration > Policies > Windows Settings > Security Settings > Advanced Audit Policy Configuration. `ExportMask` 1 is Success, 2 is Failure, 3 is Success and Failure. Leave omitted rows Not Configured in this new GPO; do not interpret omission as disabling auditing.
|
||||
3. In the same GPO, enable Security Options > **Audit: Force audit policy subcategory settings (Windows Vista or later) to override audit policy category settings**. The companion `GptTmpl.inf` shows the exact DWORD requirement. Do not add legacy category audit policy, audit failure options, privileges, SACLs or unrelated registry settings.
|
||||
4. Review GPMC's Settings report against the package. Require an exact match for the selected audit GUIDs/masks and precedence=1, with no unexpected Computer or User policy settings. Confirm no links or WMI filter. Review the GPO's security filtering/delegation independently. Back up this source GPO through GPMC or `Backup-GPO` into a fresh protected directory, retaining its **backup-instance ID**, source GPO ID, report and hashes.
|
||||
4. Disable both Computer and User settings on the source GPO before backing it up. Review GPMC's Settings report against the package. Require an exact match for the selected audit GUIDs/masks and precedence=1, with no unexpected Computer or User policy settings. Confirm no links or WMI filter. Review the GPO's security filtering/delegation independently. Back up this source GPO through GPMC or `Backup-GPO` into a fresh protected directory, retaining its **backup-instance ID**, source GPO ID, report and hashes.
|
||||
|
||||
This manual source-GPO preparation is the supported path for a narrow, genuine domain backup. Microsoft documents creating an [unlinked GPO](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-policy/group-policy-management-console) and generating backups through [Backup-GPO](https://learn.microsoft.com/en-us/powershell/module/grouppolicy/backup-gpo?view=windowsserver2025-ps).
|
||||
|
||||
@@ -19,49 +19,11 @@ Obtain Microsoft's signed LGPO utility and its documentation from the [Security
|
||||
|
||||
LGPO `/b` backs up local policy, including security settings, current advanced audit state, registry policy and configured extensions. **Its output can include settings absent from this package**, even on a lab machine. Review the complete backup in GPMC. If it contains extras, edit a newly created isolated source GPO through GPMC and make a new genuine backup; do not remove files or patch XML inside the archive. A generic local-policy backup is not automatically a narrow WELA audit-only backup. Microsoft explains the difference between [AuditPol state and local policy](https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/auditpol-local-security-policy-results-differ).
|
||||
|
||||
## Reviewed create-new-unlinked procedure
|
||||
## Reviewed create-new-disabled-unlinked command
|
||||
|
||||
The following is an **operator procedure for an already prepared, genuine, fully reviewed backup**. It is not generated executable content and WELA does not run it. Review its backup by instance ID through GPMC's Manage Backups/Settings report (or the native `GPMBackupDir.GetBackup` and `GPMBackup.GenerateReport` APIs). A CSV folder is insufficient. Require only the intended computer audit settings and precedence, with no unknown extensions, scripts, preferences, per-user audit entries or unrelated settings.
|
||||
WELA now provides the separate opt-in [`gpo-create` command](gpo-creation.md) for an already prepared genuine narrow backup. Its Review action compares native GPMC reports and actual policy files against a current WELA package. Plan and Create require the reviewed fingerprint, explicit domain GUID/FQDN, exact writable DC, and a unique new name. Both source-backup sides must already be disabled. Creation records the new GUID, disables the empty candidate, rechecks its unlinked/empty state, and imports only into that GUID with protected receipts and final readback. It never links, enables, overwrites or deletes a GPO.
|
||||
|
||||
Use explicit domain and DC parameters for every operation. Check connectivity/authority before creation and do not treat an access error as an absent GPO. Choose a fresh unique name. For example, in an authorized lab using Windows PowerShell and the GroupPolicy module:
|
||||
|
||||
```powershell
|
||||
# Replace these with the explicitly reviewed lab domain, DC, genuine backup and name.
|
||||
$targetDomain = 'lab.example.test'
|
||||
$targetDc = 'dc01.lab.example.test'
|
||||
$genuineBackupRoot = 'C:\ReviewedGpoBackups'
|
||||
$reviewedBackupId = [guid]'11111111-1111-1111-1111-111111111111'
|
||||
$newName = 'WELA Audit - reviewed lab candidate'
|
||||
$receiptPath = 'C:\Review\new-gpo-receipt.json' # Must not already exist.
|
||||
|
||||
if (Test-Path -LiteralPath $receiptPath) { throw 'Use a fresh receipt path.' }
|
||||
$existing = @(Get-GPO -All -Domain $targetDomain -Server $targetDc -ErrorAction Stop |
|
||||
Where-Object DisplayName -eq $newName)
|
||||
if ($existing.Count) { throw 'The target name already exists; stop without importing.' }
|
||||
|
||||
# Do not specify a Starter GPO or pipe to New-GPLink.
|
||||
$created = New-GPO -Name $newName -Domain $targetDomain -Server $targetDc -ErrorAction Stop
|
||||
[pscustomobject]@{
|
||||
Domain = $targetDomain; Server = $targetDc; GpoGuid = $created.Id
|
||||
Name = $created.DisplayName; BackupId = $reviewedBackupId
|
||||
State = 'Created; import and verification pending'
|
||||
} | ConvertTo-Json | Out-File -LiteralPath $receiptPath -Encoding UTF8 -NoClobber -ErrorAction Stop
|
||||
|
||||
# Recheck that this exact new GPO is empty and unlinked before importing.
|
||||
Get-GPOReport -Guid $created.Id -Domain $targetDomain -Server $targetDc -ReportType Xml
|
||||
```
|
||||
|
||||
Stop and review the returned GUID, persisted receipt and actual report. Only after confirming that the exact new GPO remains empty and unlinked, execute this separate import step in the same reviewed session:
|
||||
|
||||
```powershell
|
||||
Import-GPO -BackupId $reviewedBackupId -Path $genuineBackupRoot `
|
||||
-TargetGuid $created.Id -Domain $targetDomain -Server $targetDc -ErrorAction Stop
|
||||
Get-GPOReport -Guid $created.Id -Domain $targetDomain -Server $targetDc -ReportType Xml
|
||||
```
|
||||
|
||||
`New-GPO` creates an unlinked object and refuses a duplicate name. `Import-GPO` imports into the returned **new GUID**, without `-CreateIfNeeded`, name-based targeting or `Restore-GPO`. Importing settings preserves the destination's existing security filtering and links; it does not supply an approved scope of application. Review the actual result, including exact settings and continued absence of links, before considering any later link. Do not assume the backup's security filtering or role metadata protects the new GPO. [New-GPO](https://learn.microsoft.com/en-us/powershell/module/grouppolicy/new-gpo?view=windowsserver2025-ps), [Import-GPO](https://learn.microsoft.com/en-us/powershell/module/grouppolicy/import-gpo?view=windowsserver2025-ps).
|
||||
|
||||
If receipt persistence, import or readback fails, stop and retain the created GUID and evidence for manual review. Do not retry against an arbitrary existing GPO or automatically delete an object that another administrator may have changed or linked. This procedure is not a transaction or a lock against concurrent administrators; check the same DC immediately before each operation. Inspect both AD/SYSVOL versions and replication before proceeding beyond the unlinked candidate.
|
||||
Read that command's single-domain-forest restriction, native prerequisites, failure recovery and concurrency limits before use. The package commands remain offline and never invoke it implicitly. Successful candidate creation is separate from AD/SYSVOL replication and policy application.
|
||||
|
||||
## Deployment acceptance and recovery
|
||||
|
||||
@@ -71,4 +33,4 @@ Record the genuine backup, target GUID, actual GPMC settings, RSoP/GPO source ev
|
||||
|
||||
Rollback must be designed before linking. Preserve existing production GPOs and links throughout preparation. If testing fails, the policy owner should inspect and selectively reverse only the test changes, considering current links, authoritative settings and replication. Unlinking or deleting a GPO is not proof that all effective settings reverted. Retain evidence rather than blindly restoring an old whole-host policy snapshot. No audit-exhaustion test is required or provided.
|
||||
|
||||
WELA's automated tests validate package contents and unchanged host settings only. Genuine GPO creation/import, absence of unintended policy settings, AD/SYSVOL replication, client/DC/AD CS application and event/collection evidence remain pending lab acceptance for issue #2. Other WELA controls and Sysmon are outside this package.
|
||||
WELA's package tests validate component contents and unchanged host settings. The separate creation tests also read a genuine Microsoft backup through native GPMC and verify broad-payload/workgroup refusals, while positive creation orchestration uses mocks. Genuine GPO creation/import, absence of unintended policy settings, AD/SYSVOL replication, client/DC/AD CS application and event/collection evidence remain pending lab acceptance for issue #2. Other WELA controls and Sysmon are outside this package.
|
||||
Reference in new issue
Block a user