Freigeben über


Verhindern von Skripteinschleusungsangriffen

PowerShell-Skripts wie andere Programmiersprachen können anfällig für Einfügungsangriffe sein. Ein Einfügungsangriff tritt auf, wenn ein Benutzer Eingaben für eine anfällige Funktion bereitstellt, die zusätzliche Befehle enthält. Die anfällige Funktion führt die zusätzlichen Befehle aus, bei denen es sich um eine schwerwiegende Sicherheitslücke handeln kann. Beispielsweise könnte ein böswilliger Benutzer die anfällige Funktion missbrauchen, um beliebigen Code auf einem Remote-Computer auszuführen, wodurch dieser Computer möglicherweise kompromittiert wird und Zugriff auf andere Computer im Netzwerk erlangt.

Sobald Sie das Problem kennen, gibt es mehrere Möglichkeiten zum Schutz vor Injektionsangriffen.

Beispiel für anfälligen Code

Sicherheitsanfälligkeiten bei der PowerShell-Codeeinfügung umfassen Benutzereingaben, die Skriptcode enthalten. Die Benutzereingabe wird zu anfälligen Skripts hinzugefügt, in denen sie analysiert und von PowerShell ausgeführt wird.

function Get-ProcessById
{
    param ($ProcId)

    Invoke-Expression -Command "Get-Process -Id $ProcId"
}

Die Get-ProcessById Funktion sucht einen lokalen Prozess anhand des ID-Werts. Es verwendet ein $ProcId Parameterargument eines beliebigen Typs. Anschließend wird $ProcId in eine Zeichenfolge konvertiert und in ein anderes Skript eingefügt, das mithilfe des Invoke-Expression-Cmdlets analysiert und ausgeführt wird. Diese Funktion funktioniert einwandfrei, wenn eine gültige Prozess-ID-Ganzzahl übergeben wird.

Get-ProcessById $PID

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     97    50.09     132.72       1.20   12528   3 pwsh

Der $ProcId Parameter gibt jedoch keinen Typ an. Er akzeptiert beliebige Zeichenfolgenwerte, die andere Befehle enthalten können.

Get-ProcessById "$PID; Write-Host 'pwnd!'"

In diesem Beispiel hat die Funktion den von $PIDder Funktion identifizierten Prozess richtig abgerufen, aber auch das eingefügte Skript Write-Host 'pwnd!'ausgeführt.

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     92    45.66     122.52       1.06   21736   3 pwsh
pwnd!

Möglichkeiten zum Schutz vor Injektionsangriffen

Dies sind mehrere Möglichkeiten, um vor einem Injektionsangriff zu schützen.

Getippten Input verwenden

Sie können einen Typ für das $ProcId Argument angeben.

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."

Hier ist der $ProcId Eingabeparameter auf einen ganzzahligen Typ beschränkt, daher tritt ein Fehler auf, wenn eine Zeichenfolge übergeben wird, die nicht in eine ganze Zahl konvertiert werden kann.

Verwenden Sie nicht Invoke-Expression.

Statt Invoke-Expression zu verwenden, rufen Sie direkt Get-Process auf und lassen Sie den Parameterbinder von PowerShell die Eingabe überprüfen.

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."

Als bewährte Methode sollten Sie die Verwendung Invoke-Expressionvermeiden, insbesondere bei der Behandlung von Benutzereingaben. Invoke-Expression ist gefährlich, weil es den von Ihnen bereitgestellten Zeichenfolgeninhalt analysiert und ausführt, wodurch es anfällig für Injectionangriffe ist. Es ist besser, sich auf die PowerShell-Parameterbindung zu verlassen.

Zeichenfolgen in einfachen Anführungszeichen umschließen

Es gibt jedoch Zeiten, in denen die Verwendung von Invoke-Expression unvermeidbar ist und Sie auch Benutzereingaben von Zeichenfolgen behandeln müssen. Sie können Benutzereingaben sicher verarbeiten, indem Sie jede Zeichenfolgenvariable in einfache Anführungszeichen setzen. Das einfache Anführungszeichen sorgt dafür, dass der PowerShell-Parser die Benutzereingabe als einen einzigen string wörtlich behandelt.

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."

Diese Version der Funktion ist jedoch noch nicht vollständig vor Injektionsangriffen sicher. Ein böswilliger Benutzer kann weiterhin einzelne Anführungszeichen in seiner Eingabe verwenden, um Code einzugeben.

Get-ProcessById "$PID'; Write-Host 'pwnd!';'"

In diesem Beispiel werden einzelne Anführungszeichen in der Benutzereingabe verwendet, um zu erzwingen, dass die Funktion drei separate Anweisungen ausführt, von denen ein beliebiger Code vom Benutzer eingefügt wird.

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     97    46.08     183.10       1.08    2524   3 pwsh
pwnd!

Verwenden der EscapeSingleQuotedStringContent() Methode

Zum Schutz davor, dass Benutzer einfache Anführungszeichen einfügen, um die Funktion auszunutzen, müssen Sie die EscapeSingleQuotedStringContent() API verwenden. Dies ist eine statische öffentliche Methode der PowerShell System.Management.Automation.Language.CodeGeneration-Klasse . Mit dieser Methode wird die Benutzereingabe sicher, indem einzelne Anführungszeichen in der Benutzereingabe entfernt werden.

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."

Weitere Informationen finden Sie unter EscapeSingleQuotedStringContent().

Erkennen anfälligen Codes mit Injection Hunter

Injection Hunter ist ein Modul von Lee Holmes, das Regeln des PowerShell Script Analyzers zum Erkennen von Schwachstellen bei Code-Injektionen enthält. Verwenden Sie einen der folgenden Befehle, um das Modul aus dem PowerShell-Katalog zu installieren:

# Use PowerShellGet v2.x
Install-Module InjectionHunter

# Use PowerShellGet v3.x
Install-PSResource InjectionHunter

Sie können dies verwenden, um die Sicherheitsanalyse bei Builds, kontinuierlichen Integrationsprozessen, Bereitstellungen und anderen Szenarien zu automatisieren.

$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.

Weitere Informationen finden Sie unter PSScriptAnalyzer.