Guide des commandes via PowerShell Remoting utiles en test d’intrusion

Commandes PowerShell Remoting

Expertise

Avant d’être un outil puissant et très pratique pour la phase de latéralisation durant un test d’intrusion en environnement Active Directory, PowerShell Remoting est surtout une solution efficace pour administrer une machine en ligne de commande sous Windows. Abrégé en PowerShell Remoting, il désigne l’utilisation conjointe du langage PowerShell et du protocole de gestion à distance WinRM pour l’administration de machines Windows. Il est alors possible d’exécuter sur la machine distante des commandes ou des scripts, parmi les cas d’usage les plus courants. Cet article a été écrit par Remi Madec, Consultant Sécurité de NBS System. ll se présente davantage comme une cheatsheet des commandes PowerShell qu’un guide complet. Cependant, il n’aborde pas l’étape de l’activation et le paramétrage du PowerShell est bien décrite, notamment dans la Documentation Microsoft.

Exemple de lancement des commandes via PowerShell :

Invoke-Command

L’utilisation de cmdlet Invoke-Command permet fin de lancer une unique commande. La syntaxe est la suivante :

Invoke-Command -ScriptBlock{COMMAND} -ComputerName SERVERNAME -Credential DOMAINE\USERNAME

Par exemple, pour lancer la commande hostname sur le serveur Server avec le compte local remi, il suffit d’exécuter la ligne suivante :

Invoke-Command -ScriptBlock{hostname} -ComputerName Server -Credential remi

PS C:\Users\Public> hostname Client PS C:\Users\Public> Invoke-Command -ScriptBlock{hostname} -ComputerName Server -Credential remi Server
photo1-1

Authentification

Le paramètre Credential permet de soumettre au serveur des informations d’authentification. Plusieurs méthodes existent, la plus répandue en environnement Active Directory étant Kerberos, qui nécessite toutefois que le client et le serveur soient membres de la même forêt, ou qu’une relation de confiance soit établie en forêt.

1. Saisie d’informations d’authentification

  • Avec l’utilisateur courant

Dans le cas où l’utilisateur courant est membre du domaine et est autorisé sur le serveur, il n’est pas nécessaire de préciser dans la commande les informations d’authentification : celles de l’utilisateur courant seront relayées au serveur. La commande précédente devient donc :

Invoke-Command -ScriptBlock{COMMAND} -ComputerName SERVERNAME

Si l’on souhaite utiliser les informations d’authentification d’un autre utilisateur, il est nécessaire d’utiliser le paramètre Credential. Plusieurs solutions existent dans ce cas.

  • Avec le nom d’utilisateur et une popup

Si ces informations n’ont pas besoin d’être réutilisées pour des commandes ultérieures, il suffit de passer seulement le nom d’utilisateur (domaine et nom d’utilisateur dans le cas d’un compte du domaine). C’est ce qui est fait avec la commande suivante :

Invoke-Command -ScriptBlock{hostname} -ComputerName Server -Credential remi

Pour saisir le mot de passe, un popup s’affiche :

image2
  • Stockées dans une variable (popup)

Il est également possible de stocker ces informations d’authentification dans une variable locale, évitant ainsi de devoir les saisir à nouveau lors de chaque commande. Pour les stocker dans la variable cred, la syntaxe suivante est utilisée :

$cred = Get-Credential

Comme dans le cas précédent, un popup apparaît pour saisir ses informations :

image3

Cette variable doit ensuite être passée en argument du paramètre Credential :

Invoke-Command -ScriptBlock{COMMAND} -ComputerName SERVERNAME -Credential $cred

image4
  • Stockées dans une variable (ligne de commande)

La méthode précédente est pratique, mais la saisie d’informations d’authentification dans une popup n’est pas toujours une solution envisageable pour diverses raisons. Par exemple, si le prompt PowerShell est obtenu depuis un reverse shell, la popup s’affichera sur l’ordinateur distant ! C’est d’autant plus regrettable qu’en plus de ne pas pouvoir s’authentifier, l’attaquant perd la main sur le shell.

Il est alors possible d’utiliser l’objet PSCredential avec la saisie du mot de passe en ligne de commande. La syntaxe à utiliser est alors la suivante :

$Username = « USERNAME »

$SecurePassword = « PLAINPASSWORD » | ConvertTo-SecureString -AsPlainText -Force

