Dela via


Förhindra skriptinmatningsattacker

PowerShell-skript, liksom andra programmeringsspråk, kan vara sårbara för inmatningsattacker. En inmatningsattack inträffar när en användare ger indata till en sårbar funktion som innehåller extra kommandon. Den sårbara funktionen kör de extra kommandona, vilket kan vara en allvarlig säkerhetsrisk. En obehörig användare kan till exempel missbruka den sårbara funktionen för att köra godtycklig kod på en fjärrdator, vilket kan äventyra datorn och få åtkomst till andra datorer i nätverket.

När du är medveten om problemet finns det flera sätt att skydda mot inmatningsattacker.

Exempel på sårbar kod

Säkerhetsrisker för PowerShell-kodinmatning omfattar användarindata som innehåller skriptkod. Användarindata läggs till i ett sårbart skript där det parsas och körs av PowerShell.

function Get-ProcessById
{
    param ($ProcId)

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

Funktionen Get-ProcessById söker efter en lokal process med dess ID-värde. Det tar ett $ProcId parameterargument av vilken typ som helst. $ProcId Konverteras sedan till en sträng och infogas i ett annat skript som parsas och körs med hjälp av cmdletenInvoke-Expression. Den här funktionen fungerar bra när ett giltigt process-ID-heltal skickas.

Get-ProcessById $pid

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

Parametern $ProcId anger dock ingen typ. Den accepterar alla godtyckliga strängvärden som kan innehålla andra kommandon.

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

I det här exemplet hämtade funktionen den process som identifierades av $pid, men körde även det inmatade skriptet Write-Host 'pwnd!'.

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

Sätt att skydda mot injektionsattacker

Det finns flera sätt att skydda mot en injektionsattack.

Använda indata som skrivits

Du kan ange en typ för $ProcId argumentet.

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

$ProcId Här är indataparametern begränsad till en heltalstyp, så ett fel uppstår när en sträng skickas in som inte kan konverteras till ett heltal.

Använd inte Invoke-Expression

I stället för att använda Invoke-Expressionanropar Get-Processdu direkt och låter PowerShells parameterbindning validera indata.

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

Som bästa praxis bör du undvika att använda Invoke-Expression, särskilt när du hanterar användarindata. Invoke-Expression är farligt eftersom det parsar och kör det stränginnehåll du tillhandahåller, vilket gör det sårbart för inmatningsattacker. Det är bättre att förlita sig på PowerShell-parameterbindning.

Omsluta strängar med enkla citattecken

Det finns dock tillfällen då det inte går att använda Invoke-Expression och du måste också hantera indata för användarsträngar. Du kan hantera användarindata på ett säkert sätt med enkla citattecken runt varje stränginmatningsvariabel. Det enkla citattecknet säkerställer att PowerShells parser behandlar användarindata som en strängliteral.

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

Den här versionen av funktionen är dock ännu inte helt säker från inmatningsattacker. En obehörig användare kan fortfarande använda enkla citattecken i sina indata för att mata in kod.

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

I det här exemplet används enkla citattecken i användarindata för att tvinga funktionen att köra tre separata instruktioner, varav en är godtycklig kod som matas in av användaren.

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

EscapeSingleQuotedStringContent() Använda metoden

För att skydda mot att användaren infogar sina egna enkla citattecken för att utnyttja funktionen måste du använda API:et EscapeSingleQuotedStringContent() . Det här är en statisk offentlig metod för klassen PowerShell System.Management.Automation.Language.CodeGeneration . Den här metoden gör användarens indata säkra genom att undvika alla enkla citattecken som ingår i användarens indata.

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

Mer information finns i EscapeSingleQuotedStringContent().

Identifiera sårbar kod med Injection Hunter

Injection Hunter är en modul skriven av Lee Holmes som innehåller PowerShell Script Analyzer-regler för att identifiera sårbarheter vid kodinmatning. Använd något av följande kommandon för att installera modulen från PowerShell-galleriet:

# Use PowerShellGet v2.x
Install-Module InjectionHunter

# Use PowerShellGet v3.x
Install-PSResource InjectionHunter

Du kan använda detta för att automatisera säkerhetsanalyser under byggen, kontinuerliga integreringsprocesser, distributioner och andra scenarier.

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

Mer information finns i PSScriptAnalyzer.