Update SysvolSecAudit.ps1

Stable
This commit is contained in:
Dakhama mehdi 2024-05-24 21:41:00 +02:00 committed by GitHub
parent c64d3589f1
commit d9162430e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,14 +1,52 @@

function Find-SMSClearTextPassword {
<#
.SYNOPSIS
Sysvol Security Audit Module
.DESCRIPTION
This module is designed to scan the Sysvol folder for files containing sensitive information
such as passwords and usernames. It helps in identifying potential security risks within the Sysvol directory.
.VERSION
1.3.0
.Contribution
Loic, Bastien, Florian, Thirrey
.AUTHOR
Dakhama
.PARAMETER dnsDomain
Specifies the DNS domain to be scanned. Defaults to the current user's DNS domain if not provided.
.PARAMETER ignoreExtensions
Specifies file extensions to ignore during the scan.
.EXAMPLE
# Scan the Sysvol folder of the current domain
Invoke-SysvolSecurityAudit
# Scan the Sysvol folder of a specific domain, ignoring .txt and .log files
Invoke-SysvolSecurityAudit -dnsDomain "example.com" -ignoreExtensions "*.txt", "*.log"
.NOTES
This script requires administrative privileges to access and scan the Sysvol directory.
.LINK
https://github.com/dakhama-mehdi/CheckSysvolsecurity
#>
function Invoke-SysvolAudit {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $false)]
[String]$dnsDomain = $env:USERDNSDOMAIN,
[Parameter(Mandatory = $false)]
[String[]]$ignoreExtensions # Tableau pour stocker les extensions à ignorer
[String[]]$ignoreExtensions
)
#region code
# Tester l'acces au partage
$testpath = Test-Path "\\$dnsDomain\sysvol\"
if ($testpath -eq $false) {
@ -16,11 +54,15 @@ throw "Cannot access domain or share, pls check with GCI $dnsDomain"
}
# Tester la présence de module
if (!(Get-Module -ListAvailable -Name "PSWriteHTML"))
{
Write-Host "ReportHTML Module is not present, attempting to install it" -ForegroundColor Red
Install-Module -Name PSWriteHTML,PSWriteOffice,PSWritePDF -Force -Scope CurrentUser
Import-Module PSWriteHTML -ErrorAction SilentlyContinue
# Tester la présence des modules
$modulesToCheck = "PSWriteOffice", "PSWritePDF", "PSWriteHTML"
foreach ($module in $modulesToCheck) {
if (!(Get-Module -ListAvailable -Name $module)) {
Write-Output "installation du module $module"
Install-Module -Name $module -Force -Scope CurrentUser
} else {
Import-Module PSWriteHTML -Force
}
}
# Suppression de runspace "fantomes"
@ -28,23 +70,17 @@ $PreviousRS = get-runspace | where-object {($_.id -ne 1)}
if ($PreviousRS) { $PreviousRS.dispose() }
$Results = $null
# Début du script : obtenir la date et l'heure actuelles
$startDate = Get-Date
#region getxmlcontenant
# Récupérer les extensions de fichiers à partir du fichier XML
$xmlFileExtensions = "C:\temp\file_extensions.xml"
$extensionsXML = [xml](Get-Content $xmlFileExtensions)
$fileExtensions = $extensionsXML.FileExtensions.Extension
$extensionsXML = [xml](Get-Content $xmlFileExtensions -Encoding UTF8)
$fileExtensions = $extensionsXML.root.FileExtensions.Extension
# Récupérer les motifs de mots de passe à partir du fichier XML
$xmlPasswordPatterns = "C:\temp\password_patterns.xml"
$passwordPatternsXML = [xml](Get-Content $xmlPasswordPatterns -Encoding UTF8)
$passwordPatterns = $passwordPatternsXML.PasswordPatterns.Pattern
# Récupérer les fichiers dans les dossiers Sysvol du domaine DNS spécifié
#$sysvolFolders = Get-ChildItem -Path "\\$dnsDomain\sysvol" -Recurse -File -Include $fileExtensions -ErrorAction SilentlyContinue
$passwordPatterns = $extensionsXML.root.PasswordPatterns.Pattern
# Initialiser une liste pour stocker les résultats
$Results = @()
@ -75,8 +111,8 @@ $scriptblock = {
if ($var) {
$result = [PSCustomObject]@{
FilePath = $sysfiles
pattern = ''
Word = $pattern
pattern = $pattern
Word = ''
}
$results += $result
}
@ -95,8 +131,8 @@ $scriptblock = {
if ($var) {
$result = [PSCustomObject]@{
FilePath = $sysfiles
pattern = ''
Word = $pattern
pattern = $pattern
Word = ''
}
$results += $result
}
@ -112,14 +148,103 @@ $scriptblock = {
if ($text -match $pattern) {
$result = [PSCustomObject]@{
FilePath = $sysfiles
pattern = ''
Word = $pattern
pattern = $pattern
Word = ''
}
$results += $result
}
}
$results # Retourne tous les résultats à la fin du scriptblock
}
'.xml' = {
$results = @() # Initialisation de la variable $results dans le scriptblock
$xmlContent = Get-Content -Path $sysfiles -Raw
# Vérifier si le fichier contient "cpassword"
if ($xmlContent -match 'cpassword') {
$xml = [xml]$xmlContent
# Vérifier le contenu du fichier pour déterminer comment le traiter
if ($xml.Groups.User) {
$cpasswords = $xml | Select-Xml "/Groups/User/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} elseif ($xml.NTServices.NTService) {
$cpasswords = $xml | Select-Xml "/NTServices/NTService/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} elseif ($xml.ScheduledTasks.Task) {
$cpasswords = $xml | Select-Xml "/ScheduledTasks/Task/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} elseif ($xml.DataSources.DataSource) {
$cpasswords = $xml | Select-Xml "/DataSources/DataSource/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} elseif ($xml.Printers.SharedPrinter) {
$cpasswords = $xml | Select-Xml "/Printers/SharedPrinter/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
} elseif ($xml.Drives.Drive) {
$cpasswords = $xml | Select-Xml "/Drives/Drive/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value}
}
# Ajouter les résultats à la liste des résultats
$result = [PSCustomObject]@{
FilePath = $sysfiles
Pattern = 'cpassword'
Word = $cpasswords
}
$results += $result
}
elseif ($xmlContent -match 'DefaultUserName') {
# Autre traitement pour les fichiers XML sans cpassword
$xml = [xml]$xmlContent
# Initialiser les variables
$userName = ""
$password = ""
# Vérifier et extraire les valeurs
foreach ($registry in $xml.RegistrySettings.Registry) {
if ($registry.Properties.name -eq "DefaultUserName") {
$userName = $registry.Properties.value
}
if ($registry.Properties.name -eq "DefaultPassword") {
$password = $registry.Properties.value
}
}
# Retourner les résultats
$result = [PSCustomObject]@{
FilePath = $sysfiles
Pattern = 'AutoLogon'
Word = "$userName : $password"
}
$results += $result
}
else {
$xml = [xml]$xmlContent
foreach ($pattern in $passwordPatterns) {
$matches = $xmlContent | Select-String -Pattern $pattern
foreach ($match in $matches) {
$result = [PSCustomObject]@{
FilePath = $sysfiles
Pattern = $pattern
Word = $match.Matches.Value
}
$results += $result
}
}
}
return $results # Retourne tous les résultats à la fin du scriptblock
}
'.exe' = {
$results = @() # Initialisation de la variable $results dans le scriptblock
if ( (Get-AuthenticodeSignature -FilePath $sysfiles).status -ne "Valid") {
$result = [PSCustomObject]@{
FilePath = $sysfiles
pattern = "NotSigned"
Word = 'NotSigned'
}
$results += $result
}
$results
}
default = {
$results = @() # Initialisation de la variable $results dans le scriptblock
$matches = Select-String -Path $sysfiles -Pattern $passwordPatterns -AllMatches
@ -141,9 +266,7 @@ $scriptblock = {
$results += $result
}
if ($n -eq 2) {
# Retourne tous les résultats à la fin du scriptblock
if ($n -eq 4) {
break;
}
}
@ -152,31 +275,35 @@ $scriptblock = {
}
}
# Obtenir l'extension du fichier
$extension = [System.IO.Path]::GetExtension($sysfiles).ToLower()
# Exécuter la commande appropriée en fonction de l'extension du fichier
if ($extension -like '*.doc*' -and $fileCommands.ContainsKey('.docx')) {
& $fileCommands['.docx']
}
if ($fileCommands.ContainsKey($extension)) {
& $fileCommands[$extension]
} else {
& $fileCommands['default']
}
# Obtenir le nom du fichier
$fileName = Split-Path -Leaf $sysfiles
# Utiliser un switch pour exécuter la commande appropriée en fonction du nom du fichier
switch -Wildcard ($fileName) {
'*.doc*' { & $fileCommands['.docx'] }
'*.exe' { & $fileCommands['.exe'] }
'*.msi' { & $fileCommands['.exe'] }
'*.xlsx*' { & $fileCommands['.xlsx'] }
'*.pdf*' { & $fileCommands['.pdf'] }
'*.xml*' { & $fileCommands['.xml'] }
default { & $fileCommands['default'] }
}
}
$fichiertraite = 0
# creation des jobs par machine et lancement des jobs
Get-ChildItem -Path \\$dnsDomain\sysvol -Recurse -File -Include $fileExtensions -Exclude $ignoreExtensions -Force -ErrorAction Continue | ForEach-Object {
Get-ChildItem -Path \\$dnsDomain\sysvol -Recurse -File -Include $fileExtensions -Exclude $ignoreExtensions -Force -ErrorAction SilentlyContinue -ErrorVariable notacess | ForEach-Object {
if ($notacess) { Write-Host $notacess -ForegroundColor Red; $notacess = $null }
$fichiertraite++
$sysfiles = $_.FullName
#clear
Write-Host nous traitons $sysfiles
Write-Host Scanne : $sysfiles -ForegroundColor Cyan
$runspace = [PowerShell]::Create()
$null = $runspace.AddScript($scriptblock)
@ -191,7 +318,7 @@ $runspaces += [PSCustomObject]@{ Pipe = $runspace; Status = $runspace.BeginInvok
while ($runspaces.Status -ne $null)
{
start-sleep 1
#cls
cls
get-runspace | where-object {($_.id -ne 1) -and ($_.runspaceisremote -eq $false) -and ($_.runspaceAvailability -like "Available")}
get-runspace | where-object {($_.id -ne 1) -and ($_.runspaceisremote -eq $true)}
$slt_encours = get-runspace | where-object {($_.id -ne 1) -and ( $_.runspaceisremote -eq $true)}
@ -212,16 +339,14 @@ foreach ($runspace in $completed)
}
# Regroupement :
#region Top5
#region Summary
$sortedGroups = $Results.filepath | Group-Object | Sort-Object -Property Count -Descending
# Sélectionner les 5 premiers groupes
$top5Groups = $sortedGroups | Select-Object Count,Name -First 5
# Afficher les 5 premiers groupes
$commonPath = "\\ENI.LOCAL\sysvol\eni.local"
$commonPath = "\\$dnsDomain\sysvol\$dnsDomain"
$top5Groups = $top5Groups | ForEach-Object {
$_.Name = $_.Name -replace [regex]::Escape($commonPath), ''
$_
@ -229,6 +354,7 @@ $top5Groups = $top5Groups | ForEach-Object {
# Top 5 word
$top5Words= $Results.pattern | Group-Object | Sort-Object -Property Count -Descending | Select-Object Count,name -First 5
$Allwords = $Results.pattern | Group-Object | Sort-Object -Property Count -Descending | Select-Object Count,name
#nombre d'objet max
$objettrouve = $sortedGroups.Count
@ -243,15 +369,58 @@ $endDate = Get-Date
$elapsedTime = New-TimeSpan -Start $startDate -End $endDate
$elapsedTime = $($elapsedTime.ToString("hh\:mm\:ss"))
#endregion Top5
# Calcul potentiel risk
# Supposons que $top5Groups, $Allwords et $objettrouve soient déjà définis
$totalRisk = 0
# Évaluer le risque basé sur le nombre de fichiers contenant des mots de passe
if ($objettrouve -gt 10) {
$totalRisk += 30
} else {
$totalRisk += ($objettrouve/10) * 30
}
# Parcourir les mots-clés dans $Allwords et ajuster le score de risque
foreach ($word in $Allwords) {
switch -Regex ($word.Name) {
"Password|Pass|motdepasse|\bpass\b|\bpwd\b" {
$totalRisk += 5 * $word.Count
break
}
"cpassword" {
$totalRisk += 20 * $word.Count
break
}
"net use|NotSigned|\bidentifiant\b" {
$totalRisk += 5 * $word.Count
break
}
"AutoLogon" {
$totalRisk += 20 * $word.Count
break
}
"credentials|\bsecret\b" {
$totalRisk += 5 * $word.Count
break
}
}
}
# Limiter le score de risque à 100%
if ($totalRisk -gt 100) {
$totalRisk = 100
}
#endregion Summary
# Fermeture les connexions et suppression des slots du Pool
$pool.Close()
$pool.Dispose()
#endregion code
# Generation du rapport HTML
New-HTML -TitleText 'AD_ModernReport' -ShowHTML {
New-HTMLHeader {
New-HTMLText -LineBreak
New-HTMLSection -Invisible {
@ -270,14 +439,12 @@ New-HTMLHeader {
}
New-HTMLText -LineBreak
}
New-HTMLTab -Name 'Dashboard' -IconRegular chart-bar {
New-HTMLSection {
New-HTMLTableOption -DataStore JavaScript
New-htmlTable -HideFooter -DataTable $Results -TextWhenNoData 'Information: No Groups were found'
}
New-HTMLSection {
New-HTMLPanel {
New-HTMLPanel -Width "60%" {
New-HTMLChart -Gradient -Title 'Total traitement' -TitleAlignment center -Height 200 {
@ -298,35 +465,60 @@ New-HTMLHeader {
}
}
New-HTMLPanel {
New-HTMLChart -Title 'Top 5 Files' -TitleAlignment center {
New-ChartToolbar -Download pan
New-ChartBarOptions -Gradient
New-ChartLegend -Name $top5Groups.name[0],$top5Groups.name[1],$top5Groups.name[2],$top5Groups.name[2],$top5Groups.name[2] -HideLegend
New-ChartBar -Name 'Patch extensions' -Value $top5Groups.GetEnumerator().count[0],$top5Groups.GetEnumerator().count[1],$top5Groups.GetEnumerator().count[2],$top5Groups.GetEnumerator().count[2],$top5Groups.GetEnumerator().count[2]
New-ChartBar -Name 'Patch' -Value $top5Groups.GetEnumerator().count[0],$top5Groups.GetEnumerator().count[1],$top5Groups.GetEnumerator().count[2],$top5Groups.GetEnumerator().count[2],$top5Groups.GetEnumerator().count[2]
}
}
New-HTMLPanel {
New-HTMLChart -Title 'Top 5 Word' -TitleAlignment center {
New-ChartToolbar -Download pan
New-ChartBarOptions -Gradient
New-ChartLegend -Name $top5Words.name[0],$top5Words.name[1],$top5Words.name[2],$top5Words.name[3],$top5Words.name[4] -HideLegend
New-ChartBar -Name 'Patch extensions' -Value $top5Words.GetEnumerator().count[0],$top5Words.GetEnumerator().count[1],$top5Words.GetEnumerator().count[2],$top5Words.GetEnumerator().count[3],$top5Words.GetEnumerator().count[4]
New-ChartBar -Name 'Word' -Value $top5Words.GetEnumerator().count[0],$top5Words.GetEnumerator().count[1],$top5Words.GetEnumerator().count[2],$top5Words.GetEnumerator().count[3],$top5Words.GetEnumerator().count[4]
}
}
}
}
New-HTMLTab -Name 'Resume' -IconSolid user-alt {
New-HTMLSection -Width "60%" -HeaderBackGroundColor Teal -name 'Groups Without members' {
New-HTMLPanel -Width "40%" {
New-HTMLGage -Label 'Indicator Risk' -MinValue 0 -MaxValue 100 -Value $totalRisk -ValueColor Black -LabelColor Black -Pointer -StrokeColor Akaroa -SectorColors AirForceBlue
}
New-HTMLPanel {
New-HTMLTabPanel -Orientation vertical -Theme 'pills' {
New-HTMLTab -Name 'Why check Sysvol 2.1' -IconBrands 500px {
New-HTMLText -FontSize 20px -Text "The Sysvol folder is crucial for distributing scripts and Group Policy Objects (GPOs) to all domain computers.
It may contain sensitive information, such as plain-text passwords, making it a prime target for attackers. <br>A vulnerability in Sysvol can compromise the entire domain. Therefore, it is essential to restrict permissions, monitor changes, and regularly audit its contents to ensure network security and compliance."
}
New-HTMLTab -Name 'Audit GPO 2.2' -IconBrands 500px {
New-HTMLText -FontSize 20px -Text "Regularly audit GPOs to verify their contents, such as plain-text passwords in configuration files or auto-logon scripts, and the presence of unsigned sources. <br>Frequently run the GPOZaurr tool, which provides a comprehensive report to help identify and mitigate these risks.
<br>[GPOZaurr](https://github.com/EvotecIT/GPOZaurr/)<br>"
}
New-HTMLTab -Name 'Best Pratic 2.3' -IconBrands 500px {
New-HTMLText -FontSize 20px -Text "Enable audits on the Sysvol folder and monitor logs for multiple search attempts, as this may indicate enumeration attempts. Some elements in the Sysvol folder are not meant to be accessed by everyone. If possible, place a honeypot script in the Netlogon folder to trigger alerts for suspicious activity.
<br>[Autologon](https://learn.microsoft.com/fr-fr/sysinternals/downloads/autologon/)<br>"
}
New-HTMLTab -Name 'Tips 2.4' -IconBrands 500px {
New-HTMLText -FontSize 20px -Text "Do not store large files, such as ISO or .zip files, in the Sysvol folder. This can lead to replication issues and unnecessary consumption of storage resources, impacting the performance and reliability of your network<br> Move your scripts to a shared folder and grant access only to the relevant groups, not authenticated users. This will reduce vulnerabilities, especially if the scripts contain credentials or deploy critical applications."
}
New-HTMLTab -Name 'Hardening AD 2.4' -IconBrands 500px {
New-HTMLText -Color Green -FontSize 10px -Text "Use AD hardening to ensure security and reduce risks. Disable old protocols like SMB1 and anonymous enumeration on DC shares. Implement an N-tier architecture model, a PAW, and Silos.
To facilitate this, refer to the HardenAD project.
<br>[HardenAD](https://github.com/LoicVeirman/HardenAD*/)<br>"
}
}
}
}
}
}
return $Results
#return $Results
}
# Appeler la fonction pour trouver les mots de passe en texte clair dans les fichiers Sysvol
$var= Find-SMSClearTextPassword
#Invoke-SysvolAudit