$PScred = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName,$SecurePassword

L’utilisation de cette variable s’effectue de la même manière que précédemment :

image5

2. Attention au double saut Kerberos

Lors de la latéralisation en environnement Windows, la problématique du double saut Kerberos est récurrente. Cette situation se produit lors qu’un Client s’authentifie auprès d’un premier serveur Serveur1 en tant qu’Utilisateur1 (Saut n°1), par exemple en utilisant les commandes ci-dessus. Il tente alors depuis ce dernier d’accéder à des ressources sur Server2 (Saut n°2), sur lequel Utilisateur1 est autorisé :

image6

L’accès est refusé ! En effet, les informations d’authentification ne sont pas transmises de Server1 à Server2. Plusieurs solutions existent : parmi celles privilégiées pour l’administration, la délégation Kerberos contrainte ou la délégation Kerberos contrainte basée sur les ressources (recommandées), ou encore la délégation Kerberos non contrainte (non recommandée).

  • CredSSP

Pour un attaquant, l’utilisation du protocole CredSSP (Credential Security Support Provider) est une solution pertinente. Ce mécanisme permet de stocker en cache sur le premier serveur les informations d’authentification. Celles-ci pourront alors être relayées au second serveur. Pour ce faire, il est nécessaire de configurer le client pour qu’il puisse « déléguer » ces informations, au moyen de la commande suivante (dans un contexte à privilèges élevés) :

Enable-WSManCredSSP -Role Client -DelegateComputer CLIENTNAME

Le serveur doit également être configuré en tant que relai (rôle server), et doit donc avoir été compromis totalement. La commande suivante est à utiliser (dans un contexte à privilèges élevés) :

Enable-WSManCredSSP -Role Server -Force

Il suffit alors de spécifier le protocole CredSSP comme méthode d’authentification dans les commandes précédentes :

Invoke-Command -ScriptBlock{COMMAND} -ComputerName SERVERNAME -Credential $cred -Authentication Credssp

Note : un administrateur utilisant cette méthode exposerait son mot de passe à un attaquant si ce dernier compromettait le serveur. Il est donc important de n’utiliser cette méthode que sur des machines « de confiance ».

Gestion des sessions

Les commandes via PowerShell Remoting offrent également la possibilité de communiquer avec une machine distante de manière interactive.

1. Session interactive

  • Enter-PSSession

Il faut utiliser la syntaxe suivante, pour démarrer une session interactive :

Enter-PSSession -ComputerName SERVERNAME -Credential $cred

Le prompt est alors modifié et nous indique clairement que nous lançons nos commandes sur le serveur :

image7
  • Exit

La commande Exit permet de revenir dans le contexte du client.

2. Session persistante

Il est également possible de créer des sessions persistantes.

  • New-PSSession

Le cmdlet New-PSSession permet ceci :

New-PSSession -ComputerName SERVERNAME -Credential $cred

image8

Pour faciliter l’organisation et la gestion des sessions, il est possible de leur donner un nom et de les stocker dans une variable locale :

$session1 = New-PSSession -Name Session1 -ComputerName Server -Credential $cred

image9
  • Get-PSSession

La commande suivante effectue la visualisation des sessions existantes :

Get-PSSession

image10

Les paramètres Name et Id (et bien d’autres, par exemple ComputerName) peuvent être utilisés pour filtrer les résultats. Ainsi, les deux commandes suivantes retournent le même résultat :

Get-PSSession -Name Session1

Get-PSSession -Id 19

image11

De nombreuses possibilités d’interaction sont disponibles. Par exemple, il est possible d’assigner à une variable une session déjà existante, par exemple avec la commande suivante :

$session0 = Get-PSSession -Id 18

image13
  • Enter-PSSession

Pour interagir avec une session existante, il suffit d’utiliser le cmdlet Enter-PSSession accompagné d’un moyen d’identification de la session (son nom, son Id ou la variable dans laquelle elle est stockée). Les commandes suivantes aboutissent au même résultat :

Enter-PSSession -Id 19

Enter-PSSession -Name Session1

Enter-PSSession -Session $session1

  • Disconnect-PSSession & Connect-PSSession

La commande Exit est utilisée pour revenir dans le contexte du Client. Toutefois, la session est toujours active. Il est possible de la déconnecter à l’aide de la commande suivante :

