Evolution de la sécurité de PowerShell et techniques de contournements

Filtrer par catégorie :

08 Juillet 2019 by Lény BUENO & Slim MERIAH
Powershell_digitalsecurity
PowerShell est un interpréteur de lignes de commandes et un langage de script reposant sur le framework Microsoft .NET intégré dans les systèmes Windows. Rapidement devenu un outil indispensable pour les administrateurs système, nous verrons dans cet article comment le large spectre de fonctionnalités offert par PowerShell  permet aux attaquants de contourner les protections progressivement mises en place par Microsoft.
 
PowerShell est un langage de script orienté objet qui s’appuie sur les classes du framework .NET pour interagir avec un système Windows, en local ou à distance. De par la simplicité de sa syntaxe et des nombreuses fonctionnalités offertes par ce langage, celui-ci a rapidement pris la place de ses prédécesseurs WSH (Windows Script Host) et MS-DOS (BAT) au sein des Entreprises.

Aujourd’hui disponible dans sa version 6, PowerShell a été introduit nativement dans sa version 2.0 avec Windows 7. Depuis cette version, un nouvel éditeur de code PowerShell nommé ISE est également intégré. Avant cela, la première version de PowerShell était disponible sous forme de mise à jour facultative sur Windows XP, Windows Vista ainsi que Windows Server 2003.

La diversité des cmdlets (applets de commandes) ainsi que la possibilité d’interagir avec l’API Windows (Win32 API), ou encore l’intégration d’une interface permettant d’interroger des classes WMI (Windows Management Instrumentation), en ont fait une technologie de choix pour la mise en place d’attaques plus ou moins furtives. En contrepartie, au fil des versions, Microsoft a intégré différentes politiques et mesures de sécurité permettant de bloquer et / ou détecter l’utilisation malveillante de PowerShell.

 

1. Politique d’exécution

Parmi les premières mesures de sécurité PowerShell intégrées par Microsoft se trouve la politique d’exécution de scripts. Cette dernière a été mise en place afin de définir les conditions permettant l’exécution de scripts PowerShell au sein d’un système.

Plusieurs types de politiques plus ou moins restrictives peuvent être définies avec la cmdlet Set-ExecutionPolicy : AllSigned, Bypass, Default, RemoteSigned, Restricted, Undefined et Unrestricted. Par défaut, la politique Restricted est mise en place sur les postes de travail Windows (client) et RemoteSigned sur les serveurs Windows.

  • La politique Restricted implique que seules les commandes PowerShell puissent être exécutées. En théorie, il n’est donc pas possible d’exécuter les scripts, peu importe leur contenu.
  • La politique RemoteSigned permet d’exécuter les scripts PowerShell. Cependant, les scripts provenant d’Internet doivent être signés par un éditeur approuvé.
Une politique d’exécution restrictive peut être facilement contournée par un attaquant ayant accès à un système Windows. Cette mesure est davantage utile dans le cas où un utilisateur lambda exécute un script malveillant par inadvertance.
 

1.1. Contournement d’une politique d’exécution restrictive

De nombreuses techniques existent aujourd’hui pour contourner une politique d’exécution restrictive afin de  lancer un script PowerShell sur un système Windows [NETSPI].
 
