Serveur d'impression

Rechercher et verrouiller les autorisations de partage Windows laxistes – Bien choisir son serveur d impression

Le 4 mai 2020 - 12 minutes de lecture

Garder vos données en sécurité et à l'abri des utilisateurs non autorisés est une tâche complexe, qui peut être encore plus difficile si un paramètre par défaut dans Windows vous gêne.

Essayer de sécuriser les autorisations de partage Windows est un gros défi en raison d'un paramètre appelé contournement de la vérification qui vérifie que le système d'exploitation est activé par défaut. Ce paramètre donne accès aux dossiers même si l'utilisateur n'a de droits d'accès à aucun de ses parents.

Nous pouvons supprimer cette autorisation avec le paramètre d'objet de stratégie de groupe, mais elle est là pour une raison. Sans ce paramètre activé, vous constaterez une baisse importante des performances car Windows vérifiera chaque dossier parent pour voir si l'utilisateur est autorisé à accéder à la cible.

Cet article explique comment créer un rapport sur les autorisations de partage Windows pour déterminer quels utilisateurs ont des autorisations excessives et comment le réparer à l'aide de PowerShell et de Sysinternals.

Rassembler les partages de fichiers et leurs utilisateurs autorisés

Tout d'abord, nous devons trouver les partages de fichiers sur les serveurs et les systèmes clients. Nous pourrions le faire soit en utilisant le Get-SmbShare ou en appelant l'espace de noms win32_share à l'aide de Get-CimInstance ou Get-WmiObject.

Pour cet exemple, Get-WmiObject est le moyen préféré de récupérer nos actions, car il s'agit d'une approche plus rationalisée. Lancez le terminal PowerShell en tant qu'administrateur sur un serveur de fichiers et entrez la commande suivante:

Get-WMIObject -Class win32_share

Nom Chemin Description
---- ---- -----------
MyShare C: demo share Partage de démonstration
ADMIN $ C: Administrateur distant WINDOWS
C C:
C $ C: Partage par défaut
D $ D: Partage par défaut
E $ E: Partage par défaut
IPC $ IPC distant
imprimer $ C: WINDOWS system32 spool drivers Pilotes d'imprimante
scripts C: scripts

La commande PowerShell génère tous les partages, mais elle ne montre pas aux utilisateurs qui y ont accès. En effet, les autorisations de partage Windows résident dans un autre espace de noms appelé Win32_LogicalShareSecuritySetting:

Get-WmiObject -Class Win32_LogicalShareSecuritySetting

Cette sortie résultante ne nous dit pas grand-chose non plus. Nous avons besoin d'un script PowerShell plus complet pour générer quelque chose de plus utile:

# Obtenez tous les partages sur l'ordinateur
$ Shares = Get-WMIObject -Class win32_share

# Variable aux actions traitées.
$ NetworkShares = [System.Collections.Generic.List[PSCustomObject]]::Nouveau()

# Ignorez les partages par défaut en filtrant '2147483648'
foreach ($ Part en $ Actions |? $ _. Tapez -ne '2147483648' -et $ _. Nom -ne 'print $') {

# Créez un objet que nous retournerons
$ ShareObject = [PSCustomObject]@
Nom = $ Share.Name
Description = $ Share.Description
LocalPath = $ Share.Path
ACL = [System.Collections.ArrayList]::Nouveau()


# Obtenez les paramètres de sécurité pour le partage
$ ShareSecurity = Get-WmiObject -Class Win32_LogicalShareSecuritySetting -Filter "name = '$ ($ Share.Name)'" "

# Si des paramètres de sécurité existent, créez une liste avec les ACL
if ($ Null -ne $ ShareSecurity)
Essayer
$ SecurityDescriptor = $ ShareSecurity.GetSecurityDescriptor (). Descriptor

foreach ($ AccessControl dans $ SecurityDescriptor.DACL) Out-Null

# Renvoyer l'objet de partage avec les ACL
$ NetworkShares.Add ($ ShareObject)

Capture
Erreur d'écriture $ Erreur[0]


Autre
Write-Information "Aucune autorisation trouvée pour $ ($ Share.Name) sur $ ComputerName"

}

Le contenu du $ NetworkShares La variable devrait finir par ressembler à ce qui suit:

PS51> $ NetworkShares

Nom Description LocalPath ACL
---- ----------- --------- ---
DemoShare Demo share C: demo share System.Security.AccessControl.FileSystemAccessRule
scripts C: scripts System.Security.AccessControl.FileSystemAccessRule, System.Security.AccessControl.FileSystemAccessRule

PS51> $ NetworkShares[0].ACL

FileSystemRights: FullControl
AccessControlType: Autoriser
IdentityReference: Tout le monde
IsInherited: False
InheritanceFlags: Aucun
PropagationFlags: Aucun

