Powershell : modification du registre pour contourner CredSSP

Au mois de mars, des correctifs Microsoft ont corrigé certaines failles par rapport à CredSSP qui est notamment utilisé pour sécuriser des connexions RDP (voir ce lien). Un message d'erreur peut survenir si un client patché tente de se connecter à un serveur non patché ou vice-versa. Pour faire simple, il est nécessaire que client comme serveur soient patchés pour qu'ils puissent communiquer.

J'ai réalisé un script Powershell permettant de contourner la sécurité via le registre afin que le système ne tienne pas compte du delta de version entre le CredSSP client et serveur. Dans un monde parfait, cela ne devrait pas exister car postes de travail et serveurs devraient être patchés en temps et en heure, mais la réalité est bien évidemment tout autre pour tout un tas de raisons. 👍

#Requires -RunAsAdministrator
$CredSspPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
$ParametersPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP"
$AllowEncryptionOraclePath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters"
New-Item -Path $CredSspPath -Name "CredSSP" -Force
New-Item -Path $ParametersPath -Name "Parameters" -Force
New-ItemProperty -Path $AllowEncryptionOraclePath -Name "AllowEncryptionOracle" -PropertyType DWORD -Value "2" -Force
Write-Host "If everything went fine, please reboot the system for the changes to take effect."
Sleep 5

Le script doit être lancé en administrateur ; une fois les clefs déployées, il est nécessaire de redémarrer la station qui devrait pouvoir se connecter sans le message d'erreur plus haut, ce qui ne dispense évidemment pas d'une campagne de patch ! 😉

Vous pouvez trouver une version commentée du script sur le serveur de fichiers en cliquant sur ce lien. 💾

Powershell : déploiement d'un script et création de tâche planifiée, sur machine distante

Sous ce titre un peu barbare, je vais partager un script que j'ai brodé aujourd'hui. En local sur ma station, j'utilisais un script Powershell me permettant de fermer des sessions RDP simplement déconnectées (que j'ai d'ailleurs publié dans cet article 😉). Seulement, il a été décidé de le modifier de manière à ce que le script ne demande plus un nom de machine particulière, mais de simplement s'occuper de la machine sur laquelle il est exécuté. En contrepartie, l'idée était de le déployer sur tous les serveurs, afin de pouvoir l'appeler via une tâche planifiée de manière à ce que tous les jours les sessions RDP inactives soient shuntées.

Le script ci-dessous va donc effectuer les tâches suivantes :

  • demander un nom de serveur
  • créer un répertoire sur le disque local C:
  • copier le script dans le répertoire fraîchement créé
  • créer une tâche planifiée, exécutée par l'utilisateur SYSTEM, avec une élévation de droits, qui va donc appeler le script qui a été copié.

Plusieurs choses :

  • Les instructions propres au planificateur de tâches ne fonctionnent qu'à partir de Windows 2012 R2 ou 8.1, indépendamment de la version de PS.
  • J'ai utilisé les partages administratifs au lieu d'un PS-Session pour la copie car un Copy-Item -ToSession nécessite PowerShell V5, or mon environnement est hybride V4 et V5 et je ne peux pas tout déployer directement depuis un hôte en V5.
  • Les commandlets du planificateur de tâches ne fonctionnent qu'en local, il faut donc les appeler sur le système distant via Invoke-Command.
$RemoteServer = Read-Host "Destination Server to install script and create scheduled task ?"
$ScriptDir = "\\"+$RemoteServer+"\c$\"
New-Item -Path $ScriptDir -Name "Scripts" -ItemType "directory"
$FinalDest = "\\"+$RemoteServer+"\c$\Scripts"
Copy-Item "script.ps1" -Destination $FinalDest -Force
if ($?){ Write-Host "Copy successful." }
else { Write-Host "Copy failed." ; break }
Invoke-Command -ComputerName $RemoteServer -ScriptBlock {
$TaskDetails = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$TaskAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "C:\Scripts\script.ps1"
$TaskSched = New-ScheduledTaskTrigger -Daily -At 4am
$TaskName = "AutoDisconnectSession"
Register-ScheduledTask -Action $TaskAction -Principal $TaskDetails -Trigger $TaskSched -TaskName $TaskName }
if ($?) { Write-Host "Task successfully created." }
else { "There was an error creating the task." }