Disconnect-PSSession -Id 18

image14

Celle-ci n’est cependant pas supprimée. Il est par exemple possible de lancer un script, de déconnecter la session, puis de reconnecter la session plus tard pour consulter les résultats. C’est d’autant plus pratique que cette session est conservée côté serveur, et il est donc possible de s’y reconnecter depuis une machine cliente différente de la première (ce qui nécessite tout de même d’utiliser le même compte utilisateur).

Pour se reconnecter à une session existante, il convient d’utiliser le cmdlet Connect-PSSession :

Connect-PSSession -Id 18

La commande suivante est utilisée pour supprimer définitivement une session :

Remove-PSSession -Id 18

image15

3. Sessions multiples

Pour lancer des commandes ou des scripts sur de multiples machines, par exemple lors de la phase de post-exploitation, plusieurs sessions (sur le même serveur ou sur plusieurs serveurs compromis) peuvent être stockées dans une unique variable :

$sessions = New-PSSession -ComputerName Server,Server -Credential $cred

Il suffit alors de l’utiliser de la même manière que précédemment pour obtenir le résultat de toutes les sessions :

Invoke-Command -ScriptBlock{hostname} -Session $sessions

image16

Dans certains cas, il peut également être intéressant de créer de multiples sessions, chacune stockée dans une variable. C’est possible en une unique ligne avec la syntaxe suivante :

$sess1, $sess2 = New-PSSession -ComputerName Server,Server -Credential $cred

Chaque variable correspond alors à une session :

image17

Note : si le nombre de variables passées excède le nombre de machines, les variables en excès seront vides. Dans le cas contraire, toutes les sessions en excès seront attribuées à la dernière variable.

Lancement des commandes à distance via le PowerShell Remoting

1. Le PowerShell Remoting explicite

Les commandes via PowerShell Remoting offrent de nombreuses possibilités pour lancer une ou plusieurs commandes, des scripts, importer des modules …

  • Commandes et scripts distants

Pour lancer plusieurs commandes, Il suffit de les séparer par un point-virgule dans le paramètre ScriptBlock :

Invoke-Command -ScriptBlock{hostname;whoami} -Session $session1

Il est possible de lancer un script déjà présent sur le serveur en précisant son chemin relatif dans le paramètre ScriptBlock :

Invoke-Command -ScriptBlock{C:\Users\Public\hostname.ps1} -Session $session1

image18

Ces fonctionnalités permettent par exemple de charger un module pour en exécuter des fonctions en une seule ligne :

Invoke-Command -ScriptBlock{Import-Module C:\PATHTOMODULE; MODULEFUNCTION} -Session $session1

  • Scripts stockés localement

Déposer des scripts sur une machines compromise n’est pas forcément la manière la plus furtive de procéder. Il est cependant possible d’exécuter sur la machine distante des scripts stockés sur le client. Pour ce faire, le paramètre FilePath est utilisé :

Invoke-Command -FilePath C:\Users\Public\local_hostname_script.ps1 -Session $session1

image19

2. Le PowerShell Remoting implicite

L’ensemble des commandes utilisées précédemment est exécuté explicitement sur le serveur : il est clair que c’est à travers la session qu’elles sont envoyées.

Par exemple, pour importer le module Powerview.ps1 stocké sur la machine distante et en lancer une commande (ici Get-NetLoggedon), la syntaxe explicite est la suivante :

Invoke-Command -ScriptBlock{Import-Module C:\Users\Public\Powerview.ps1;Get-NetLoggedon}-Session $session1

Sur le serveur et la commande exécuté, il y a bien ce module qui est chargé :

  • Export-PSSession

Cette syntaxe est plutôt lourde, et c’est ici qu’intervient le Remoting implicite : il est possible d’exporter le contexte de la session pour lancer des commandes de ce module sur le serveur comme si le module était chargé localement. Pour ce faire, le cmdlet Export-PSSession est utilisé :

Export-PSSession -Session $Session1 -OutputModule Powerview

Cette commande stocke localement ce contexte dans le module passé en argument du paramètre OutputModule. Il suffit de l’importer et d’en utiliser les fonctions. De manière transparente, celles-ci sont toujours exécutées sur le serveur, au travers de la session dont provient l’export :

image21

Interaction avec une session persistante

