diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..0e2a353 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,125 @@ +# Elysium — Agent Context + +> This file is written for AI coding agents. The project language is English; all code comments, documentation, and settings are in English. + +## Project Overview + +Elysium is a Windows-focused Active Directory weak-password assessment toolkit. It is implemented entirely in PowerShell (with one Python decryption helper) and is designed to be run from a dedicated, trusted Windows host by an operator with replication-equivalent rights on the target AD domain. + +The tool performs three core workflows: + +1. **Update Known-Hashes Database (KHDB)** — Download an incremental, sharded hash database from remote storage (Azure Blob or S3-compatible). +2. **Test Weak AD Passwords** — Use DSInternals to replicate account data and test passwords against the local KHDB, producing timestamped text reports. +3. **Extract and Send Current Hashes** — Pull NTLM hashes (without usernames) from live AD, compress, encrypt, and upload them back to the tool provider to improve the KHDB. This step is optional. +4. **Update Lithnet Password Protection Store** — Populate a local Lithnet Password Protection store with compromised hashes, plaintext passwords, and banned words. + +## Technology Stack + +- **Runtime:** Windows PowerShell 5.1 or PowerShell 7 (`pwsh`). +- **Required PowerShell modules:** `DSInternals`, `ActiveDirectory` (RSAT). +- **Optional PowerShell modules:** `Az.Storage`, `AWS.Tools.S3` / `AWSPowerShell.NetCore`, `LithnetPasswordProtection`. +- **Python 3:** `decrypt.py` requires `pycryptodome` for decrypting uploaded payload files. +- **Network:** TLS 1.2+ enforced; native S3 SigV4 signing implemented in pure PowerShell/.NET (no AWS Tools required). + +## Project Structure + +``` +Elysium.ps1 # Main menu / orchestrator script +Elysium.Common.ps1 # Shared helpers: pwsh relauncher, Windows PS fallback +ElysiumSettings.txt # Live configuration (key=value format, # comments) +ElysiumSettings.txt.sample # Documented template for operators + +Update-KHDB.ps1 # KHDB downloader: manifest + shard incremental update +Prepare-KHDBStorage.ps1 # KHDB publisher: split source into shards, build manifest, upload +Test-WeakADPasswords.ps1 # AD password-quality test with DSInternals +Extract-NTHashes.ps1 # Hash extraction, compression, encryption, upload +Update-LithnetStore.ps1 # Lithnet Password Protection store importer +Uninstall.ps1 # Self-removal script +decrypt.py # Python 3 decryptor for .enc payloads + +Settings.ps1 # Legacy settings file (superseded by ElysiumSettings.txt) +khdb.txt # Local merged KHDB file (generated by Update-KHDB.ps1) +Reports/ # Generated reports and transcript logs +``` + +## Configuration Format + +`ElysiumSettings.txt` uses a simple `Key=value` format. Lines starting with `#` are comments. Values are **not** quoted by default; if quotes are used they are stripped by some parsers. + +Key sections: + +- `StorageProvider` — `Azure` or `S3` +- Azure: `storageAccountName`, `containerName`, `sasToken` +- S3: `s3EndpointUrl`, `s3Region`, `s3BucketName`, `s3AccessKeyId`, `s3SecretAccessKey`, `s3ForcePathStyle`, `s3UseAwsTools` +- KHDB layout: `KhdbManifestPath`, `KhdbShardPrefix`, `KhdbLocalShardDir` +- App: `InstallationPath`, `ReportPathBase`, `WeakPasswordsDatabase`, `CheckOnlyEnabledUsers` +- Lithnet: `LithnetStorePath`, `LithnetSyncHibp`, `LithnetHashSources`, `LithnetPlaintextSources`, `LithnetBannedWordSources` +- Telemetry (optional): `UsageBeaconUrl`, `UsageBeaconMethod`, `UsageBeaconInstanceId`, `UsageBeaconTimeoutSeconds` +- Domains: `Domain1Name`, `Domain1DC`, `Domain2Name`, `Domain2DC`, ... + +## PowerShell Edition Handling + +This project has nuanced PowerShell edition rules that must be preserved: + +- **Scripts that benefit from parallelism** (`Update-KHDB.ps1`, `Prepare-KHDBStorage.ps1`, `Update-LithnetStore.ps1`, `Uninstall.ps1`) auto-relaunch under `pwsh` (PowerShell 7+) via `Restart-WithPwshIfAvailable` in `Elysium.Common.ps1`. +- **Scripts that require legacy modules** (`Test-WeakADPasswords.ps1`, `Extract-NTHashes.ps1`) auto-relaunch under `Windows PowerShell` (`powershell.exe`) via `Restart-WithWindowsPowerShellIfAvailable`, because `DSInternals` and `ActiveDirectory` often need the Desktop edition. +- `Elysium.ps1` (the menu) checks `$PSVersionTable.PSEdition` and invokes the appropriate child process for options 2 and 3. + +When modifying any script, keep the `. $commonHelper` import and the corresponding `Restart-With*IfAvailable` call at the top. + +## Code Style Guidelines + +- Strict mode and error handling are mandatory at the top of every script: + ```powershell + $ErrorActionPreference = 'Stop' + Set-StrictMode -Version Latest + ``` +- Every operational script starts a **transcript** into `Reports/logs/` (or `%TEMP%` for uninstall) and stops it in a `finally` block. +- Functions use `Verb-Noun` naming. Private helpers are also `Verb-Noun`. +- Settings parsing is done manually via `Get-Content` and string splitting on `=`, not `ConvertFrom-StringData`. +- Paths are resolved relative to `$PSScriptRoot` whenever possible. +- Large file operations use `StreamReader` / `StreamWriter` with explicit `UTF8Encoding($false)` (no BOM) and large buffers (1 MiB preferred). +- S3-native functions (SigV4) are duplicated in scripts that need them because they run in parallel `ForEach-Object -Parallel` scopes where module imports are not preserved. + +## Build / Run Commands + +There is no package manager or build system. The tool is run directly: + +```powershell +# Main menu +.\Elysium.ps1 + +# Direct invocation (respects auto-relaunch behavior) +.\Update-KHDB.ps1 +.\Update-KHDB.ps1 -MaxParallelTransfers 8 +.\Test-WeakADPasswords.ps1 +.\Extract-NTHashes.ps1 +.\Update-LithnetStore.ps1 +.\Prepare-KHDBStorage.ps1 -SourcePath .\khdb.txt -OutputRoot .\publish -StorageProvider S3 -SkipUpload +.\Uninstall.ps1 +``` + +No tests or CI pipelines exist in this repository. + +## Testing & Validation + +- **KHDB validation:** `Validate-KHDBFile` in `Update-KHDB.ps1` checks 32-hex format, sorting, and duplicates. +- **DSInternals compatibility:** `Resolve-DSInternalsWeakHashFile` in `Test-WeakADPasswords.ps1` normalizes legacy `HASH:count` lines into a temporary hash-only file. +- **Upload integrity:** After every upload, the script downloads the blob back and compares SHA256 checksums before deleting local artifacts. +- **Credential pre-check:** `Test-WeakADPasswords.ps1` validates credentials against the chosen DC with `Get-ADDomain` and checks the three replication extended rights before attempting DCSync. + +## Security Considerations + +- The operator passphrase is stored in the **user-level** environment variable `ELYSIUM_PASSPHRASE`. Do not log or serialize it. +- `Test-WeakADPasswords.ps1` refuses to run when Windows FIPS policy is enabled (`HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\FipsAlgorithmPolicy\Enabled = 1`) because DSInternals operations may fail or be limited. +- The extract-and-send workflow uploads **hashes only** (no usernames). Encryption uses PBKDF2 (SHA-256, 100k iterations, random 16-byte salt) + AES-256-CBC with a 4-byte magic header `ELY1`. +- S3 requests are signed with native SigV4 via `System.Net.Http.HttpClient` so no AWS credentials file or third-party module is required. If AWS Tools are used (`s3UseAwsTools = true`), the native path is still available as a fallback. +- Reports contain sensitive AD data. They are written to `Reports/` under the script root by default. +- All network operations enforce TLS 1.2+ (`[System.Net.ServicePointManager]::SecurityProtocol`). + +## Notes for Agents + +- Do **not** introduce new package-manager files (e.g., `package.json`, `pyproject.toml`, `Cargo.toml`). This project is intentionally dependency-light and script-driven. +- When adding new settings, keep the `key=value` flat format and update both `ElysiumSettings.txt.sample` and any parser that reads the file. +- If you add a new operational script, include the standard banner, strict mode, transcript logging, and the `Elysium.Common.ps1` relauncher pattern. +- The `.gitignore` excludes `khdb.txt`, `ElysiumSettings.txt`, `Reports/`, `khdb-shards/`, and `khdb-manifest.json`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 64b7cf3..50c755c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,72 +1,84 @@ # Changelog -## 2026-03-16 +All notable changes to the Elysium project are documented in this file. -### Test-WeakADPasswords.ps1 v1.4.5 +Starting with **v2.2.0**, Elysium uses a **unified project version**. All scripts, settings templates, and documentation share the same version number so operators can verify consistency at a glance. Releases prior to v2.2.0 used per-script versioning; those entries are preserved below under their original dates. + +--- + +## [2.2.0] — 2026-06-09 + +### Changed +- **Unified versioning:** All PowerShell scripts, the settings template, and documentation now share a single project version (`2.2.0`). This replaces the previous per-script versioning model. + +### Test-WeakADPasswords.ps1 +- Added `Test-ReplicationPermissions` helper that validates the three required AD replication extended rights (`Replicating Directory Changes`, `Replicating Directory Changes All`, `Replicating Directory Changes In Filtered Set`) against the domain object's DACL before attempting DCSync. Missing permissions now produce a clear, fail-fast error instead of an opaque `Access is denied` later in the workflow. + +--- + +## Historical Releases (per-script versioning) + +### 2026-03-16 + +#### Test-WeakADPasswords.ps1 v1.4.5 Fixed: - Normalizes legacy `HASH:count` KHDB files into a temporary hash-only list before calling `DSInternals`, so dictionary matches no longer fail silently when clients have older database content. - Warns when KHDB normalization is required instead of leaving the weak-password match section empty without explanation. -### Update-KHDB.ps1 v2.1.1 +#### Update-KHDB.ps1 v2.1.1 Fixed: - Rebuilds the merged local `khdb.txt` as a DSInternals-compatible hash-only file even when upstream shards still contain legacy `HASH:count` lines. - Tightened KHDB merge validation so malformed shard content is surfaced during update rather than producing a silently unusable weak-password database. -### Prepare-KHDBStorage.ps1 v1.1.1 +#### Prepare-KHDBStorage.ps1 v1.1.1 Fixed: - Accepts legacy `HASH:count` source input but writes deduplicated hash-only shards for downstream DSInternals consumers. -### README.md +#### README.md Changed: - Corrected the KHDB format documentation to require one NT hash per line and documented the automatic legacy-format normalization. -## 2026-02-17 +### 2026-02-17 -### Test-WeakADPasswords.ps1 v1.4.4 +#### Test-WeakADPasswords.ps1 v1.4.4 Changed: - Added startup FIPS policy detection (`HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\FipsAlgorithmPolicy\Enabled`) with fail-fast behavior and explicit remediation steps to avoid opaque DSInternals runtime failures. -## 2026-02-17 - -### Test-WeakADPasswords.ps1 v1.4.3 +#### Test-WeakADPasswords.ps1 v1.4.3 Fixed: - Added explicit handling for `Microsoft.PowerShell.Commands.WriteErrorException,DSInternals.Bootstrap.psm1` so known FIPS bootstrap errors are downgraded to a controlled warning when possible, with a clear fail message if DSInternals cannot load under policy. -## 2026-02-17 - -### Test-WeakADPasswords.ps1 v1.4.2 +#### Test-WeakADPasswords.ps1 v1.4.2 Fixed: - DSInternals module import now handles the known FIPS bootstrap warning as non-fatal when the module successfully loads, preventing repeated `SecurityError` noise during startup. -## 2026-02-17 - -### Test-WeakADPasswords.ps1 v1.4.1 +#### Test-WeakADPasswords.ps1 v1.4.1 Changed: - Added credential pre-validation against the selected domain controller before running `Get-ADReplAccount`, including retry prompts for rejected credentials. - Improved error diagnostics to distinguish invalid credentials from missing replication permissions (`Access is denied`). - Added optional `-Credential` parameter to `Test-WeakADPasswords` for callers that need to provide credentials non-interactively. -### README.md +#### README.md Changed: - Updated weak-password testing documentation to reflect credential pre-check behavior and added a short troubleshooting section for common authentication/permissions failures. -## 2025-10-30 +### 2025-10-30 -### Update-KHDB.ps1 v2.0.0 +#### Update-KHDB.ps1 v2.0.0 Changed: - Replaced single-archive workflow with manifest-driven, two-hex shard downloads that verify SHA256/size before in-place updates. - Added incremental refresh logic, stale shard cleanup, and automatic rebuild of the merged `khdb.txt` for downstream scripts. - Hardened validation to stream-check merged output while preserving strict TLS, retry, and transcript behaviour. -### ElysiumSettings.txt.sample v1.3.0 +#### ElysiumSettings.txt.sample v1.3.0 Added: - Documented `KhdbManifestPath`, `KhdbShardPrefix`, and `KhdbLocalShardDir` defaults for the shard-aware updater. -### README.md +#### README.md Changed: - Described the manifest/shard update flow so operators understand the incremental download model and automatic cleanup. -### Prepare-KHDBStorage.ps1 v1.0.0 +#### Prepare-KHDBStorage.ps1 v1.0.0 Added: - Helper script to split `khdb.txt` (or a directory/list of `.gz` HIBP slices) into two-hex shards, build the JSON manifest, and push the package to Azure Blob Storage or S3-compatible endpoints. - Validation step that tallies and quarantines malformed hashes before sharding, writing `invalid-hashes.txt` plus a console summary so bad data never reaches storage. @@ -76,63 +88,63 @@ Added: - Emits a merged `khdb-clean.txt` alongside the shards for DSInternals or offline review, including SHA256 fingerprints for both manifest and clean output. - Automatic checkpoint/resume when `-ForcePlainText` is used (configurable via `-CheckpointPath`, disable with `-NoCheckpoint`) so large ingests can be paused and resumed without reprocessing prior shards. -## 2025-10-26 +### 2025-10-26 -### Test-WeakADPasswords.ps1 v1.3.3 +#### Test-WeakADPasswords.ps1 v1.3.3 Added: - Opt-in usage beacon that fires a single HTTP request (GET/POST/PUT) after settings load, suitable for pre-signed S3 URLs, and only includes script name, version, and a UTC timestamp (plus optional instance ID). - Instance identifier header/body support and configurable timeout so adopters can differentiate deployments without collecting user data. -### ElysiumSettings.txt.sample v1.2.0 +#### ElysiumSettings.txt.sample v1.2.0 Added: - Documented `UsageBeacon*` keys (URL, method, instance ID, timeout) so telemetry stays disabled by default but easy to enable. -### README.md +#### README.md Added: - Usage beacon section explaining how to configure the lightweight tracking call and what metadata is transmitted. -## 2025-10-21 +### 2025-10-21 -### Extract-NTHashes.ps1 v1.2.1 +#### Extract-NTHashes.ps1 v1.2.1 Fixed: - Corrected SigV4 host header formatting so non-default ports serialize without parser errors. - Hardened hashing helpers to avoid `ComputeHash` overload ambiguity under Windows PowerShell. - Domain selection menu now respects the configured numeric order. -### Test-WeakADPasswords.ps1 v1.3.2 +#### Test-WeakADPasswords.ps1 v1.3.2 Changed: - Switched to the sorted KHDB path when driving `Test-PasswordQuality`, eliminating full linear scans and avoiding malformed-line crashes on massive datasets. -### Test-WeakADPasswords.ps1 v1.3.1 +#### Test-WeakADPasswords.ps1 v1.3.1 Fixed: - Domain picker now renders in numeric order from settings for predictable operator workflows. - UPN export now relies on structured weak-password results, so dictionary hit UPN lists are populated reliably. -## 2025-10-10 +### 2025-10-10 -### Test-WeakADPasswords.ps1 v1.3.0 +#### Test-WeakADPasswords.ps1 v1.3.0 Added: - `CheckOnlyEnabledUsers` flag wired from settings to filter accounts prior to `Test-PasswordQuality`. - Transcript logging to `Reports/logs/test-weakad-.log`. -### Extract-NTHashes.ps1 v1.2.0 +#### Extract-NTHashes.ps1 v1.2.0 Added: - Transcript logging to `Reports/logs/extract-hashes-.log`. -### Elysium.ps1 v1.1.0 +#### Elysium.ps1 v1.1.0 Updated: - Added strict error handling (`$ErrorActionPreference='Stop'`) and `Set-StrictMode`. - Resolved script invocations via `$PSScriptRoot` to avoid CWD issues. -### Elysium.ps1 v1.2.0 +#### Elysium.ps1 v1.2.0 Added: - Transcript logging to `Reports/logs/orchestrator-.log` and graceful shutdown without `exit`. -### Uninstall.ps1 v1.1.0 +#### Uninstall.ps1 v1.1.0 Added: - Transcript logging to `%TEMP%/Elysium/logs/uninstall-.log` so logs persist after directory removal. -### Update-KHDB.ps1 v1.1.0 +#### Update-KHDB.ps1 v1.1.0 Added/Updated: - Robust settings validation and SAS token normalization. - Safe URL construction with `UriBuilder` and custom User-Agent. @@ -142,7 +154,7 @@ Added/Updated: - KHDB validation: format check (32-hex), deduplication and normalization. - Transcript logging to `Reports/logs/update-khdb-.log`. -### Test-WeakADPasswords.ps1 v1.2.0 +#### Test-WeakADPasswords.ps1 v1.2.0 Updated: - Enforced modules via `#Requires`; removed runtime installs. - Added strict mode and error preference. @@ -150,7 +162,7 @@ Updated: - Ensured report directory creation and sane defaults (`Reports`). - Removed stray top-level loop; UPN enrichment occurs during report generation only. -### Extract-NTHashes.ps1 v1.1.0 +#### Extract-NTHashes.ps1 v1.1.0 Updated: - Enforced modules via `#Requires`; added strict mode. - Fixed variable ordering bug and unified filename scheme with domain prefix. @@ -158,18 +170,18 @@ Updated: - Normalized SAS token and verified container existence; checksum verified before cleanup; artifacts retained on failure. - Paths resolved relative to `$PSScriptRoot`; ensured report base directory exists. -### ElysiumSettings.txt.sample v1.1.0 +#### ElysiumSettings.txt.sample v1.1.0 Updated: - `ReportPathBase` default changed to `Reports` (relative) and added guidance on required modules and replication rights. - Added optional `CheckOnlyEnabledUsers=true` example flag. -## Extract-NTHashes.ps1 +### Extract-NTHashes.ps1 -### version 1.1.1 +#### version 1.1.1 **Updated:** - UPNs of the accounts with passwords found in dictionary were moved into separate report (one UPN at a line) to enable further automation. -### version 1.1.0 +#### version 1.1.0 **Added:** - UPN retrieval (this will prolong the time needed to run the script significantly) - Better error handling diff --git a/Elysium.ps1 b/Elysium.ps1 index bba4838..b1b2dd8 100644 --- a/Elysium.ps1 +++ b/Elysium.ps1 @@ -7,7 +7,7 @@ ################################################## ## Project: Elysium ## ## File: Elysium.ps1 ## -## Version: 1.3.0 ## +## Version: 2.2.0 ## ## Support: support@cqre.net ## ################################################## diff --git a/ElysiumSettings.txt.sample b/ElysiumSettings.txt.sample index db80c3f..8b319f0 100644 --- a/ElysiumSettings.txt.sample +++ b/ElysiumSettings.txt.sample @@ -8,7 +8,7 @@ ################################################## ## Project: Elysium ## ## File: ElysiumSettings.txt ## -## Version: 1.3.0 ## +## Version: 2.2.0 ## ## Support: support@cqre.net ## ################################################## diff --git a/Extract-NTHashes.ps1 b/Extract-NTHashes.ps1 index f8bb843..9d1c23b 100644 --- a/Extract-NTHashes.ps1 +++ b/Extract-NTHashes.ps1 @@ -7,7 +7,7 @@ ################################################## ## Project: Elysium ## ## File: Extract-NTLMHashes.ps1 ## -## Version: 1.3.0 ## +## Version: 2.2.0 ## ## Support: support@cqre.net ## ################################################## diff --git a/Prepare-KHDBStorage.ps1 b/Prepare-KHDBStorage.ps1 index c1f15a9..755fc49 100644 --- a/Prepare-KHDBStorage.ps1 +++ b/Prepare-KHDBStorage.ps1 @@ -7,7 +7,7 @@ ################################################## ## Project: Elysium ## ## File: Prepare-KHDBStorage.ps1 ## -## Version: 1.1.1 ## +## Version: 2.2.0 ## ## Support: support@cqre.net ## ################################################## diff --git a/README.md b/README.md index 521d403..3c7a128 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,13 @@ Sensitive operations are confined only to the dedicated host. In the third step, * **Administrative Access:** Local admin privileges on the host for installation and updating. * **Domain Credentials:** For weak-password testing (option 2), an account with the three replication rights (`Replicating Directory Changes`, `Replicating Directory Changes All`, `Replicating Directory Changes In Filtered Set`) on the domain naming context; Domain Admin also works but is not required. Keep this account disabled and enable only when running tests. * **Network Requirements:** A stable connection to the domain controller in each tested AD domain and internet access (specific hostnames/IP addresses will be provided). + +## Versioning and Releases + +Elysium uses a **unified project version** starting with v2.2.0. Every script, the settings template, and the documentation share the same version number so you can verify consistency at a glance by checking the header of any `.ps1` file. Releases are tagged in Git (`v..`) and documented in `CHANGELOG.md`. + +Prior to v2.2.0, each script carried its own version number; those historical versions are preserved in the changelog for reference. + --- ## Operation ### Install and update @@ -61,8 +68,10 @@ To delegate, enable Advanced Features in ADUC, right-click the domain, choose *D #### Common errors - `The server has rejected the client credentials.` or `Credentials ... were rejected`: The supplied username/password is invalid for the selected domain controller, or the session is not running in the expected domain context. Re-run and provide valid domain credentials. +- `Account '' is missing the following replication permissions ...`: + Starting with v2.2.0, the script pre-validates the three required replication extended rights against the domain object ACL before attempting DCSync. If this error appears, delegate the listed rights (see *Least privileges* above) and retry. - `Get-ADReplAccount: Access is denied`: - Credentials are valid, but the account does not have the three replication permissions listed above. + Credentials are valid, but the account does not have the three replication permissions listed above. This error should now be rare because the pre-check catches most permission issues early; if it still occurs, verify the account is not restricted by an additional conditional access or Group Policy setting. - `Only FIPS certified cryptographic algorithms are enabled in .NET`: This warning comes from DSInternals under FIPS-enforced environments. Hash-quality operations that rely on MD5 may be limited. diff --git a/Test-WeakADPasswords.ps1 b/Test-WeakADPasswords.ps1 index 26adce5..61f038c 100644 --- a/Test-WeakADPasswords.ps1 +++ b/Test-WeakADPasswords.ps1 @@ -8,7 +8,7 @@ ################################################## ## Project: Elysium ## ## File: Test-WeakADPasswords.ps1 ## -## Version: 1.4.5 ## +## Version: 2.2.0 ## ## Support: support@cqre.net ## ################################################## @@ -590,6 +590,75 @@ function Get-ValidatedADCredential { } } +function Test-ReplicationPermissions { + param( + [Parameter(Mandatory)][string]$DomainDN, + [Parameter(Mandatory)][string]$Server, + [Parameter(Mandatory)][System.Management.Automation.PSCredential]$Credential + ) + + $requiredRights = [ordered]@{ + 'Replicating Directory Changes' = [guid]'1131f6aa-9c07-11d1-f79f-00c04fc2dcd2' + 'Replicating Directory Changes All' = [guid]'1131f6ab-9c07-11d1-f79f-00c04fc2dcd2' + 'Replicating Directory Changes In Filtered Set' = [guid]'89e95b76-444d-4c62-991a-0facbeda640c' + } + + # Collect caller SID + direct group SIDs so we can match ACEs below + $callerSids = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) + try { + $samName = $Credential.UserName -replace '^.*\\', '' + $adUser = Get-ADUser -Identity $samName -Server $Server -Credential $Credential ` + -Properties SID, MemberOf -ErrorAction Stop + [void]$callerSids.Add($adUser.SID.Value) + foreach ($groupDN in @($adUser.MemberOf)) { + try { + $g = Get-ADGroup -Identity $groupDN -Server $Server -Credential $Credential ` + -Properties SID -ErrorAction Stop + [void]$callerSids.Add($g.SID.Value) + } catch { } + } + } catch { + Write-Warning ("Could not resolve account SIDs for replication permission pre-check: {0}. Skipping." -f $_.Exception.Message) + return + } + + # Read the domain object's DACL via ADSI so we can use the provided credential + $acl = $null + try { + $de = New-Object System.DirectoryServices.DirectoryEntry( + "LDAP://$Server/$DomainDN", + $Credential.UserName, + $Credential.GetNetworkCredential().Password + ) + # Translate all trustees to SID form for consistent comparison + $acl = $de.ObjectSecurity.GetAccessRules( + $true, $true, [System.Security.Principal.SecurityIdentifier]) + } catch { + Write-Warning ("Could not read domain object ACL for replication permission pre-check: {0}. Skipping." -f $_.Exception.Message) + return + } + + $missing = @() + foreach ($rightName in $requiredRights.Keys) { + $guid = $requiredRights[$rightName] + $granted = $false + foreach ($ace in $acl) { + if ($ace.AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow) { continue } + if (-not ($ace.ActiveDirectoryRights -band [System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight)) { continue } + if ($ace.ObjectType -ne $guid) { continue } + if ($callerSids.Contains($ace.IdentityReference.Value)) { $granted = $true; break } + } + if (-not $granted) { $missing += $rightName } + } + + if ($missing.Count -gt 0) { + throw ("Account '{0}' is missing the following replication permissions on '{1}':`n - {2}`n`nGrant these extended rights on the domain object to allow DCSync-based hash retrieval." -f ` + $Credential.UserName, $DomainDN, ($missing -join "`n - ")) + } + + Write-Verbose ("Replication permission pre-check passed for '{0}'." -f $Credential.UserName) +} + # Function to test for weak AD passwords function Test-WeakADPasswords { param ( @@ -624,6 +693,16 @@ function Test-WeakADPasswords { Write-Verbose ("Using credential supplied by caller: {0}" -f $credential.UserName) } + # Verify the account has the three replication extended rights before attempting DCSync + try { + $domainInfo = Get-ADDomain -Server $selectedDomain["DC"] -Credential $credential -ErrorAction Stop + Test-ReplicationPermissions -DomainDN $domainInfo.DistinguishedName ` + -Server $selectedDomain["DC"] -Credential $credential + } catch { + Write-Error $_.Exception.Message + return + } + # Performing the test Write-Verbose "Testing password quality for $($selectedDomain.Name)..." $resolvedHashFile = $null diff --git a/Uninstall.ps1 b/Uninstall.ps1 index 23f973e..1f37480 100644 --- a/Uninstall.ps1 +++ b/Uninstall.ps1 @@ -7,7 +7,7 @@ ################################################## ## Project: Elysium ## ## File: Uninstall.ps1 ## -## Version: 1.2.0 ## +## Version: 2.2.0 ## ## Support: support@cqre.net ## ################################################## diff --git a/Update-KHDB.ps1 b/Update-KHDB.ps1 index ace9f27..d7a9033 100644 --- a/Update-KHDB.ps1 +++ b/Update-KHDB.ps1 @@ -7,7 +7,7 @@ ################################################## ## Project: Elysium ## ## File: Update-KHDB.ps1 ## -## Version: 2.1.1 ## +## Version: 2.2.0 ## ## Support: support@cqre.net ## ################################################## diff --git a/Update-LithnetStore.ps1 b/Update-LithnetStore.ps1 index 0650491..bf1bc80 100644 --- a/Update-LithnetStore.ps1 +++ b/Update-LithnetStore.ps1 @@ -7,7 +7,7 @@ ################################################## ## Project: Elysium ## ## File: Update-LithnetStore.ps1 ## -## Version: 1.1.0 ## +## Version: 2.2.0 ## ## Support: support@cqre.net ## ##################################################