Delen via


Aanvallen met scriptinjectie voorkomen

PowerShell-scripts, zoals andere programmeertalen, kunnen kwetsbaar zijn voor injectieaanvallen. Een injectieaanval treedt op wanneer een gebruiker invoer levert aan een kwetsbare functie die extra opdrachten bevat. De kwetsbare functie voert de extra opdrachten uit, wat een ernstig beveiligingsprobleem kan zijn. Een kwaadwillende gebruiker kan bijvoorbeeld misbruik maken van de kwetsbare functie om willekeurige code uit te voeren op een externe computer, waardoor deze computer mogelijk in gevaar komt en toegang krijgt tot andere computers in het netwerk.

Zodra u op de hoogte bent van het probleem, zijn er verschillende manieren om te beschermen tegen injectieaanvallen.

Voorbeeld van kwetsbare code

PowerShell-code-injectieproblemen omvatten gebruikersinvoer die scriptcode bevat. De gebruikersinvoer wordt toegevoegd aan een kwetsbaar script waar het wordt geparseerd en uitgevoerd door PowerShell.

function Get-ProcessById
{
    param ($ProcId)

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

De Get-ProcessById functie zoekt een lokaal proces op met de id-waarde. Er wordt een $ProcId parameterargument van elk type gebruikt. De $ProcId wordt vervolgens geconverteerd naar een tekenreeks en ingevoegd in een ander script dat wordt geparseerd en uitgevoerd met behulp van de Invoke-Expression cmdlet. Deze functie werkt prima wanneer een geldig proces-id-geheel getal wordt doorgegeven.

Get-ProcessById $pid

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

De $ProcId parameter geeft echter geen type op. Hiermee wordt elke willekeurige tekenreekswaarde geaccepteerd die andere opdrachten kan bevatten.

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

In dit voorbeeld heeft de functie het proces dat is geïdentificeerd, $pidcorrect opgehaald, maar ook het geïnjecteerde script Write-Host 'pwnd!'uitgevoerd.

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

Manieren om te beschermen tegen injectieaanvallen

De zijn verschillende manieren om te beschermen tegen een injectieaanval.

Getypte invoer gebruiken

U kunt een type opgeven voor het $ProcId argument.

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 is de $ProcId invoerparameter beperkt tot een geheel getaltype, dus er treedt een fout op wanneer een tekenreeks wordt doorgegeven die niet kan worden geconverteerd naar een geheel getal.

Niet gebruiken Invoke-Expression

In plaats van de parameterbinding van Invoke-ExpressionPowerShell rechtstreeks aan te roepen Get-Processen de invoer te valideren.

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 best practice moet u het gebruik Invoke-Expressionvermijden, met name bij het verwerken van gebruikersinvoer. Invoke-Expression is gevaarlijk omdat deze inhoud parseert en uitvoert welke tekenreeksinhoud u opgeeft, waardoor deze kwetsbaar is voor injectieaanvallen. Het is beter om te vertrouwen op PowerShell-parameterbinding.

Tekenreeksen verpakken in enkele aanhalingstekens

Er zijn echter momenten waarop het gebruik Invoke-Expression onvermijdelijk is en u ook invoer van gebruikersreeksen moet verwerken. U kunt gebruikersinvoer veilig verwerken met enkele aanhalingstekens rond elke tekenreeksinvoervariabele. De enkele aanhalingsteken zorgt ervoor dat de parser van PowerShell de invoer van de gebruiker behandelt als één letterlijke tekenreeks.

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

Deze versie van de functie is echter nog niet volledig veilig tegen injectieaanvallen. Een kwaadwillende gebruiker kan nog steeds enkele aanhalingstekens gebruiken in hun invoer om code in te voeren.

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

In dit voorbeeld worden enkele aanhalingstekens in de invoer van de gebruiker gebruikt om te forceren dat de functie drie afzonderlijke instructies uitvoert, waarvan een willekeurige code is die door de gebruiker is geïnjecteerd.

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

EscapeSingleQuotedStringContent() De methode gebruiken

Als u de gebruiker wilt beschermen tegen het invoegen van hun eigen enkele aanhalingstekens om gebruik te maken van de functie, moet u de EscapeSingleQuotedStringContent() API gebruiken. Dit is een statische openbare methode van de klasse PowerShell System.Management.Automation.Language.CodeGeneration . Deze methode maakt de invoer van de gebruiker veilig door enkele aanhalingstekens in de gebruikersinvoer te ontsnappen.

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

Zie EscapeSingleQuotedStringContent()voor meer informatie.

Kwetsbare code detecteren met Injection Hunter

Injection Hunter is een module geschreven door Lee Holmes die PowerShell Script Analyzer-regels bevat voor het detecteren van beveiligingsproblemen met code-injectie. Gebruik een van de volgende opdrachten om de module te installeren vanuit de PowerShell Gallery:

# Use PowerShellGet v2.x
Install-Module InjectionHunter

# Use PowerShellGet v3.x
Install-PSResource InjectionHunter

U kunt dit gebruiken om beveiligingsanalyses te automatiseren tijdens builds, processen voor continue integratie, implementaties en andere scenario's.

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

Zie PSScriptAnalyzer voor meer informatie.