Quản lý bảo mật Active Directory (AD) có thể là một thách thức, đặc biệt là khi xác định tài khoản chia sẻ mật khẩu hoặc sử dụng các thực tiễn xác thực yếu. , một công cụ PowerShell mạnh mẽ, nhẹ, nhanh chóng tiết lộ việc sử dụng mật khẩu được chia sẻ và cải thiện tư thế bảo mật của tổ chức của bạn. LazyAdminFinder LazyAdminFinder là gì? LazyAdminFinder là một kịch bản PowerShell sử dụng mô-đun DSInternals để: Phát hiện và báo cáo hash mật khẩu NTLM được chia sẻ. Lưu trữ và so sánh dữ liệu hash lịch sử để xác định việc sử dụng lại mật khẩu. Cung cấp các báo cáo toàn diện xác định hành vi tài khoản rủi ro. Được thiết kế đặc biệt cho người quản trị Active Directory, LazyAdminFinder cung cấp những hiểu biết nhanh chóng và có thể thực hiện về bảo mật mật khẩu. Tại sao nên sử dụng LazyAdminFinder? Identify weak or compromised passwords. Security Improvement: Maintain AD integrity for audit and compliance purposes. Compliance: Quickly audit accounts without manually reviewing data. Efficiency: LazyAdminFinder hoạt động như thế nào? Fetch và Filter tài khoản người dùng Kịch bản thu thập tài khoản người dùng AD, lọc ra các tài khoản bị vô hiệu hóa, máy và dịch vụ để chỉ tập trung vào người dùng đang hoạt động. NTLM Hash Extraction và Archiving LazyAdminFinder trích xuất các hash NTLM từ tài khoản và lưu trữ an toàn các hash SHA-256 của họ để so sánh lịch sử. Password Reuse phát hiện Bằng cách so sánh chạy hiện tại với các kho lưu trữ trước đó, công cụ phát hiện sử dụng lại mật khẩu, đánh dấu các tài khoản có rủi ro bảo mật tiềm tàng. Quản trị hoặc người dùng có đặc quyền đồng bộ mật khẩu giữa tài khoản tiêu chuẩn và tài khoản quản trị. Người dùng, đặc biệt là người quản trị, liên tục đặt lại mật khẩu của họ cho các giá trị đã được sử dụng trước đó. Chia sẻ Password Grouping Kịch bản xác định và nhóm các tài khoản chia sẻ hash NTLM giống hệt nhau, có thể chỉ ra chia sẻ mật khẩu có chủ ý hoặc nhiều người dùng độc lập chọn cùng một mật khẩu - thường là do thói quen mật khẩu yếu. ví dụ, nếu nhiều người dùng chọn một mật khẩu chung như "Summer2025!", LazyAdminFinder sẽ nhóm các tài khoản này lại với nhau, cho phép bạn nhanh chóng phát hiện cả mật khẩu chia sẻ tiềm năng và suy nghĩ song song rủi ro trong việc tạo mật khẩu. Tần số sử dụng khuyến cáo Hãy xem xét chạy LazyAdminFinder thường xuyên dựa trên chính sách đặt lại mật khẩu của tổ chức của bạn. Ví dụ, nếu chính sách của bạn yêu cầu đặt lại mật khẩu mỗi 90 ngày, hãy lên lịch để kịch bản chạy khoảng 100 ngày một lần. Thời gian này đảm bảo bạn nắm bắt các trường hợp nơi người quản trị hoặc người dùng có đặc quyền có thể đặt lại mật khẩu của họ trở lại những người đã sử dụng trước đó. Nếu tổ chức của bạn không thực thi chính sách sử dụng lại mật khẩu, chạy LazyAdminFinder định kỳ trở nên quan trọng hơn để xác định và giảm thiểu các rủi ro bảo mật tiềm năng. Cài đặt LazyAdminFinder Bước 1: Chuẩn bị Đảm bảo PowerShell được cài đặt trên hệ thống của bạn. Cài đặt các module cần thiết: Install-Module DSInternals Bước 2: Thiết lập script Tùy chỉnh các thông số thiết yếu này trong kịch bản được cung cấp: Domain Controller : $dc = "your-domain-controller.example.com" Định nghĩa ngữ cảnh: $nc = "DC=yourdomain,DC=com" Đường dẫn báo cáo xuất khẩu: $outputReport = "C:\Path\To\SharedPasswordsReport.csv" Địa chỉ lưu trữ: $archiveDir = "C:\Path\To\HashArchives" Bước 3: Run the script Chạy kịch bản dưới dạng Domain admin: powershell.exe -ExecutionPolicy Bypass -File "C:\Path\To\LazyAdminFinder.ps1" Đánh giá kết quả Một báo cáo CSV chi tiết được tạo ra, làm nổi bật rõ ràng các tài khoản chia sẻ mật khẩu hoặc độc lập chọn mật khẩu yếu. Lưu trữ lịch sử được lưu trữ an toàn cho các so sánh trong tương lai, đảm bảo quản lý mật khẩu mạnh mẽ. Sử dụng trường hợp cho LazyAdminFinder Kiểm tra bảo mật: Thường xuyên xác định và khắc phục mật khẩu được chia sẻ, yếu hoặc bị xâm phạm. Trả lời sự cố: Phát hiện nhanh các tài khoản bị xâm phạm sau các sự cố bảo mật. Kiểm tra tuân thủ thường xuyên: Đảm bảo tuân thủ liên tục bằng cách duy trì các thực tiễn bảo mật tài khoản mạnh mẽ. Quản lý tài khoản đặc quyền: Nhắm mục tiêu cụ thể vào người quản trị hoặc người dùng đặc quyền có thể tái sử dụng hoặc đồng bộ hóa mật khẩu trên nhiều tài khoản. Tùy chỉnh LazyAdminFinder Cảm thấy tự do để điều chỉnh kịch bản theo môi trường và nhu cầu của bạn: Thay đổi logic lọc để bao gồm / loại trừ các loại tài khoản cụ thể. Điều chỉnh đường dẫn lưu trữ và báo cáo cho các tùy chọn lưu trữ của bạn. Tích hợp các khả năng báo cáo bổ sung theo yêu cầu. Lợi ích của việc sử dụng LazyAdminFinder Automates complex AD security checks. Rapid Security Assessments: Clearly identifies potential security risks within AD. Enhanced Visibility: Enables administrators to swiftly address vulnerabilities before exploitation. Proactive Defense: LazyAdminFinder đơn giản hóa nhiệm vụ quan trọng của kiểm tra mật khẩu trong Active Directory, trao quyền cho người quản trị để duy trì một môi trường CNTT an toàn, tuân thủ và hiệu quả. Khám phá mật khẩu được chia sẻ, khắc phục rủi ro bảo mật và tăng cường bảo mật quảng cáo của bạn một cách dễ dàng với LazyAdminFinder. #Another /\_[]_/\ # fine |] _||_ [| # ___ \/ || \/ # /___\ || # (|0 0|) || # __/{\U/}\_ ___/vvv # / \ {~} / _|_P| # | /\ ~ /_/ [] # |_| (____) # \_]/______\ Barberion # _\_||_/_ Production # (_,_||_,_) # Import-Module DSInternals # === Parameters === $dc = "your-domain-controller.example.com" $nc = "DC=yourdomain,DC=com" $outputReport = "C:\Path\To\SharedPasswordsReport.csv" $archiveDir = "C:\Path\To\HashArchives" # Ensure archive directory exists if (-not (Test-Path $archiveDir)) { New-Item -ItemType Directory -Path $archiveDir | Out-Null } $timestamp = (Get-Date).ToString("yyyyMMdd_HHmmss") # === 1. Fetch & filter AD user accounts === Write-Host "[+] Fetching AD user accounts (skipping machines, service & disabled)..." $filteredAccounts = Get-ADReplAccount -All -Server $dc -NamingContext $nc | Where-Object { $_.NTHash -and $_.SamAccountName } | Where-Object { $_.SamAccountName -notmatch '\$$' } | Where-Object { $_.SamAccountName -notmatch '^(?i)(svc|service)' } | Where-Object { if ($_.PSObject.Properties.Match('IsDisabled').Count -gt 0) { -not $_.IsDisabled } else { # bit 2 = disabled ( ($_.UserAccountControl -band 2) -eq 0 ) } } if (-not $filteredAccounts) { Write-Host "[-] No matching user accounts found. Exiting." exit } # === 2. Convert NTLM byte array to hex string === $filteredAccounts | ForEach-Object { $hex = [BitConverter]::ToString($_.NTHash) -replace '-', '' $_ | Add-Member -MemberType NoteProperty -Name NTLMHashString -Value $hex -Force } # === 3. Archive SHA-256 of each NTLM hash === Write-Host "[+] Archiving SHA-256 of each NTLM hash..." $sha256 = [System.Security.Cryptography.SHA256]::Create() $currentArchive = $filteredAccounts | ForEach-Object { $shaBytes = $sha256.ComputeHash($_.NTHash) $shaHex = [BitConverter]::ToString($shaBytes) -replace '-', '' [PSCustomObject]@{ SamAccountName = $_.SamAccountName HashSha256 = $shaHex } } $sha256.Dispose() $archiveFile = Join-Path $archiveDir "UserHashArchive_$timestamp.csv" $currentArchive | Export-Csv -Path $archiveFile -NoTypeInformation # === 4. Compare to previous archive === $allArchives = Get-ChildItem -Path $archiveDir -Filter "UserHashArchive_*.csv" | Sort-Object LastWriteTime -Descending if ($allArchives.Count -gt 1) { $previousFile = $allArchives[1].FullName Write-Host "[+] Comparing this run to previous archive: $previousFile" $prevData = Import-Csv $previousFile $reused = Compare-Object ` -ReferenceObject $prevData ` -DifferenceObject $currentArchive ` -Property SamAccountName, HashSha256 ` -IncludeEqual | Where-Object { $_.SideIndicator -eq '==' } | Select-Object SamAccountName, HashSha256 if ($reused) { $reuseReport = Join-Path $archiveDir "PasswordReuse_$timestamp.csv" Write-Host "[!] $($reused.Count) accounts reused their old hash; exporting to $reuseReport" $reused | Export-Csv -Path $reuseReport -NoTypeInformation } else { Write-Host "[+] No password‑reuse detected this run." } } else { Write-Host "[+] Only one archive present; skipping reuse comparison." } # === 5. Shared‑password grouping & report === Write-Host "[+] Grouping accounts by shared NTLM hash..." $sharedGroups = $filteredAccounts | Group-Object -Property NTLMHashString | Where-Object { $_.Count -gt 1 } if (-not $sharedGroups) { Write-Host "[-] No shared hashes found." exit } $reportResults = @() Write-Host "[+] Generating shared‑password report:" foreach ($g in $sharedGroups) { $h = $g.Name $users = $g.Group | ForEach-Object { $_.SamAccountName } $reportResults += [PSCustomObject]@{ SharedHash = $h UserCount = $users.Count Users = $users -join ', ' } Write-Host '----------------------------------------------' Write-Host "Shared Hash: $h" Write-Host "User Count : $($users.Count)" Write-Host "Users : $($users -join ', ')" Write-Host '----------------------------------------------`n' } Write-Host "[+] Saving shared‑password report to $outputReport" $reportResults | Export-Csv -Path $outputReport -NoTypeInformation Write-Host "[Summary] Shared groups: $($reportResults.Count); Total archives: $($allArchives.Count)"