Загрузка данных
# ============================================================
# Browser Saved Password Audit
# PowerShell 2.0 compatible
#
# Проверяет наличие реально сохраненных паролей:
# - Google Chrome
# - Microsoft Edge
# - Yandex Browser
#
# Требуется sqlite3.exe рядом со скриптом.
#
# Результаты:
# COMPUTERNAME_PASS.txt
# COMPUTERNAME_FAIL.txt
# COMPUTERNAME_PASS_WITH_WARNINGS.txt
# COMPUTERNAME.marker
# summary.txt
# ============================================================
# ------------------------------------------------------------
# НАСТРОЙКИ
# ------------------------------------------------------------
$ResultDirectory = "\\10.68.16.120\report\browser_password_check"
$SummaryFile = Join-Path $ResultDirectory "summary.txt"
$ComputerName = $env:COMPUTERNAME
# sqlite3.exe должен лежать рядом со скриптом
$ScriptDirectory = Split-Path -Parent $MyInvocation.MyCommand.Definition
$SqliteExe = Join-Path $ScriptDirectory "sqlite3.exe"
# Только сетевой marker
$MarkerFile = Join-Path $ResultDirectory ($ComputerName + ".marker")
# Временная директория
$TempDirectory = Join-Path $env:TEMP "BrowserPasswordAudit"
# ------------------------------------------------------------
# MARKER CHECK
# ------------------------------------------------------------
Write-Host "==============================================="
Write-Host " Browser Saved Password Audit"
Write-Host " Computer: $ComputerName"
Write-Host "==============================================="
Write-Host ""
Write-Host "Checking network marker..."
if (Test-Path $MarkerFile)
{
Write-Host "Marker already exists:"
Write-Host $MarkerFile
Write-Host ""
Write-Host "Audit was already completed. Exiting."
exit 0
}
Write-Host "Marker not found. Starting audit..."
Write-Host ""
# ------------------------------------------------------------
# ПРОВЕРКА SQLITE
# ------------------------------------------------------------
if (-not (Test-Path $SqliteExe))
{
Write-Host "ERROR: sqlite3.exe was not found:"
Write-Host $SqliteExe
exit 1
}
# ------------------------------------------------------------
# ПОДГОТОВКА TEMP
# ------------------------------------------------------------
if (Test-Path $TempDirectory)
{
Remove-Item $TempDirectory -Recurse -Force -ErrorAction SilentlyContinue
}
New-Item -Path $TempDirectory -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
# ------------------------------------------------------------
# ОБЩИЕ ПЕРЕМЕННЫЕ
# ------------------------------------------------------------
$TotalSavedPasswords = 0
$TotalWarnings = 0
$TotalFailures = 0
$Report = @()
$Report += "============================================================"
$Report += " Browser Saved Password Audit"
$Report += " Computer: $ComputerName"
$Report += " Date: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
$Report += "============================================================"
$Report += ""
$Report += "The audit checks actual saved password records in Chromium"
$Report += "Login Data SQLite databases."
$Report += "Password values are NOT extracted or written to the report."
$Report += ""
# ------------------------------------------------------------
# ПОЛУЧЕНИЕ ПРОФИЛЕЙ WINDOWS
# ------------------------------------------------------------
$UserDirectories = Get-ChildItem "C:\Users" -Directory -ErrorAction SilentlyContinue
if ($null -eq $UserDirectories)
{
$Report += "WARNING: Could not enumerate C:\Users"
$TotalWarnings++
}
# ------------------------------------------------------------
# ФУНКЦИЯ ПРОВЕРКИ Login Data
# ------------------------------------------------------------
function Test-LoginDatabase
{
param(
[string]$BrowserName,
[string]$DatabasePath,
[string]$UserName,
[string]$ProfileName
)
$Result = New-Object PSObject
$Result | Add-Member NoteProperty Browser $BrowserName
$Result | Add-Member NoteProperty User $UserName
$Result | Add-Member NoteProperty Profile $ProfileName
$Result | Add-Member NoteProperty Database $DatabasePath
$Result | Add-Member NoteProperty PasswordCount 0
$Result | Add-Member NoteProperty Status "PASS"
$Result | Add-Member NoteProperty Message ""
if (-not (Test-Path $DatabasePath))
{
$Result.Message = "Login Data not found"
return $Result
}
# --------------------------------------------------------
# Копируем БД во временный файл.
# Браузер может держать оригинал открытым.
# --------------------------------------------------------
$SafeUser = $UserName -replace '[^a-zA-Z0-9_-]', '_'
$SafeBrowser = $BrowserName -replace '[^a-zA-Z0-9_-]', '_'
$SafeProfile = $ProfileName -replace '[^a-zA-Z0-9_-]', '_'
$RandomPart = [Guid]::NewGuid().ToString("N")
$TempDatabase = Join-Path $TempDirectory (
$SafeBrowser + "_" +
$SafeUser + "_" +
$SafeProfile + "_" +
$RandomPart + ".db"
)
try
{
Copy-Item $DatabasePath $TempDatabase -Force -ErrorAction Stop
}
catch
{
$Result.Status = "WARNING"
$Result.Message = "Could not copy Login Data: " + $_.Exception.Message
return $Result
}
# --------------------------------------------------------
# SQL:
#
# Считаем только реальные записи с непустым password_value.
#
# blacklisted_by_user = 0
# исключает сайты, для которых сохранение пароля
# было запрещено пользователем.
# --------------------------------------------------------
$SqlQuery = "SELECT COUNT(*) FROM logins WHERE blacklisted_by_user = 0 AND password_value IS NOT NULL AND length(password_value) > 0;"
try
{
$Output = & $SqliteExe -readonly $TempDatabase $SqlQuery 2>&1
$ExitCode = $LASTEXITCODE
if ($ExitCode -ne 0)
{
$Result.Status = "WARNING"
$Result.Message = "SQLite query failed: " + (($Output | Out-String).Trim())
return $Result
}
$CountText = (($Output | Out-String).Trim())
$Count = 0
if (-not [int]::TryParse($CountText, [ref]$Count))
{
$Result.Status = "WARNING"
$Result.Message = "SQLite returned an unexpected value: " + $CountText
return $Result
}
$Result.PasswordCount = $Count
if ($Count -gt 0)
{
$Result.Status = "FAIL"
$Result.Message = "Saved passwords found: " + $Count
}
else
{
$Result.Status = "PASS"
$Result.Message = "No saved passwords found"
}
}
catch
{
$Result.Status = "WARNING"
$Result.Message = "Exception while checking SQLite database: " + $_.Exception.Message
}
finally
{
if (Test-Path $TempDatabase)
{
Remove-Item $TempDatabase -Force -ErrorAction SilentlyContinue
}
}
return $Result
}
# ------------------------------------------------------------
# ПРОВЕРКА БРАУЗЕРОВ
# ------------------------------------------------------------
$Browsers = @()
# Google Chrome
$Browsers += New-Object PSObject -Property @{
Name = "Google Chrome"
RelativePath = "AppData\Local\Google\Chrome\User Data"
}
# Microsoft Edge
$Browsers += New-Object PSObject -Property @{
Name = "Microsoft Edge"
RelativePath = "AppData\Local\Microsoft\Edge\User Data"
}
# Yandex Browser
$Browsers += New-Object PSObject -Property @{
Name = "Yandex Browser"
RelativePath = "AppData\Local\Yandex\YandexBrowser\User Data"
}
foreach ($UserDirectory in $UserDirectories)
{
$UserName = $UserDirectory.Name
# --------------------------------------------------------
# Служебные профили Windows пропускаем
# --------------------------------------------------------
if ($UserName -eq "All Users")
{
continue
}
if ($UserName -eq "Default")
{
continue
}
if ($UserName -eq "Default User")
{
continue
}
if ($UserName -eq "Public")
{
continue
}
$Report += "------------------------------------------------------------"
$Report += "Windows user: $UserName"
$Report += "------------------------------------------------------------"
foreach ($Browser in $Browsers)
{
$BrowserUserData = Join-Path $UserDirectory.FullName $Browser.RelativePath
if (-not (Test-Path $BrowserUserData))
{
$Report += ""
$Report += $Browser.Name + ": not installed / profile not found"
continue
}
# ----------------------------------------------------
# Получаем профили браузера:
#
# Default
# Profile 1
# Profile 2
# etc.
# ----------------------------------------------------
$BrowserProfiles = Get-ChildItem $BrowserUserData -Directory -ErrorAction SilentlyContinue
if ($null -eq $BrowserProfiles)
{
$Report += ""
$Report += $Browser.Name + ": no browser profiles found"
continue
}
foreach ($Profile in $BrowserProfiles)
{
$LoginData = Join-Path $Profile.FullName "Login Data"
# Проверяем только если Login Data существует
if (-not (Test-Path $LoginData))
{
continue
}
$Result = Test-LoginDatabase `
-BrowserName $Browser.Name `
-DatabasePath $LoginData `
-UserName $UserName `
-ProfileName $Profile.Name
$Report += ""
$Report += "Browser: $($Result.Browser)"
$Report += "User: $($Result.User)"
$Report += "Profile: $($Result.Profile)"
$Report += "Database: $($Result.Database)"
$Report += "Saved passwords: $($Result.PasswordCount)"
$Report += "Status: $($Result.Status)"
$Report += "Message: $($Result.Message)"
# ------------------------------------------------
# Общая статистика
# ------------------------------------------------
if ($Result.Status -eq "FAIL")
{
$TotalFailures++
$TotalSavedPasswords += $Result.PasswordCount
}
elseif ($Result.Status -eq "WARNING")
{
$TotalWarnings++
}
}
}
$Report += ""
}
# ------------------------------------------------------------
# ИТОГОВЫЙ СТАТУС
# ------------------------------------------------------------
$Report += ""
$Report += "============================================================"
$Report += " SUMMARY"
$Report += "============================================================"
$Report += "Total saved password records found: $TotalSavedPasswords"
$Report += "Failed checks: $TotalFailures"
$Report += "Warnings: $TotalWarnings"
$Report += ""
if ($TotalFailures -gt 0)
{
$OverallStatus = "FAIL"
}
elseif ($TotalWarnings -gt 0)
{
$OverallStatus = "PASS_WITH_WARNINGS"
}
else
{
$OverallStatus = "PASS"
}
$Report += "OVERALL STATUS: $OverallStatus"
$Report += "============================================================"
# ------------------------------------------------------------
# УДАЛЯЕМ TEMP
# ------------------------------------------------------------
if (Test-Path $TempDirectory)
{
Remove-Item $TempDirectory -Recurse -Force -ErrorAction SilentlyContinue
}
# ------------------------------------------------------------
# СОЗДАНИЕ ВРЕМЕННОГО ОТЧЕТА НА СЕТИ
# ------------------------------------------------------------
$TemporaryReport = Join-Path $ResultDirectory ($ComputerName + ".txt")
$FinalReport = Join-Path $ResultDirectory (
$ComputerName + "_" + $OverallStatus + ".txt"
)
$NetworkReportSaved = $false
try
{
$ReportDirectoryExists = Test-Path $ResultDirectory
if (-not $ReportDirectoryExists)
{
throw "Report directory is not accessible."
}
# Если старый временный файл остался
if (Test-Path $TemporaryReport)
{
Remove-Item $TemporaryReport -Force -ErrorAction Stop
}
$Report | Out-File `
-FilePath $TemporaryReport `
-Encoding UTF8 `
-Force `
-ErrorAction Stop
if (-not (Test-Path $TemporaryReport))
{
throw "Report file was not created."
}
# --------------------------------------------------------
# Переименование с добавлением статуса
# --------------------------------------------------------
if (Test-Path $FinalReport)
{
Remove-Item $FinalReport -Force -ErrorAction Stop
}
Rename-Item `
-Path $TemporaryReport `
-NewName ($ComputerName + "_" + $OverallStatus + ".txt") `
-ErrorAction Stop
if (-not (Test-Path $FinalReport))
{
throw "Final report was not found after rename."
}
$NetworkReportSaved = $true
}
catch
{
Write-Host ""
Write-Host "ERROR: Could not save report to network."
Write-Host $_.Exception.Message
}
# ------------------------------------------------------------
# ЕСЛИ ОТЧЕТ СОХРАНЕН НА СЕТИ —
# СОЗДАЕМ MARKER
# ------------------------------------------------------------
$MarkerCreated = $false
if ($NetworkReportSaved)
{
try
{
if (Test-Path $MarkerFile)
{
Remove-Item $MarkerFile -Force -ErrorAction SilentlyContinue
}
New-Item `
-Path $MarkerFile `
-ItemType File `
-Force `
-ErrorAction Stop | Out-Null
if (Test-Path $MarkerFile)
{
$MarkerCreated = $true
}
}
catch
{
Write-Host ""
Write-Host "WARNING: Report saved, but marker could not be created."
Write-Host $_.Exception.Message
}
}
# ------------------------------------------------------------
# SUMMARY.TXT
# ------------------------------------------------------------
if ($NetworkReportSaved)
{
try
{
Add-Content `
-Path $SummaryFile `
-Value ($ComputerName + " - " + $OverallStatus) `
-ErrorAction Stop
}
catch
{
Write-Host ""
Write-Host "WARNING: Could not update summary.txt"
Write-Host $_.Exception.Message
}
}
# ------------------------------------------------------------
# ФИНАЛЬНЫЙ ВЫВОД
# ------------------------------------------------------------
Write-Host ""
Write-Host "==============================================="
Write-Host " AUDIT COMPLETE"
Write-Host "==============================================="
Write-Host "Computer: $ComputerName"
Write-Host "Saved passwords found: $TotalSavedPasswords"
Write-Host "Warnings: $TotalWarnings"
Write-Host "Overall status: $OverallStatus"
if ($NetworkReportSaved)
{
Write-Host "Report: $FinalReport"
}
else
{
Write-Host "Report was NOT saved to network."
}
if ($MarkerCreated)
{
Write-Host "Marker: CREATED"
}
else
{
Write-Host "Marker: NOT CREATED"
}
Write-Host "==============================================="