9496063b97
Test-ReplicationPermissions now recognizes: - GenericAll as satisfying replication rights - Blanket ExtendedRight (empty ObjectType) ACEs Also adds diagnostic hints distinguishing between 'missing ACE entirely' and 'ACE exists but not for you'. All versions bumped to unified v2.2.3.
168 lines
6.5 KiB
PowerShell
168 lines
6.5 KiB
PowerShell
##################################################
|
|
## ____ ___ ____ _____ _ _ _____ _____ ##
|
|
## / ___/ _ \| _ \| ____| | \ | | ____|_ _| ##
|
|
## | | | | | | |_) | _| | \| | _| | | ##
|
|
## | |__| |_| | _ <| |___ _| |\ | |___ | | ##
|
|
## \____\__\_\_| \_\_____(_)_| \_|_____| |_| ##
|
|
##################################################
|
|
## Project: Elysium ##
|
|
## File: Update-LithnetStore.ps1 ##
|
|
## Version: 2.2.3 ##
|
|
## Support: support@cqre.net ##
|
|
##################################################
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Populates a Lithnet Password Protection store with compromised passwords and banned words.
|
|
|
|
.DESCRIPTION
|
|
Reads configuration from ElysiumSettings.txt (or a provided settings file), opens the Lithnet
|
|
Password Protection store, optionally synchronizes with Have I Been Pwned, imports local NTLM
|
|
hash lists, plaintext password lists, and banned-word files.
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$SettingsPath,
|
|
[string[]]$HashFiles,
|
|
[string[]]$PlaintextFiles,
|
|
[string[]]$BannedWordFiles,
|
|
[switch]$SkipHibpSync
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
Set-StrictMode -Version Latest
|
|
[string]$commonHelper = Join-Path -Path $PSScriptRoot -ChildPath 'Elysium.Common.ps1'
|
|
if (-not (Test-Path -LiteralPath $commonHelper)) { throw "Common helper not found at $commonHelper" }
|
|
. $commonHelper
|
|
Restart-WithPwshIfAvailable -BoundParameters $PSBoundParameters -UnboundArguments $MyInvocation.UnboundArguments
|
|
|
|
function Read-KeyValueSettings {
|
|
param([string]$Path)
|
|
$result = @{}
|
|
if (-not (Test-Path -LiteralPath $Path)) { throw "Settings file not found at $Path" }
|
|
Get-Content -LiteralPath $Path | ForEach-Object {
|
|
$line = $_
|
|
if (-not $line) { return }
|
|
$trimmed = $line.Trim()
|
|
if (-not $trimmed) { return }
|
|
if ($trimmed.StartsWith('#')) { return }
|
|
$kv = $line -split '=', 2
|
|
if ($kv.Count -ne 2) { return }
|
|
$key = $kv[0].Trim()
|
|
$value = $kv[1].Trim()
|
|
if (-not $key) { return }
|
|
if ($value.StartsWith("'") -and $value.EndsWith("'") -and $value.Length -ge 2) {
|
|
$value = $value.Substring(1, $value.Length - 2)
|
|
}
|
|
$result[$key] = $value
|
|
}
|
|
return $result
|
|
}
|
|
|
|
function Get-BooleanSetting {
|
|
param(
|
|
[string]$Value,
|
|
[bool]$Default = $false
|
|
)
|
|
if ([string]::IsNullOrWhiteSpace($Value)) { return $Default }
|
|
try { return [System.Convert]::ToBoolean($Value) } catch { return $Default }
|
|
}
|
|
|
|
function Get-ListFromSetting {
|
|
param([string]$Value)
|
|
if ([string]::IsNullOrWhiteSpace($Value)) { return @() }
|
|
return ($Value -split '[,;]' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
|
|
}
|
|
|
|
function Resolve-ExistingPath {
|
|
param([string]$PathValue, [string]$Description)
|
|
if ([string]::IsNullOrWhiteSpace($PathValue)) { throw "$Description path was not provided." }
|
|
if (-not (Test-Path -LiteralPath $PathValue)) {
|
|
throw "$Description not found at '$PathValue'."
|
|
}
|
|
return (Resolve-Path -LiteralPath $PathValue).Path
|
|
}
|
|
|
|
if (-not $SettingsPath) {
|
|
$SettingsPath = Join-Path -Path $PSScriptRoot -ChildPath 'ElysiumSettings.txt'
|
|
}
|
|
$settings = Read-KeyValueSettings -Path $SettingsPath
|
|
|
|
$storePathSetting = $settings['LithnetStorePath']
|
|
$storePath = Resolve-ExistingPath -PathValue $storePathSetting -Description 'Lithnet store'
|
|
|
|
$settingsHashSources = Get-ListFromSetting -Value $settings['LithnetHashSources']
|
|
$settingsPlainSources = Get-ListFromSetting -Value $settings['LithnetPlaintextSources']
|
|
$settingsBannedSources = Get-ListFromSetting -Value $settings['LithnetBannedWordSources']
|
|
|
|
$hashSourcePaths = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::OrdinalIgnoreCase)
|
|
foreach ($path in @($HashFiles) + $settingsHashSources) {
|
|
if ([string]::IsNullOrWhiteSpace($path)) { continue }
|
|
$resolved = Resolve-ExistingPath -PathValue $path -Description 'Hash list'
|
|
[void]$hashSourcePaths.Add($resolved)
|
|
}
|
|
if ($hashSourcePaths.Count -eq 0) {
|
|
$defaultKhdb = Join-Path -Path $PSScriptRoot -ChildPath 'khdb.txt'
|
|
if (Test-Path -LiteralPath $defaultKhdb) {
|
|
[void]$hashSourcePaths.Add((Resolve-Path -LiteralPath $defaultKhdb).Path)
|
|
} else {
|
|
throw 'No hash files were provided via parameters or LithnetHashSources, and khdb.txt was not found.'
|
|
}
|
|
}
|
|
|
|
$plaintextSourcePaths = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::OrdinalIgnoreCase)
|
|
foreach ($path in @($PlaintextFiles) + $settingsPlainSources) {
|
|
if ([string]::IsNullOrWhiteSpace($path)) { continue }
|
|
$resolved = Resolve-ExistingPath -PathValue $path -Description 'Plaintext password list'
|
|
[void]$plaintextSourcePaths.Add($resolved)
|
|
}
|
|
|
|
$bannedWordSourcePaths = New-Object System.Collections.Generic.HashSet[string] ([System.StringComparer]::OrdinalIgnoreCase)
|
|
foreach ($path in @($BannedWordFiles) + $settingsBannedSources) {
|
|
if ([string]::IsNullOrWhiteSpace($path)) { continue }
|
|
$resolved = Resolve-ExistingPath -PathValue $path -Description 'Banned word list'
|
|
[void]$bannedWordSourcePaths.Add($resolved)
|
|
}
|
|
|
|
$syncHibp = Get-BooleanSetting -Value $settings['LithnetSyncHibp'] -Default:$false
|
|
if ($SkipHibpSync) { $syncHibp = $false }
|
|
|
|
Write-Host "Importing LithnetPasswordProtection module..."
|
|
try {
|
|
Import-Module -Name LithnetPasswordProtection -ErrorAction Stop | Out-Null
|
|
} catch {
|
|
throw "LithnetPasswordProtection module not found: $($_.Exception.Message). Install it from https://github.com/lithnet/password-protection."
|
|
}
|
|
|
|
Write-Host ("Opening Lithnet store at '{0}'..." -f $storePath)
|
|
Open-Store -Path $storePath
|
|
$storeOpened = $true
|
|
try {
|
|
if ($syncHibp) {
|
|
Write-Host 'Synchronizing compromised hashes from Have I Been Pwned (this can take a while)...'
|
|
Sync-HashesFromHibp
|
|
}
|
|
|
|
foreach ($hashFile in ($hashSourcePaths.ToArray() | Sort-Object)) {
|
|
Write-Host ("Importing NTLM hash list '{0}'..." -f $hashFile)
|
|
Import-CompromisedPasswordHashes -Filename $hashFile
|
|
}
|
|
|
|
foreach ($plainFile in ($plaintextSourcePaths.ToArray() | Sort-Object)) {
|
|
Write-Host ("Importing plaintext password list '{0}'..." -f $plainFile)
|
|
Import-CompromisedPasswords -Filename $plainFile
|
|
}
|
|
|
|
foreach ($bannedFile in ($bannedWordSourcePaths.ToArray() | Sort-Object)) {
|
|
Write-Host ("Importing banned word list '{0}'..." -f $bannedFile)
|
|
Import-BannedWords -Filename $bannedFile
|
|
}
|
|
|
|
Write-Host 'Lithnet store update completed successfully.'
|
|
} finally {
|
|
if ($storeOpened) {
|
|
try { Close-Store } catch {}
|
|
}
|
|
}
|