## https://sploitus.com/exploit?id=4971BB29-0C64-537E-903F-63867E5442C7
# BuildReview2 - Attack-Path-Driven Windows Host Review
A rewrite of my `BuildReview-Windows` that pivots from compliance-style checks to
attack-path-driven findings. Each check is framed around what an operator can
*do* with the misconfiguration, mapped to MITRE ATT&CK, rated separately for
severity and exploitability, and exported in HTML, JSON, or Markdown.
## Why this rewrite
The original tool gave a pass/fail per registry setting. For a red team build
review that's the wrong unit of analysis as what matters is whether the host
(plus its place in the domain) yields a path to lateral movement, credential
theft, or escalation. This rewrite keeps the collection approach (PowerShell,
runs locally, minimal deps) and replaces the reporting shape.
## Architecture
```
BuildReview2/
Engine/
Invoke-BuildReview.ps1 # Entry point - Import this
New-Finding.ps1 # Uniform finding constructor
Test-Precondition.ps1 # Shared preconditions (elevated, domain-joined, role=DC, etc.)
Collectors/ # Grab raw state
Get-LSACredentialHygiene.ps1
Get-CoercionAndRelayPosture.ps1
Get-KerberosHygiene.ps1
Get-ADCSClientPosture.ps1
Get-ExecutionControlState.ps1
Get-DelegationState.ps1
Get-LAPSState.ps1
Get-NetworkServicesPosture.ps1
Get-PatchPosture.ps1
Get-LocalAccountAndGroupState.ps1
Get-ServicePermissions.ps1
Get-GPOAppliedState.ps1
Get-RDPPosture.ps1
Get-BitLockerState.ps1
Get-AutologonAndStoredCreds.ps1
Rules/ # Rule metadata and logic (one rule = one finding type)
*.psd1 # Machine-readable rule definitions
Reporting/
Export-HtmlReport.ps1
Export-JsonReport.ps1
Export-MarkdownReport.ps1
Export-CsvReport.ps1
Docs/
CheckCatalogue.md # This file's catalogue lives here too
USAGE.md # How to run this thing
```
## Finding schema
Every rule emits `[PSCustomObject]` with these fields:
| Field | Type | Notes |
|-------------------|----------|---------------------------------------------------------------|
| `CheckID` | string | Stable ID, e.g. `BR-KRB-001` |
| `Category` | string | `Kerberos`, `ADCS`, `Coercion`, `LSA`, etc. |
| `Title` | string | Human-readable one-liner |
| `Severity` | string | `Critical` \| `High` \| `Medium` \| `Low` \| `Info` |
| `Exploitability` | string | `High` \| `Medium` \| `Low` \| `Theoretical` \| `NotOnThisHost` |
| `AttackPath` | string | Short explanation, e.g. "Kerberoasting of RC4-only SPN" |
| `MITRE` | string[] | One or more technique IDs |
| `Evidence` | hashtable| Whatever proves the finding (reg values, file paths, output) |
| `Remediation` | string | Blue team action |
| `OperatorNotes` | string | Red team notes: tooling, preconditions, OPSEC cost |
| `References` | string[] | URLs - research blogs, CVEs, Microsoft docs |
| `Host` | string | `$env:COMPUTERNAME` |
| `Collected` | datetime | Collection timestamp |
The `OperatorNotes` field is the practical one as it's where you capture "what
do I actually run to leverage this?" and sometimes, "how loud is it?". That's the
information missing from my old CIS-style output.
## Severity vs exploitability
These are seperate. Examples:
| Condition | Severity | Exploitability |
|------------------------------------------------------|-----------|---------------------|
| WDigest `UseLogonCredential=1` on Server 2019 | High | High |
| RC4 enabled cluster-wide but no kerberoastable SPNs | High | Low on this host |
| WebClient service running + host not domain-joined | Medium | NotOnThisHost |
| PrintNightmare patch missing on non-DC workstation | High | Medium |
| KrbRelayUp preconditions present on a DC | Critical | High |
The report sorts by `Exploitability desc, Severity desc` by default, so the
things you can use first.
## Check catalogue (what to add)
Grouped by attack path. Each entry is a rule to implement. In my dated and existing
`BuildReview-Windows`, the checks are mostly re-used as collectors; the value add
is the rules layered on top.
### Credential access - LSA, DPAPI, caches
| ID | Check | MITRE |
|--------------|-------------------------------------------------------------------------|---------------|
| BR-LSA-001 | `UseLogonCredential` enables WDigest plaintext caching | T1003.001 |
| BR-LSA-002 | LSA not running as PPL (`RunAsPPL=0` or missing) | T1003.001 |
| BR-LSA-003 | Credential Guard not enabled on supported OS (`LsaCfgFlags`) | T1003.001 |
| BR-LSA-004 | `TokenLeakDetectDelaySecs` unset (allows MSV1_0 cred retention) | T1003.001 |
| BR-LSA-005 | `CachedLogonsCount` > 4 (offline cached domain logon hashes) | T1003.005 |
| BR-LSA-006 | `DisableDomainCreds=0` (credential theft from vault) | T1555.004 |
| BR-LSA-007 | `LimitBlankPasswordUse=0` on workstation | T1078.003 |
| BR-LSA-008 | Plaintext autologon creds in `Winlogon\DefaultPassword` | T1552.002 |
| BR-LSA-009 | Unattend/Sysprep files with creds on disk | T1552.001 |
| BR-LSA-010 | Saved creds in `cmdkey` / vault readable by current user | T1555.004 |
| BR-LSA-011 | DPAPI master keys present + user browsed to cred-storing apps (hint) | T1555.003 |
| BR-LSA-012 | RDP saved creds (`TERMSRV/*` entries in vault) | T1555.004 |
### Kerberos hygiene
| ID | Check | MITRE |
|--------------|-------------------------------------------------------------------------|---------------|
| BR-KRB-001 | RC4 in `SupportedEncryptionTypes` or `DefaultDomainSupportedEncTypes` | T1558.003 |
| BR-KRB-002 | Account SPNs present locally without AES keys (Kerberoast-friendly) | T1558.003 |
| BR-KRB-003 | `RC4DefaultDisablementPhase` unset on 2026+ DCs | T1558.003 |
| BR-KRB-004 | AS-REP roastable local users (`DONT_REQ_PREAUTH`) | T1558.004 |
| BR-KRB-005 | `msDS-MachineAccountQuota` writable by this machine's context (>0) | T1136.002 |
| BR-KRB-006 | Kerberos armouring (FAST) not enforced | T1558.003 |
| BR-KRB-007 | `StrongCertificateBindingEnforcement` ` entry.
2. Create `Rules/BR--.psd1` with metadata.
3. Add the rule logic inside the collector (or a separate analyser) that
reads `$global:BR2.Raw.` and calls `New-Finding` when the condition
is met.
## Notes on OPSEC and use
This is an authorised build review tool. It runs locally on the target host,
reads state, and will write temp files to disk. That's loud by design - registry reads, WMI
queries, and ADWS lookups are all visible to EDR in the usual ways.
If you want to run it during an active engagement (as opposed to an
authorised build review), you can try and use the collectors as
standalone. Feed them into your C2 via `execute-assembly`, `powerpick`, or a
`BOF`.