Release v2.2.0: unified versioning and replication permission pre-check
- Unified project versioning (v2.2.0) across all scripts, settings template, and documentation. All components now share a single version number. - Added Test-ReplicationPermissions to Test-WeakADPasswords.ps1 to validate the three required AD replication extended rights before DCSync, providing clear fail-fast errors when permissions are missing. - Updated CHANGELOG.md with unified versioning strategy and release history. - Updated README.md with versioning section and improved troubleshooting docs.
This commit is contained in:
@@ -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`.
|
||||||
+55
-43
@@ -1,72 +1,84 @@
|
|||||||
# Changelog
|
# 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:
|
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.
|
- 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.
|
- 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:
|
Fixed:
|
||||||
- Rebuilds the merged local `khdb.txt` as a DSInternals-compatible hash-only file even when upstream shards still contain legacy `HASH:count` lines.
|
- 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.
|
- 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:
|
Fixed:
|
||||||
- Accepts legacy `HASH:count` source input but writes deduplicated hash-only shards for downstream DSInternals consumers.
|
- Accepts legacy `HASH:count` source input but writes deduplicated hash-only shards for downstream DSInternals consumers.
|
||||||
|
|
||||||
### README.md
|
#### README.md
|
||||||
Changed:
|
Changed:
|
||||||
- Corrected the KHDB format documentation to require one NT hash per line and documented the automatic legacy-format normalization.
|
- 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:
|
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.
|
- 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:
|
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.
|
- 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:
|
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.
|
- 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:
|
Changed:
|
||||||
- Added credential pre-validation against the selected domain controller before running `Get-ADReplAccount`, including retry prompts for rejected credentials.
|
- 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`).
|
- 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.
|
- Added optional `-Credential` parameter to `Test-WeakADPasswords` for callers that need to provide credentials non-interactively.
|
||||||
|
|
||||||
### README.md
|
#### README.md
|
||||||
Changed:
|
Changed:
|
||||||
- Updated weak-password testing documentation to reflect credential pre-check behavior and added a short troubleshooting section for common authentication/permissions failures.
|
- 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:
|
Changed:
|
||||||
- Replaced single-archive workflow with manifest-driven, two-hex shard downloads that verify SHA256/size before in-place updates.
|
- 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.
|
- 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.
|
- 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:
|
Added:
|
||||||
- Documented `KhdbManifestPath`, `KhdbShardPrefix`, and `KhdbLocalShardDir` defaults for the shard-aware updater.
|
- Documented `KhdbManifestPath`, `KhdbShardPrefix`, and `KhdbLocalShardDir` defaults for the shard-aware updater.
|
||||||
|
|
||||||
### README.md
|
#### README.md
|
||||||
Changed:
|
Changed:
|
||||||
- Described the manifest/shard update flow so operators understand the incremental download model and automatic cleanup.
|
- 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:
|
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.
|
- 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.
|
- 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.
|
- 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.
|
- 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:
|
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).
|
- 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.
|
- 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:
|
Added:
|
||||||
- Documented `UsageBeacon*` keys (URL, method, instance ID, timeout) so telemetry stays disabled by default but easy to enable.
|
- Documented `UsageBeacon*` keys (URL, method, instance ID, timeout) so telemetry stays disabled by default but easy to enable.
|
||||||
|
|
||||||
### README.md
|
#### README.md
|
||||||
Added:
|
Added:
|
||||||
- Usage beacon section explaining how to configure the lightweight tracking call and what metadata is transmitted.
|
- 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:
|
Fixed:
|
||||||
- Corrected SigV4 host header formatting so non-default ports serialize without parser errors.
|
- Corrected SigV4 host header formatting so non-default ports serialize without parser errors.
|
||||||
- Hardened hashing helpers to avoid `ComputeHash` overload ambiguity under Windows PowerShell.
|
- Hardened hashing helpers to avoid `ComputeHash` overload ambiguity under Windows PowerShell.
|
||||||
- Domain selection menu now respects the configured numeric order.
|
- Domain selection menu now respects the configured numeric order.
|
||||||
|
|
||||||
### Test-WeakADPasswords.ps1 v1.3.2
|
#### Test-WeakADPasswords.ps1 v1.3.2
|
||||||
Changed:
|
Changed:
|
||||||
- Switched to the sorted KHDB path when driving `Test-PasswordQuality`, eliminating full linear scans and avoiding malformed-line crashes on massive datasets.
|
- 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:
|
Fixed:
|
||||||
- Domain picker now renders in numeric order from settings for predictable operator workflows.
|
- 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.
|
- 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:
|
Added:
|
||||||
- `CheckOnlyEnabledUsers` flag wired from settings to filter accounts prior to `Test-PasswordQuality`.
|
- `CheckOnlyEnabledUsers` flag wired from settings to filter accounts prior to `Test-PasswordQuality`.
|
||||||
- Transcript logging to `Reports/logs/test-weakad-<timestamp>.log`.
|
- Transcript logging to `Reports/logs/test-weakad-<timestamp>.log`.
|
||||||
|
|
||||||
### Extract-NTHashes.ps1 v1.2.0
|
#### Extract-NTHashes.ps1 v1.2.0
|
||||||
Added:
|
Added:
|
||||||
- Transcript logging to `Reports/logs/extract-hashes-<timestamp>.log`.
|
- Transcript logging to `Reports/logs/extract-hashes-<timestamp>.log`.
|
||||||
|
|
||||||
### Elysium.ps1 v1.1.0
|
#### Elysium.ps1 v1.1.0
|
||||||
Updated:
|
Updated:
|
||||||
- Added strict error handling (`$ErrorActionPreference='Stop'`) and `Set-StrictMode`.
|
- Added strict error handling (`$ErrorActionPreference='Stop'`) and `Set-StrictMode`.
|
||||||
- Resolved script invocations via `$PSScriptRoot` to avoid CWD issues.
|
- Resolved script invocations via `$PSScriptRoot` to avoid CWD issues.
|
||||||
|
|
||||||
### Elysium.ps1 v1.2.0
|
#### Elysium.ps1 v1.2.0
|
||||||
Added:
|
Added:
|
||||||
- Transcript logging to `Reports/logs/orchestrator-<timestamp>.log` and graceful shutdown without `exit`.
|
- Transcript logging to `Reports/logs/orchestrator-<timestamp>.log` and graceful shutdown without `exit`.
|
||||||
|
|
||||||
### Uninstall.ps1 v1.1.0
|
#### Uninstall.ps1 v1.1.0
|
||||||
Added:
|
Added:
|
||||||
- Transcript logging to `%TEMP%/Elysium/logs/uninstall-<timestamp>.log` so logs persist after directory removal.
|
- Transcript logging to `%TEMP%/Elysium/logs/uninstall-<timestamp>.log` so logs persist after directory removal.
|
||||||
|
|
||||||
### Update-KHDB.ps1 v1.1.0
|
#### Update-KHDB.ps1 v1.1.0
|
||||||
Added/Updated:
|
Added/Updated:
|
||||||
- Robust settings validation and SAS token normalization.
|
- Robust settings validation and SAS token normalization.
|
||||||
- Safe URL construction with `UriBuilder` and custom User-Agent.
|
- Safe URL construction with `UriBuilder` and custom User-Agent.
|
||||||
@@ -142,7 +154,7 @@ Added/Updated:
|
|||||||
- KHDB validation: format check (32-hex), deduplication and normalization.
|
- KHDB validation: format check (32-hex), deduplication and normalization.
|
||||||
- Transcript logging to `Reports/logs/update-khdb-<timestamp>.log`.
|
- Transcript logging to `Reports/logs/update-khdb-<timestamp>.log`.
|
||||||
|
|
||||||
### Test-WeakADPasswords.ps1 v1.2.0
|
#### Test-WeakADPasswords.ps1 v1.2.0
|
||||||
Updated:
|
Updated:
|
||||||
- Enforced modules via `#Requires`; removed runtime installs.
|
- Enforced modules via `#Requires`; removed runtime installs.
|
||||||
- Added strict mode and error preference.
|
- Added strict mode and error preference.
|
||||||
@@ -150,7 +162,7 @@ Updated:
|
|||||||
- Ensured report directory creation and sane defaults (`Reports`).
|
- Ensured report directory creation and sane defaults (`Reports`).
|
||||||
- Removed stray top-level loop; UPN enrichment occurs during report generation only.
|
- 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:
|
Updated:
|
||||||
- Enforced modules via `#Requires`; added strict mode.
|
- Enforced modules via `#Requires`; added strict mode.
|
||||||
- Fixed variable ordering bug and unified filename scheme with domain prefix.
|
- 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.
|
- 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.
|
- Paths resolved relative to `$PSScriptRoot`; ensured report base directory exists.
|
||||||
|
|
||||||
### ElysiumSettings.txt.sample v1.1.0
|
#### ElysiumSettings.txt.sample v1.1.0
|
||||||
Updated:
|
Updated:
|
||||||
- `ReportPathBase` default changed to `Reports` (relative) and added guidance on required modules and replication rights.
|
- `ReportPathBase` default changed to `Reports` (relative) and added guidance on required modules and replication rights.
|
||||||
- Added optional `CheckOnlyEnabledUsers=true` example flag.
|
- Added optional `CheckOnlyEnabledUsers=true` example flag.
|
||||||
|
|
||||||
## Extract-NTHashes.ps1
|
### Extract-NTHashes.ps1
|
||||||
|
|
||||||
### version 1.1.1
|
#### version 1.1.1
|
||||||
**Updated:**
|
**Updated:**
|
||||||
- UPNs of the accounts with passwords found in dictionary were moved into separate report (one UPN at a line) to enable further automation.
|
- 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:**
|
**Added:**
|
||||||
- UPN retrieval (this will prolong the time needed to run the script significantly)
|
- UPN retrieval (this will prolong the time needed to run the script significantly)
|
||||||
- Better error handling
|
- Better error handling
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
##################################################
|
##################################################
|
||||||
## Project: Elysium ##
|
## Project: Elysium ##
|
||||||
## File: Elysium.ps1 ##
|
## File: Elysium.ps1 ##
|
||||||
## Version: 1.3.0 ##
|
## Version: 2.2.0 ##
|
||||||
## Support: support@cqre.net ##
|
## Support: support@cqre.net ##
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
##################################################
|
##################################################
|
||||||
## Project: Elysium ##
|
## Project: Elysium ##
|
||||||
## File: ElysiumSettings.txt ##
|
## File: ElysiumSettings.txt ##
|
||||||
## Version: 1.3.0 ##
|
## Version: 2.2.0 ##
|
||||||
## Support: support@cqre.net ##
|
## Support: support@cqre.net ##
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
##################################################
|
##################################################
|
||||||
## Project: Elysium ##
|
## Project: Elysium ##
|
||||||
## File: Extract-NTLMHashes.ps1 ##
|
## File: Extract-NTLMHashes.ps1 ##
|
||||||
## Version: 1.3.0 ##
|
## Version: 2.2.0 ##
|
||||||
## Support: support@cqre.net ##
|
## Support: support@cqre.net ##
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
##################################################
|
##################################################
|
||||||
## Project: Elysium ##
|
## Project: Elysium ##
|
||||||
## File: Prepare-KHDBStorage.ps1 ##
|
## File: Prepare-KHDBStorage.ps1 ##
|
||||||
## Version: 1.1.1 ##
|
## Version: 2.2.0 ##
|
||||||
## Support: support@cqre.net ##
|
## Support: support@cqre.net ##
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
* **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.
|
* **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).
|
* **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<major>.<minor>.<patch>`) 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
|
## Operation
|
||||||
### Install and update
|
### Install and update
|
||||||
@@ -61,8 +68,10 @@ To delegate, enable Advanced Features in ADUC, right-click the domain, choose *D
|
|||||||
#### Common errors
|
#### Common errors
|
||||||
- `The server has rejected the client credentials.` or `Credentials ... were rejected`:
|
- `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.
|
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 '<user>' 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`:
|
- `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`:
|
- `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.
|
This warning comes from DSInternals under FIPS-enforced environments. Hash-quality operations that rely on MD5 may be limited.
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
##################################################
|
##################################################
|
||||||
## Project: Elysium ##
|
## Project: Elysium ##
|
||||||
## File: Test-WeakADPasswords.ps1 ##
|
## File: Test-WeakADPasswords.ps1 ##
|
||||||
## Version: 1.4.5 ##
|
## Version: 2.2.0 ##
|
||||||
## Support: support@cqre.net ##
|
## 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 to test for weak AD passwords
|
||||||
function Test-WeakADPasswords {
|
function Test-WeakADPasswords {
|
||||||
param (
|
param (
|
||||||
@@ -624,6 +693,16 @@ function Test-WeakADPasswords {
|
|||||||
Write-Verbose ("Using credential supplied by caller: {0}" -f $credential.UserName)
|
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
|
# Performing the test
|
||||||
Write-Verbose "Testing password quality for $($selectedDomain.Name)..."
|
Write-Verbose "Testing password quality for $($selectedDomain.Name)..."
|
||||||
$resolvedHashFile = $null
|
$resolvedHashFile = $null
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
##################################################
|
##################################################
|
||||||
## Project: Elysium ##
|
## Project: Elysium ##
|
||||||
## File: Uninstall.ps1 ##
|
## File: Uninstall.ps1 ##
|
||||||
## Version: 1.2.0 ##
|
## Version: 2.2.0 ##
|
||||||
## Support: support@cqre.net ##
|
## Support: support@cqre.net ##
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
##################################################
|
##################################################
|
||||||
## Project: Elysium ##
|
## Project: Elysium ##
|
||||||
## File: Update-KHDB.ps1 ##
|
## File: Update-KHDB.ps1 ##
|
||||||
## Version: 2.1.1 ##
|
## Version: 2.2.0 ##
|
||||||
## Support: support@cqre.net ##
|
## Support: support@cqre.net ##
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
##################################################
|
##################################################
|
||||||
## Project: Elysium ##
|
## Project: Elysium ##
|
||||||
## File: Update-LithnetStore.ps1 ##
|
## File: Update-LithnetStore.ps1 ##
|
||||||
## Version: 1.1.0 ##
|
## Version: 2.2.0 ##
|
||||||
## Support: support@cqre.net ##
|
## Support: support@cqre.net ##
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user