Powershell : fermeture de session inactives à distance

Suite à un besoin récurrent, j'ai développé un script Powershell permettant de mettre fin à tous les sessions déclarées comme inactives sur un serveur Windows distant. Il est constitué d'une fonction qui est chargée de terminer les sessions et de quelques instructions appelant cette fonction ; une fois un serveur traité, le script demande si l'utilisateur souhaite traiter un autre serveur.

A noter qu'il faut naturellement des droits d'administration sur les serveurs sur lesquels une session doit être terminée.

$kick = "Y"
function Kick {
param ($srv)
$quout = quser /server:$srv
$status = "Disc"
$indexs = 2
$indexu = 1
$sid = (($quout | Where-Object { $_ -match $status }) -split ' +')[2]
while ($sid -ne $null)
{
$username = (($quout | Where-Object { $_ -match $status }) -split ' +')[$indexu]
$sid = (($quout | Where-Object { $_ -match $status }) -split ' +')[$indexs]
if ($sid -eq $null) { break }
Write-Host "User :"$username
Invoke-RDUserLogoff -HostServer $srv -Unifiedsid $sid -Force
$indexu = $indexu+8
$indexs = $indexs+8
Write-Host "Session has been terminated."
Start-Sleep -Seconds 3
}
}
Write-Host "Force close disconnected session script for Windows 2008 and 2012"
while ($kick -eq "Y")
{
$srv = Read-Host "Server Name"
kick($srv)
$kick = Read-Host "Do you want to process another server ? Y/N"
}

Désactivation de TLS 1.0, TLS 1.1 et activation de TLS 1.2 sur Windows Server 2008 R2 et +

Il a été décidé par les responsables d'une plateforme sur laquelle je suis intervenu ce jour de la désactivation de TLS 1.0 et 1.1 au profit de 1.2 sur un serveur Windows 2008 R2 utilisant IIS 7. Je vais donc décrire dans cet article les modifications qui sont à réaliser en base de registre - je pense réaliser par la suite un script permettant l'automatisation de la création et peuplement de ces clefs.

En préalable, il est important de vérifier que le KB 3080079 soit installé sur le serveur si 2008 R2, sans quoi une fois la désactivation de TLS 1.0 effective il ne sera plus possible d'accéder en Remote Desktop sur le serveur. Je renvoie à cette page pour plus d'informations.

J'ai réalisé une archive ZIP des clefs de registre évoquées dans ce billet sur mon miroir de téléchargement.

Dans la base de registre, on ira jusqu'à la clef suivante :
HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols

Une fois dans cette clef, il suffira de créer une clef supplémentaire par protocole. On créé donc 3 clefs : TLS 1.0, TLS 1.1 et TLS 1.2. A noter qu'il est fort probable que soient déjà présentes d'autres clefs pour SSL, comme sur cette capture d'écran.

Dans chacune des clefs TLS, il faudra créer 2 sous-clefs : Client et Server. L'arborescence ressemble donc à cela :

Dans chacune des 6 clefs qui ont été crées, il faudra ajouter 2 valeurs DWORD en hexadécimal :

  • DisabledByDefault, qui aura toujours la valeur 0
  • Enabled, qui aura la valeur 0 pour TLS 1.0 et TLS 1.1 et la valeur 1 pour TLS 1.2.

Ce qui donne, pour TLS 1.0\Client, TLS 1.0\Server, TLS 1.1\Client et TLS 1.1\Server :

Pour TLS 1.2\Client et TLS 1.2\Server :

Ensuite, un redémarrage du serveur suffit pour que les modifications soient prises en compte. Les protocoles TLS 1.0 et 1.1 ne sont plus actifs. A noter que ces clefs de registre peuvent également être appliquées sur Windows Server 2012 et R2.

Si jamais le Remote Desktop ne fonctionne plus une fois TLS 1.0 désactivé et que le patch est bien installé sur le serveur (si antérieur à 2012), il faut forcer le Terminal Server à utiliser son encryption et non celle de TLS 1.0. Pour ce faire, on ouvrira tsconfig.msc, puis les propriétés du serveur. Cette fenêtre s'ouvre :

Il est important que le Security Layer soit basculé sur RDP Security Layer et non TLS 1.0, faute de quoi la connexion sera impossible.