Nous avons réussi à collecter des données sur nos autorisations de partage Windows, montrant qui a accès à quoi. Cela peut ne pas être suffisant car les administrateurs attribuent généralement des autorisations de partage réseau au niveau NTFS, pas au niveau du partage réseau.

Nous devons également vérifier les fichiers et dossiers du partage s'il existe des autorisations excessives pour d'autres groupes, tels que Tout le monde ou Utilisateurs de domaine.

Analyse des autorisations de fichiers à l'aide d'AccessChk

Nous avons une liste de nos partages de fichiers. Ensuite, nous devons obtenir toutes les autorisations de fichier. La méthode la plus rapide consiste à utiliser l'utilitaire de fichiers AccessChk de la suite Sysinternals et à analyser la sortie avec PowerShell.

Placez AccessChk sur votre serveur de fichiers et copiez le fichier AccessChk64.exe dans votre dossier system32. Vous pouvez télécharger l'utilitaire à partir du lien ci-dessus ou utiliser le code PowerShell suivant pour le télécharger et le copier dans votre dossier system32:

Invoke-WebRequest -OutFile $ env: TEMP  AccessChk.zip -Uri https://download.sysinternals.com/files/AccessChk.zip 
Expand-Archive -Path $ env: TEMP AccessChk.zip -DestinationPath $ env: TEMP -Force
Copy-Item -Path $ env: TEMP AccessChk64.exe C: Windows System32 AccessChk64.exe

Nous pouvons utiliser PowerShell pour créer une fonction wrapper autour d'AccessChk à utiliser dans un script:

Fonction Invoke-AccessChk {
param (
$ Path,
$ Directeurs,
$ AccessChkPath = "$ env: windir system32 accesschk64.exe",
[switch]$ Répertoires
[switch]$ AcceptEula

)

# Accepter le CLUF
if ($ AcceptEula)
& $ AccessChkPath / accepteula

$ Argument = "uqs"
if ($ DirectoriesOnly)
$ Argument = "udqs"

$ Output = & $ AccessChkPath -nobanner - $ Argument $ Path

Foreach ($ Row dans $ Output)

# Si c'est une ligne avec un chemin de fichier, sortez l'objet précédent et créez-en un nouveau
if ($ Row -match "^ S")
If ($ Null -ne $ Object)
if ($ Object.Access.Keys.Count -gt 0)
$ Object


$ Object = [PSCustomObject]@
Chemin = $ Ligne
Accès = @

# S'il s'agit d'une ligne avec des autorisations
if ($ Row -match "^ [R ][W ]") "))

$ Row -match "^ (?[R ]) (?[W ]) (?. *) "


# Si c'est la dernière ligne - sortez l'objet une fois de plus
if ($ Object.Access.Keys.Count -gt 0)
$ Object

}

Nous pouvons maintenant courir Invoke-AccessChk avec les partages réseau stockés dans le $ NetworkShares variable de l'étape précédente. Nous ajoutons à une liste des principaux de sécurité – sans "domaine" – pour trouver:

# Invoke-AccessChk ne sortira que les fichiers / dossiers où les principaux suivants ont l'autorisation:
$ RiskPrincipals = @ (
'Toutes les personnes',
«Utilisateurs du domaine»,
«Ordinateurs de domaine»,
'Utilisateurs authentifiés',
'Utilisateurs'
)

$ RiskyPermissions = Foreach ($ NetworkShare in $ NetworkShares | Select -First 1) ? $ _ -In $ RiskPrincipals)

if ($ RiskPrincipalExist)
Invoke-AccessChk -Path $ NetworkShare.LocalPath -Principals $ RiskPrincipals

le $ RiskyPermissions La variable donnera une sortie similaire à ceci:

PS51> $ RiskyPermissions

Accès au chemin
---- ------
C: demo share File1.txt BUILTIN Users, NT AUTHORITY Authenticated Users
C: demo share Folder1 picture.png AUTORITÉ NT Utilisateurs authentifiés
C: demo share Folder1 Folder2 AUTORITÉ NT Utilisateurs authentifiés

PS51> $ RiskyPermissions[0].Accès

Création d'un rapport à partir de plusieurs ordinateurs et serveurs

Jusqu'à présent, vous pouvez obtenir une liste de tous les partages de fichiers et vérifier tous les fichiers avec le wrapper PowerShell pour Invoke-AccessChk. L'une des nombreuses forces de PowerShell est sa capacité à évoluer. La communication à distance PowerShell portera le code que nous avons produit au niveau supérieur pour recueillir les informations de plusieurs ordinateurs à la fois.

Tout d'abord, nous avons besoin d'une liste d'ordinateurs et de serveurs à analyser. Si possible, le moyen le plus simple consiste à utiliser le module Active Directory de RSAT:

$ Computers = (Get-ADComputer -Filter *). DnsHostName