Enfin, autre fonctionnalité pratique : il est possible de se servir d’une session PowerShell pour transférer des fichiers.

  • Depuis le client vers le serveur

La commande à utiliser est :

Copy-Item -Path C:\LOCALPATHTOFILE -ToSession $session1 -Destination C:\REMOTEDESTINATIONFILEPATH

  • Depuis le serveur vers le client

Le paramètre FromSession remplace ToSession :

Copy-Item -Path C:\REMOTEPATHTOFILE -FromSession $session1 -Destination C:\LOCALDESTINATIONFILEPATH

Cheatsheet de commandes PowerShell Remoting

1. Syntaxe générique

Exécution de commande :

Invoke-Command -ScriptBlock{COMMAND} -ComputerName SERVERNAME

2. Authentification

Popup :

Invoke-Command -ScriptBlock{COMMAND} -ComputerName SERVERNAME -Credential DOMAINE\USERNAME

Stockage dans une variable (popup) :

$cred = Get-Credential
Invoke-Command -ScriptBlock{COMMAND} -ComputerName SERVERNAME -Credential $cred

Stockage dans une variable (CLI) :

$Username = « USERNAME »
$SecurePassword = « PLAINPASSWORD » | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName,$SecurePassword
Invoke-Command -ScriptBlock{COMMAND} -ComputerName SERVERNAME -Credential $cred

3. Double saut Kerberos (CredSSP)

Activation du la délégation (client) :

Enable-WSManCredSSP -Role Client –

DelegateComputer CLIENTNAME :

Activation du la délégation (serveur) Enable-WSManCredSSP -Role Server -Force

Exécution de commande :

Invoke-Command -ScriptBlock{COMMAND} -ComputerName SERVERNAME -Credential $cred -Authentication Credssp

4. Gestion des sessions

Session interactive :

Enter-PSSession -ComputerName SERVERNAME -Credential $cred

Session persistante :

New-PSSession -ComputerName SERVERNAME -Credential $cred

Session persistante nommée et stockée :

$SESSIONVAR = New-PSSession -Name SESSIONNAME -ComputerName SERVERNAME -Credential $cred

Visualisation des sessions :

Get-PSSession

Filtre par nom/Id :

Get-PSSession -Name SESSIONNAME
Get-PSSession -Id SESSIONID

Interaction par Id/nom/variable :

Enter-PSSession -Id SESSIONID
Enter-PSSession -Name SESSIONNAME
Enter-PSSession -Session
$SESSIONVAR

Déconnexion :

Disconnect-PSSession -Id SESSIONID

Reconnexion :

Connect-PSSession -Id SESSIONID

Suppression définitive :

Remove-PSSession -Id SESSIONID

Stockage X sessions dans 1 variable :

$SESSIONVAR = New-PSSession -ComputerName SERVERNAME1,SERVERNAME2 -Credential $cred

Stockage X sessions dans X variable :

$SESSIONVAR1, $SESSIONVAR2 = New-PSSession -ComputerName SERVERNAME1,SERVERNAME2 -Credential $cred

5. Commandes et scripts

Multiples commandes :

Invoke-Command -ScriptBlock{COMMAND1;COMMAND2} -Session $SESSIONVAR

Script distant :

Invoke-Command -ScriptBlock{REMOTEPATHTOSCRIPT\SCRIPT.ps1} -Session $SESSIONVAR

Module distant :

Invoke-Command -ScriptBlock{Import-Module C:\REMOTEPATHTOMODULE; MODULEFUNCTION} -Session $SESSIONVAR

Script local :

Invoke-Command -FilePath REMOTEPATHTOSCRIPT\SCRIPT.ps1 -Session $SESSIONVAR

Remoting implicite :

Export-PSSession -Session $SESSIONVAR -OutputModule OUTPUTMODULENAME

6. Transfert de fichiers

Client -> Serveur :

Copy-Item -Path C:\LOCALPATHTOFILE\FILE -ToSession $SESSIONVAR -Destination C:\REMOTEDESTINATIONFILEPATH

Serveur -> Client :

Copy-Item -Path C:\REMOTEPATHTOFILE\FILE -FromSession $SESSIONVAR -Destination C:\LOCALDESTINATIONFILEPATH

Article de Remi Madec, consultant sécurité de NBS System

Vous souhaitez en savoir plus ?

Nos équipes sont là pour vous accompagner concernant les commandes via le PowerShell