Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les scripts PowerShell, comme d’autres langages de programmation, peuvent être vulnérables aux attaques par injection. Une attaque par injection se produit lorsqu’un utilisateur fournit une entrée à une fonction vulnérable qui inclut des commandes supplémentaires. La fonction vulnérable exécute les commandes supplémentaires, ce qui peut être une vulnérabilité de sécurité grave. Par exemple, un utilisateur malveillant peut abuser de la fonction vulnérable pour exécuter du code arbitraire sur un ordinateur distant, ce qui peut compromettre cet ordinateur et accéder à d’autres ordinateurs sur le réseau.
Une fois que vous connaissez le problème, il existe plusieurs façons de vous protéger contre les attaques par injection.
Exemple de code vulnérable
Les vulnérabilités d’injection de code PowerShell impliquent une entrée utilisateur qui contient du code de script. L’entrée utilisateur est ajoutée au script vulnérable où PowerShell analyse et l’exécute.
function Get-ProcessById
{
param ($ProcId)
Invoke-Expression -Command "Get-Process -Id $ProcId"
}
La Get-ProcessById fonction recherche un processus local par sa valeur d’ID. Il prend un $ProcId argument de paramètre de n’importe quel type.
$ProcId est ensuite converti en chaîne de caractères et inséré dans un autre script.
Invoke-Expression l’applet de commande analyse et exécute la chaîne fournie. Cette fonction fonctionne correctement lorsqu’un entier d’ID de processus valide est transmis.
Get-ProcessById $PID
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
97 50.09 132.72 1.20 12528 3 pwsh
Toutefois, le $ProcId paramètre ne spécifie pas de type. Elle accepte toute valeur de chaîne arbitraire qui peut inclure d’autres commandes.
Get-ProcessById "$PID; Write-Host 'pwnd!'"
Dans cet exemple, la fonction a correctement récupéré le processus identifié par $PID, mais a également exécuté le script Write-Host 'pwnd!'injecté.
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
92 45.66 122.52 1.06 21736 3 pwsh
pwnd!
Méthodes de protection contre les attaques par injection
Il s’agit de plusieurs façons de se protéger contre une attaque par injection.
Utiliser une entrée typée
Vous pouvez spécifier un type pour l’argument $ProcId .
function Get-ProcessById
{
param ([int] $ProcId)
Invoke-Expression -Command "Get-Process -Id $ProcId"
}
Get-ProcessById "$PID; Write-Host 'pwnd!'"
Get-ProcessById:
Line |
7 | Get-ProcessById "$PID; Write-Host 'pwnd!'"
| ~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot process argument transformation on parameter 'ProcId'. Cannot convert value
"8064; Write-Host 'pwnd!'" to type "System.Int32". Error: "The input string '8064; Write-Host 'pwnd!'
was not in a correct format."
Ici, le $ProcId paramètre d’entrée est limité à un type entier. Par conséquent, une erreur se produit lorsqu’une chaîne est passée qui ne peut pas être convertie en entier.
N’utilisez pas Invoke-Expression
Au lieu d’utiliser Invoke-Expression, appeler Get-Processdirectement et laisser le classeur de paramètres de PowerShell valider l’entrée.
function Get-ProcessById
{
param ($ProcId)
Get-Process -Id $ProcId
}
Get-ProcessById "$PID; Write-Host 'pwnd!'"
Get-Process:
Line |
5 | Get-Process -Id $ProcId
| ~~~~~~~
| Cannot bind parameter 'Id'. Cannot convert value "8064; Write-Host 'pwnd!'" to type
"System.Int32". Error: "The input string '8064; Write-Host 'pwnd!' was not in a correct
format."
En guise de meilleure pratique, vous devez éviter d’utiliser Invoke-Expression, en particulier lors de la gestion des entrées utilisateur.
Invoke-Expression est dangereux parce qu’il analyse et exécute le contenu de chaîne que vous fournissez, ce qui le rend vulnérable aux attaques par injection. Il est préférable de s’appuyer sur la liaison de paramètres PowerShell.
Envelopper des chaînes entre guillemets simples
Toutefois, il existe des moments où l’utilisation de Invoke-Expression est inévitable et vous devez également gérer la chaîne de caractères de l'utilisateur. Vous pouvez gérer en toute sécurité l’entrée utilisateur à l’aide de guillemets uniques autour de chaque variable d’entrée de chaîne. Le guillemet unique garantit que l’analyseur de PowerShell traite l’entrée utilisateur comme un littéral de chaîne unique.
function Get-ProcessById
{
param ($ProcId)
Invoke-Expression -Command "Get-Process -Id '$ProcId'"
}
Get-ProcessById "$PID; Write-Host 'pwnd!'"
Get-Process: Cannot bind parameter 'Id'. Cannot convert value "8064; Write-Host " to type
"System.Int32". Error: "The input string '8064; Write-Host' was not in a correct format."
Toutefois, cette version de la fonction n’est pas sécurisée contre les attaques par injection. Un utilisateur malveillant peut toujours utiliser des guillemets simples dans son entrée pour injecter du code.
Get-ProcessById "$PID'; Write-Host 'pwnd!';'"
Cet exemple utilise des guillemets simples dans l’entrée utilisateur pour forcer la fonction à exécuter trois instructions distinctes, dont l’un est du code arbitraire injecté par l’utilisateur.
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
97 46.08 183.10 1.08 2524 3 pwsh
pwnd!
Utiliser la EscapeSingleQuotedStringContent() méthode
Pour vous protéger contre l'utilisateur insérant ses propres guillemets simples pour exploiter la fonction, vous devez utiliser l'API EscapeSingleQuotedStringContent().
EscapeSingleQuotedStringContent() est une méthode statique publique de la classe PowerShell System.Management.Automation.Language.CodeGeneration . Cette méthode rend l’entrée fournie par l’utilisateur sécurisée en échappant les guillemets uniques inclus dans l’entrée utilisateur.
function Get-ProcessById
{
param ($ProcId)
$ProcIdClean = [System.Management.Automation.Language.CodeGeneration]::
EscapeSingleQuotedStringContent("$ProcId")
Invoke-Expression -Command "Get-Process -Id '$ProcIdClean'"
}
Get-ProcessById "$PID'; Write-Host 'pwnd!';'"
Get-Process: Cannot bind parameter 'Id'. Cannot convert value "8064'; Write-Host 'pwnd!';'" to type
"System.Int32". Error: "The input string '8064'; Write-Host 'pwnd!';'' was not in a correct format."
Pour plus d’informations, consultez EscapeSingleQuotedStringContent().
Détection du code vulnérable avec Injection Hunter
Injection Hunter est un module écrit par Lee Holmes qui contient des règles d’analyseur de script PowerShell pour détecter les vulnérabilités d’injection de code. Utilisez l’une des commandes suivantes pour installer le module à partir de PowerShell Gallery :
# Use PowerShellGet v2.x
Install-Module InjectionHunter
# Use PowerShellGet v3.x
Install-PSResource InjectionHunter
Vous pouvez utiliser ce module pour automatiser l’analyse de la sécurité pendant les builds, les processus d’intégration continue, les déploiements et d’autres scénarios.
$RulePath = (Get-Module -List InjectionHunter).Path
Invoke-ScriptAnalyzer -CustomRulePath $RulePath -Path .\Invoke-Dangerous.ps1
RuleName Severity ScriptName Line Message
-------- -------- ---------- ---- -------
InjectionRisk.InvokeExpression Warning Invoke-Dan 3 Possible script injection risk via the
gerous.ps1 Invoke-Expression cmdlet. Untrusted input can cause
arbitrary PowerShell expressions to be run.
Variables may be used directly for dynamic parameter
arguments, splatting can be used for dynamic
parameter names, and the invocation operator can be
used for dynamic command names. If content escaping
is truly needed, PowerShell has several valid quote
characters, so [System.Management.Automation.Languag
e.CodeGeneration]::Escape* should be used.
Pour plus d’informations, consultez PSScriptAnalyzer.