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`.
|
||||
Reference in New Issue
Block a user