Cette méthode n'est peut-être pas une option dans les environnements plus vastes fortement segmentés. Une autre approche consiste à obtenir des données de votre base de données de gestion de configuration ou à les saisir manuellement à l'aide de l'exemple suivant:

$ Ordinateurs = @ (
'Server1',
«Server2»,
«Server3»,
«Server4»,
«Server5»,
«PC1»
# etc
)

Il est maintenant temps de lier tous ces composants dans un script qui utilise des travaux d'arrière-plan PowerShell pour effectuer les actions suivantes sur les machines spécifiées dans le $ Ordinateurs paramètre:

  • Obtenez tous les partages partagés avec l'un des principaux dans $ RiskPrincipals.
  • Téléchargez AccessChk s'il n'existe pas déjà.
  • Vérifiez l'autorisation NTFS de tous les partages rassemblés par AccessChk.
  • Renvoyer un objet avec une liste avec tous les fichiers où les principaux de sécurité dans $ RiskPrincipals avoir des autorisations de lecture ou d'écriture.

L'ordinateur exécutant le script collectera ensuite les résultats de tous les travaux et les affichera dans un fichier CSV portant le nom ShareAccessReport.

N'oubliez pas d'exécuter ce qui suit en tant qu'administrateur sur un ordinateur disposant d'un accès réseau auxdites machines et d'accepter le CLUF pour AccessChk en modifiant $ AcceptEula à vrai:

$ Ordinateurs = @ (
«Serveur-1»,
«Serveur-2»,
«PC-1»
)

# Accepter le CLUF pour AccessChk
# CHANGER EN VRAI
$ AcceptEula = $ false

if (! $ AcceptEula)
Write-Warning "N'a pas accepté le CLUF pour AccessChk, ne peut pas continuer"
Pause

# Principaux que nous voulons rechercher
$ RiskPrincipals = @ (
'Toutes les personnes',
«Utilisateurs du domaine»,
«Ordinateurs de domaine»,
'Utilisateurs authentifiés',
'Utilisateurs'
)

# Liste des partages que nous voulons ignorer.
# Définir un nom de partage lié juste au cas où, car il devrait presque toujours être ce chemin
$ IgnoreShares = @ (
'print $'
)

# Scriptblock que nous enverrons avec Invoke-Command
$ Scriptblock = {

$ RiskPrincipals = $ args[0].RiskPrincipals
$ IgnoreShares = $ args[1].IgnoreShares
$ AcceptEula = $ args[2].AccepterEula

# Fonctions pour télécharger et utiliser AccessChk
# Il utilise un objet shell au lieu de Expand-Archive pour une compatibilité descendante
Fonction Download-AccessChk
param (
$ Url = "https://download.sysinternals.com/files/AccessChk.zip",
$ Dest = $ env: temp
)
if (Test-Path "$ dest accesschk.zip")
rm $ Dest AccessCHK.zip -Force

(New-Object System.Net.WebClient) .DownloadFile ($ url, "$ env: temp AccessChk.zip")
$ Shell = New-Object -ComObject Shell.Application
$ Zip = $ shell.NameSpace ("$ env: temp AccessChk.zip")
$ Destination = $ shell.NameSpace ("$ env: windir system32 ")

$ copyFlags = 0x00
$ copyFlags + = 0x04
$ copyFlags + = 0x10

$ Destination.CopyHere ($ Zip.Items (), $ copyFlags)

# La fonction qui utilise accesschk de la partie 2
Fonction Invoke-AccessChk {
param (
$ Path,
$ Directeurs,
$ AccessChkPath = "$ env: windir system32 accesschk64.exe",
[switch]$ Répertoires
[switch]$ AcceptEula

)

if (! (Test-Path "$ env: windir system32 accesschk64.exe"))
Download-AccessChk

# Accepter le CLUF
if ($ AcceptEula)
& $ AccessChkPath / accepteula

$ Argument = "uqs"
if ($ DirectoriesOnly)
$ Argument = "udqs"

$ Output = & $ AccessChkPath -nobanner - $ Argument $ Path

Foreach ($ Row dans $ Output)

# Si c'est une ligne avec un chemin de fichier, sortez l'objet précédent et créez-en un nouveau
if ($ Row -match "^ S")
If ($ Null -ne $ Object)
if ($ Object.Access.Keys.Count -gt 0)
$ Object


$ Object = [PSCustomObject]@
Chemin = $ Ligne
Accès = @

# S'il s'agit d'une ligne avec des autorisations
if ($ Row -match "^ [R ][W ]") ")) Out-Null

$ Object.Access[$Matches.Principal] = @
Read = $ Matches.Read -eq 'R'
Write = $ Matches.Read -eq 'W'




# Si c'est la dernière ligne - sortez l'objet une fois de plus
if ($ Object.Access.Keys.Count -gt 0)
$ Object

}

# Obtenez tous les partages en utilisant WMI
$ Shares = Get-WmiObject -Class win32_share

# Créez un objet que nous reviendrons plus tard lorsque nous aurons terminé
$ ReturnObject = [PSCustomObject]@
ComputerName = $ ComputerName
NetworkShares = [System.Collections.Generic.List[PSCustomObject]]::Nouveau()
AccessibleObjects = @

# Ignorez les partages par défaut en filtrant '2147483648'
# Ignorer les parts de $ IgnoreShares
foreach ($ Part en $ Actions |? $ _. Tapez -ne '2147483648' |? $ _. Nom -notin $ IgnoreShares) {
$ ShareObject = [PSCustomObject]@
Nom = $ Share.Name
Description = $ Share.Description
LocalPath = $ Share.Path
ACL = [System.Collections.ArrayList]::Nouveau()

$ ShareSecurity = Get-WMIObject -Class Win32_LogicalShareSecuritySetting -Filter "name = '$ ($ Share.Name)'" "
if ($ Null -ne $ ShareSecurity) {
Essayer
$ SecurityDescriptor = $ ShareSecurity.GetSecurityDescriptor (). Descriptor

foreach ($ AccessControl dans $ SecurityDescriptor.DACL) Out-Null

# Ajouter un partage réseau uniquement s'il contient un utilisateur / groupe à risque

$ Match = $ False
Foreach ($ IdentityReference dans $ ShareObject.ACL.IdentityReference.Value)
Foreach ($ Pattern in $ RiskPrincipals)
if ($ IdentityReference -Match $ Pattern)
$ Match = $ True



if ($ Match)
$ ReturnObject.NetworkShares.Add ($ ShareObject)

Autre
Write-Verbose "Aucune correspondance pour les groupes à risque, n'ajoutant pas"



Capture
Erreur d'écriture $ Erreur[0]

}
Autre
Write-Information "Aucune autorisation trouvée pour $ ($ Share.Name) sur $ ComputerName"


}
# Obtenez tous les fichiers de NetworkShares où un principal de $ RiskPrincipals a un accès en lecture ou en écriture
$ ReturnObject.NetworkShares | Pour chaque
$ ReturnObject.AccessibleObjects[$_.Name] = Invoke-AccessChk -Path $ _. LocalPath -Principals $ RiskPrincipals -AcceptEula: $ AcceptEula

# Terminé! Permet de renvoyer l'objet de retour:
$ ReturnObject
}

