guest@6admin.io:~$

L'ExecutionPolicy PowerShell et ce qu'elle n'est pas

La phrase la plus utile sur l’ExecutionPolicy est celle que Microsoft inscrit dans sa propre documentation: ce n’est pas une frontière de sécurité. C’est une ceinture contre le double-clic sur un script qu’on ne voulait pas lancer, rien de plus et la prendre pour un contrôle qui tient l’attaquant à distance est une erreur de catégorie qui masque les vrais leviers. La façon honnête de la traiter est donc de dire ce qu’elle fait, de prouver à quel point c’est peu, puis de pointer ce qui contraint réellement PowerShell.

Les niveaux, en bref

PolitiqueEffet
Restrictedaucun script (défaut client)
AllSignedtout script doit être signé
RemoteSignedles scripts locaux tournent, les téléchargés doivent être signés
Unrestrictedtout tourne, avec invite pour les fichiers téléchargés
Bypasstout tourne, sans invite
Undefinedhérite du scope suivant

La valeur effective est la plus restrictive parmi les scopes, qui par ordre de priorité décroissant sont les deux scopes de stratégie de groupe, puis Process, CurrentUser et LocalMachine. Pour un parc de postes, RemoteSigned par stratégie de groupe est le défaut sensé: l’automatisation locale tourne et tout ce qui porte un Mark-of-the-Web venu d’un téléchargement ou d’un partage réseau doit d’abord être signé.

Get-ExecutionPolicy -List          # voir tous les scopes d'un coup
Set-ExecutionPolicy RemoteSigned -Scope LocalMachine

RemoteSigned repose entièrement sur le flux de données alterné Zone.Identifier que le navigateur ou le client SMB appose sur un fichier téléchargé. C’est tout le mécanisme et Unblock-File le retire en un appel, premier indice du poids qu’il peut porter.

Pourquoi ce n’est pas une frontière

Chacun de ces appels lance un script quelle que soit la politique, sans privilège particulier:

powershell.exe -ExecutionPolicy Bypass -File script.ps1
powershell.exe -Command "& { Get-Content script.ps1 | Invoke-Expression }"
Get-Content script.ps1 | Invoke-Expression

La politique régit la façon dont powershell.exe charge un .ps1 depuis le disque et rien de plus. Elle ne régit pas l’interpréteur: injectez le texte dans Invoke-Expression, passez-le en ligne de commande ou posez -ExecutionPolicy Bypass au lancement et la restriction n’a jamais été sur le chemin. Un attaquant qui peut lancer une commande PowerShell peut lancer n’importe quelle commande PowerShell, donc la politique arrête un accident et un utilisateur non averti, jamais un adversaire. Bâtissez votre modèle de menace là-dessus et vous ne serez pas surpris.

Ce qui contraint réellement PowerShell

Trois choses font un vrai travail et aucune n’est l’ExecutionPolicy.

Le Constrained Language Mode est celui qui mord. Il restreint le langage lui-même (pas de types .NET arbitraires, pas d’Add-Type, pas de COM) de sorte que même le code qui tourne ne peut atteindre la surface dangereuse et WDAC ou AppLocker en mode enforcement bascule PowerShell en CLM automatiquement pour tout ce qui n’est pas sur la liste d’autorisation. Ce couple, le contrôle applicatif décidant ce qui peut tourner et le CLM rognant ce que le code autorisé peut faire, est la frontière réelle que l’ExecutionPolicy ne fait que mimer.

La journalisation est l’autre moitié, parce qu’une frontière qu’on ne voit pas vaut peu. Le script-block logging enregistre ce qui a été exécuté, y compris le code décodé ou généré à l’exécution, c’est-à-dire précisément ce qui défait l’obfuscation vers laquelle un attaquant se tourne. La transcription capture la session. Les deux sont des réglages de stratégie de groupe ou les clés de registre derrière elles:

$base = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell"
Set-ItemProperty "$base\ScriptBlockLogging" EnableScriptBlockLogging 1
Set-ItemProperty "$base\Transcription"      EnableTranscripting      1

La signature de code est la troisième et c’est ce qui rend AllSigned sérieux plutôt que théâtral: une vraie PKI avec un certificat de signature de code, des scripts signés via Set-AuthenticodeSignature et la clé privée gardée ailleurs que sur l’agent de build. Un certificat auto-signé suffit pour apprendre le mécanisme et ne vaut rien comme ancre de confiance.

Où atterrir

Pour un parc géré: RemoteSigned par stratégie de groupe pour couvrir le cas de l’accident, WDAC ou AppLocker en enforcement pour que le contrôle applicatif et le Constrained Language Mode fassent la vraie restriction et le script-block logging plus la transcription qui coulent vers l’endroit où vous gardez les logs. L’ExecutionPolicy est la ceinture de ce véhicule. Elle vaut la peine d’être mise et personne ne devrait la prendre pour les freins.