1.1.1. Invoke-Expression
Invoke-Expression est une applet de commande PowerShell permettant d’évaluer des expressions PowerShell et d’exécuter des commandes. L’utilisation de cette cmdlet  permet d’exécuter des scripts PowerShell peu importe le niveau de restriction mis en place via la politique d’exécution. Il suffit pour cela de passer à Invoke-Expression le contenu d’un script en entrée (via la cmdlet Get-Content ou Download Cradles [DLCRAD] :

 

1.1.2. Utilisation de la politique Bypass
La politique d’exécution Bypass permet à un utilisateur d’exécuter n’importe quel script PowerShell.
Afin d’exécuter un script sur un système où la politique d’exécution est restrictive, il est possible de forcer le mode Bypass sur la politique sans que cela nécessite les privilèges d’administration :
  • Cela peut se faire en modifiant une variable d’environnement, ce qui ne va impacter que la session PowerShell courante. Ainsi, l’exécution de script ne va pas être possible si l’utilisateur relance une autre invite de commandes PowerShell :
 
 
  • Il est possible de passer en mode Bypass en appliquant cette politique durant l’exécution de PowerShell avec le paramètre « -ExecutionPolicy » ou « -ep » :
 

1.1.3. Annulation du « AuthorizationManager »
AuthorizationManager est une classe permettant de contrôler et restreindre l'exécution des commandes  PowerShell dans un contexte spécifique. Cette classe fait partie de « System.Management.Automation »,  une librairie permettant d’exécuter PowerShell.
 
Ainsi, en implémentant une fonction permettant de mettre à « null » la classe « AuthorizationManager » dans la session PowerShell courante, la politique d’exécution devient automatiquement non restrictive (Unrestricted) et permet ainsi d’exécuter n’importe quel script.
 
Pour cela il suffit d’appeler la fonction suivante au sein d’une invite de commandes PowerShell :
 



 

2. AntiMalware Scan Interface (AMSI)

2.1. Principes de l’AMSI

AMSI est une interface permettant de fournir, à n’importe quelle application tierce installée sur un système Windows (antivirus, logiciels de sécurité, etc.), un moyen d’analyser l’exécution d’un script, même chargé en mémoire, afin de détecter s’il est malveillant ou non.

 

2.2. Techniques de contournement de l’AMSI avec PowerShell

2.2.1. Manipulation de chaînes de caractères
Dans un premier temps, l’analyse effectuée par l’AMSI sur un script potentiellement malveillant repose sur une base de signatures. Par conséquent, l’obfuscation des chaînes de caractères ainsi que la modification d’un script d’attaque peut être un moyen efficace et facile à mettre en place pour contourner une détection.

Certains outils tels que Invoke-Obfuscation ou encore PSAmsi peuvent s’avérer être très utiles pour contourner la détection basée sur les signatures de l’AMSI.
 
2.2.2 Patching de la mémoire
La librairie AMSI.dll est chargée dans la mémoire du processus powershell.exe pour analyser une session PowerShell.
Cette technique de contournement de l’AMSI repose sur ce principe de fonctionnement. En effet, la librairie AMSI.dll est chargée dans l’espace mémoire du processus PowerShell lancé par un simple utilisateur, qui  dispose donc des privilèges suffisants pour en modifier le comportement.

En étudiant les fonctions de l’API appelées durant une analyse, il s’avère que la fonction AmsiScanBuffer [AMSISCAN] semble pertinente :

Fig. 2 : AmsiScanBuffer à chaque fois qu’une commande PowerShell est exécutée

 
Le paramètre length correspond au nombre d’octets qui vont être lu du tampon contenant le code à analyser. En spécifiant la valeur 0 au niveau du paramètre length, aucun octet du script ne va donc être analysé par l’AMSI.

Cette technique permet ainsi de désactiver l’AMSI. Plusieurs outils et scripts existent aujourd’hui pour automatiser cette manœuvre.

 

3. Détections et investigations

Face aux différentes attaques pouvant être mise en œuvre, la BlueTeam possède un certain nombre d'outils pour détecter et investiguer ces dernières.
 

3.1. PowerShell Transcript

Start-Transcript est une cmdlet présente depuis PowerShell v2 qui enregistre l'ensemble des commandes d'une session PowerShell dans un fichier texte. Ce fichier contient également des informations telles que le nom de l’utilisateur exécutant les commandes, un horodatage pour chaque commande entrée, le résultat des commandes, etc.

Dans le cas de la mise en place d’un système de journalisation centralisé, le fichier de journalisation peut être stocké sur un serveur distant.

Pour démarrer l'enregistrement, il suffit d’exécuter la cmdlet Start-Transcript. Le fichier dans lequel enregistrer les commandes peut également être précisé via les paramètres :



 
A des fins de détections et d'investigations, ce mécanisme peut être implémenté au sein d'un environnement Windows Active Directory. Pour cela, une stratégie de groupe (GPO) nommée « Activer la transcription PowerShell » peut être mise en place en configurant le répertoire de sortie pour le fichier de journalisation ainsi que la présence ou non des en-têtes contenant les informations sur l’environnement d’exécution des commandes.

Fig. 2 : Fenêtre Windows de configuration de la stratégie « Activer la transcription PowerShell »

3.2. PowerShell Script Block Logging

La journalisation des blocs de scripts PowerShell est également possible via une GPO pouvant être activée sur les environnements Active Directory. Concrètement, un script block correspond à tout type de commande PowerShell pouvant être exécuté. Ainsi, lorsque du code PowerShell est exécuté, chaque instruction présente dans celui-ci va être journalisée. L’avantage de cette stratégie pour une BlueTeam réside dans le fait que les instructions PowerShell sont journalisées au cours de leur exécution. Ainsi, les instructions obfusquées ou contenant des chaînes de caractères encodées vont être journalisées dans un format pouvant être facilement interprété par un analyste (chaînes de caractères décodées et code désobfusqué). Également, les journaux du script block logging sont intégrés au sein du gestionnaire d’événements Windows. Cela facilite donc le processus de centralisation des journaux via WinRM et également leur traitement.
 
3.2.1. Deep script block logging
Avec la version 5 de PowerShell, Microsoft a introduit un mécanisme permettant de journaliser automatiquement des instructions même si la stratégie de script block logging n’est pas implémentée. En effet, lorsque des instructions PowerShell considérées comme étant suspicieuses par le système sont exécutées, celles-ci sont enregistrées même si le script block logging est désactivé.

Les instructions considérées comme étant suspicieuses par le système correspondent à des commandes PowerShell exécutant du code généré dynamiquement :


 


3.3. Techniques de contournement

Il existe aujourd’hui différentes techniques permettant d’éviter les détections et les remontées d’alertes lorsque PowerShell est utilisé au cours des audits RedTeam.
 
3.3.1. Unmanaged PowerShell
Il arrive parfois que les membres d’une BlueTeam surveillent l’exécution des processus conventionnels pour exécuter du PowerShell, soit : powershell.exe et powershell_ise.exe. En effet, généralement des règles de détection ainsi que des restrictions sont mises en place en se basant sur l’exécution de ces processus spécifiques.
 
Concrètement, afin d’exécuter des commandes PowerShell, le processus powershell.exe charge la librairie .NET System.Management.Automation [LIBPSHELL] et fait appel à ses fonctions permettant d’évaluer des expressions PowerShell. Ainsi, en reprenant ce principe, il est possible d’exécuter du PowerShell depuis n’importe quel autre processus tant que celui-ci charge la même librairie (System.Management.Automation). Par exemple, une DLL contenant du code PowerShell et faisant appel aux fonctions de la librairie System.Management.Automation pour exécuter ce même code pourrait être injectée dans la mémoire d’un processus légitime.
 
Par conséquent, en audit RedTeam, les règles de détection basées sur la surveillance des processus powershell.exe et powershell_ise.exe ne devraient pas détecter une activité suspecte étant donné que le code PowerShell exécuté via cette technique peut être lancé depuis n’importe quel autre programme. Cela permet ainsi d’être plus furtif et  de gagner du temps sur une phase de post-exploitation. Plusieurs projets existent aujourd’hui pour facilement mettre en place ce type de technique [UNPSHELL].
 
3.3.2. Contournement du script block logging
Comme vu précédemment, le script block logging correspond à une GPO permettant de journaliser chaque instruction PowerShell exécutée. Ainsi, lorsqu’une session PowerShell est initialisée, PowerShell vérifie si cette GPO est implémentée et insère dans un cache une valeur permettant d’identifier la mise en place ou non de la stratégie. Concrètement, à chaque fois qu’une instruction PowerShell va être exécutée, PowerShell va vérifier dans son cache si le script block logging est mis en place ou non.

La technique de contournement repose sur ce principe. En effet, la valeur mise en cache par PowerShell permettant d’identifier l’implémentation de la GPO est accessible en écriture par un simple utilisateur ayant ouvert une session PowerShell. Ainsi, il est possible avec un morceau de code de réécrire les valeurs mises en cache dans le but de forcer la désactivation du script block logging pour la session courante :


 
 
Par ailleurs, il existe également une autre technique pour contourner le script block logging. Celle-ci consiste à assigner une valeur nulle à une instance de la classe EventProvider chargée de journaliser les évènements PowerShell :


 
 
Cependant, il est à noter que les instructions PowerShell permettant de contourner le script block logging vont tout de même être journalisées et cela va donc générer une alerte (évènement de type avertissement). Il est ainsi important soit d’obfusquer le code permettant de contourner cette stratégie au préalable, ou bien d’utiliser la technique du Unmanaged PowerShell vue précédemment pour être davantage furtif. Dans ce cas, le Script block logging sera également activé, cependant, les règles mises en place par les équipes blueteam sont généralement configurées pour remonter des alertes basées uniquement sur les blocs de scripts exécutés depuis le processus « powershell.exe », « powershell_ISE.exe », etc.
 
3.3.3. Utilisation d’une version inférieure de PowerShell
Durant un exercice de type RedTeam, il est judicieux de vérifier quelles versions de PowerShell sont présentes sur le système. En effet, la version 2 n’est pas compatible avec les mesures de sécurité et de journalisation mises en place dans les versions plus évoluées de PowerShell.

La commande suivante permet de vérifier si la version 2 de PowerShell est disponible sur un système :


Pour lancer PowerShell v2, il suffit juste d’exécuter la commande suivante, cela fonctionne également depuis une session PowerShell ayant une version plus évoluée :


Cependant, sur Windows 10, il est généralement nécessaire d’installer au préalable la version 2.0.50727 du framework .NET, ce qui n’est malheureusement pas envisageable sur un environnement de production au cours d’un audit RedTeam.
 


4. Environnements durcis

Les solutions de contrôle d’applications à l’échelle du système sont de plus en plus présentes en entreprise. En environnement Windows, on retrouvera généralement les solutions DeviceGuard ou AppLocker, qui permettront, via la définition de règles de stratégies, d’autoriser ou non l’exécution d’une application sur le système.
 

4.1. Listes blanches et mode de langage contraint

Si l’une de ces solutions est active, il se pourrait que l’exécution des applications powershell.exe et powershell_ise.exe soit interdite, ou que PowerShell soit exécuté en mode de langage contraint (CLM pour Constrained Language Mode).

Ce mode permet de prendre en charge les tâches administratives quotidiennes, tout en limitant l'accès aux éléments de langage sensibles, qui pourraient être utilisés à des fins malveillantes (comme un appel à l’API Windows ou le chargement d’un script en mémoire par exemple).


 
 
Il est également intéressant de préciser que dans ces conditions, tout script faisant partie de la liste blanche des fichiers autorisés par la solution de contrôle d’applications, pourra être exécuté en mode de langage complet.
 

4.2. Techniques de contournement

Bien que les listes blanches d’applications et le mode de langage contraint renforcent la robustesse d’un système, ces solutions ne sont pas infaillibles et des méthodes de contournement existent.
 
4.2.1. Mode de verrouillage AppLocker
A chaque démarrage de PowerShell, un script et un module sont créés dans le répertoire temporaire de l’utilisateur puis exécutés. Leur nom est généré aléatoirement et leur contenu ne comporte qu’un unique commentaire. Si l’exécution s’est déroulée avec succès, la session PowerShell sera en mode de langage complet, dans le cas contraire, cela signifie que le mode de verrouillage AppLocker est actif et la session sera donc en mode de langage contraint.
 
Cela devient intéressant, car PowerShell obtient le répertoire temporaire de l’utilisateur dans lequel créer les fichiers à partir des variables d’environnement. D’autre part, les règles par défaut d’AppLocker autorisent l’exécution de scripts depuis C:\Windows\*.
Ainsi, en remplaçant le répertoire temporaire de l’utilisateur par C:\Windows\temp dans la variable d’environnement et en exécutant PowerShell, les scripts vérifiant la politique AppLocker seront exécutés avec succès. La session sera alors en mode de langage complet.
Cette technique, découverte par Oddvar Moe, a aussitôt été portée dans son module PowerShell aidant à identifier les faiblesses AppLocker [POWERAL].
 
4.2.2. Binaires Microsoft signés
Dans le cas où l’exécution de powershell.exe est interdite, il faut garder à l’esprit qu’il est possible d’exécuter des commandes PowerShell par le biais de code C# :

 

Petite astuce, l’utilisation de la classe Pipeline [PIP] permet de contourner le mode de langage contraint.

Côté exécution du code C#, ce n’est pas non plus cause perdue, l’utilisation de binaires Microsoft signés  permettra de passer outre la liste blanche d’applications.
Une première possibilité repose sur le Microsoft Build Engine (MSBuild), une plateforme de génération d'applications utilisée par Visual Studio pour charger et générer des projets managés (.csproj). Il est possible d’insérer du code C# dans la structure XML de ces fichiers ([UNIC] et [MSBU]).

Une seconde possibilité repose sur l’utilitaire InstallUtil, qui peut  charger et exécuter du code C# dans son propre processus par le biais de ses fonctions d’installation ou de désinstallation :


 

La fonction d’installation nécessite les droits d’administration, contrairement à la fonction de désinstallation qui peut être appelée par un utilisateur non privilégié.

Reste alors à compiler le code malveillant puis l’exécuter :


Il ne s’agit bien évidemment que d’un échantillon de possibilités parmi tant d’autres.
 
4.2.3. Rétrogradation de version PowerShell
Une fois encore, si la version 2 de PowerShell est accessible sur le système, le simple fait de la charger enlèvera cette protection. En effet, cette version ne supporte pas le mode de langage contraint.

 

Conclusion

Avec suffisamment de moyens, une BlueTeam a désormais toutes les cartes en main pour rapidement détecter les tentatives d’intrusions et déplacements latéraux au sein de son SI.
 
Un parc moderne et à jour, un bouquet de GPOs judicieusement sélectionnées, un espace de stockage suffisant pour recueillir l’ensemble des journaux collectés et surtout une solide équipe capable de créer les règles de corrélation et les mécanismes d’alertes adéquats feront frémir les plus aguerris des pentesters.

Quoiqu’il en soit, les attaquants les plus avertis rivalisent d’ingéniosité et trouveront toujours un moyen pour contourner les nouvelles protections, le tout étant de les ralentir au maximum et de complexifier leur tâche.
 
 

Remerciements

Elias ISSA et Thomas GAYET pour leur aide ainsi que leur relecture.

 

Auteurs








Sources :