# À ajouter à la liste d'arguments d'Invoke-Job car le travail PowerShell distant n'a pas accès à notre espace variable.
$ InvokeParam = @
RiskPrincipals = $ RiskPrincipals
IgnoreShares = $ IgnoreShares
AcceptEula = $ AcceptEULA

# Commencer les travaux
$ Job = Invoke-Command -AsJob -ComputerName $ Computers -ArgumentList $ InvokeParam -ScriptBlock $ Scriptblock

# Attendez la fin des travaux
$ Job | Wait-Job

# Collecte des données de tous les travaux
$ Output = Get-Job | Receive-Job

# Sortie de la sortie dans un CSV
$ ToCSV = Foreach ($ Résultat dans $ Output) {

Foreach ($ Entrez $ Result.AccessibleObjects.Keys) Sélectionnez @ Name = 'ShareName'; Expression = $ Key, Path, $ ReadAccess, $ WriteAccess

}
# Exporter le CSV
$ ToCSV | Export-Csv -Path. ShareAccessReport.csv

Lorsque le travail PowerShell se termine, il crée un rapport complet de l'accès des principaux dans le $ RiskyPrincipals variable.

Correction des autorisations de partage Windows

Après avoir examiné le CSV et trouvé les autorisations qui doivent être ajustées, il existe deux façons de les corriger. S'il n'y en a que quelques-uns, le meilleur moyen est d'utiliser l'interface graphique. Mais s'il y en a des milliers, la commande suivante utilisera la sortie CSV pour accélérer cela:

# Cela doit s'exécuter localement sur le serveur avec le partage de fichiers.

$ UserToRemove = 'Invité'
$ CSV = Import-Csv -Path. ShareAccessReport.csv | ?
$ CSV | ? $ _. ComputerName -eq $ env: COMPUTERNAME | Pour chaque
$ ACL = Get-Acl -Path $ _. Path
$ ACL.Access

Ce script PowerShell supprimera toutes les autorisations du principal de sécurité invité.

Le premier rapport apportera généralement beaucoup de travail car il découvrira beaucoup de bizarreries et de risques en ce qui concerne vos autorisations de partage Windows. Mais la gestion régulière d'une solution comme celle-ci, spécialement destinée aux partages contenant des informations sensibles, sera finalement payante.

Commentaires

Laisser un commentaire

Votre commentaire sera révisé par les administrateurs si besoin.