Sdílet prostřednictvím


Prevence útoků prostřednictvím injektáže skriptů

Skripty PowerShellu, jako jsou jiné programovací jazyky, můžou být ohrožené útoky prostřednictvím injektáže. Útok prostřednictvím injektáže nastane, když uživatel poskytne vstup do zranitelné funkce, která obsahuje další příkazy. Ohrožená funkce spouští další příkazy, což může být závažná ohrožení zabezpečení. Uživatel se zlými úmysly může například zneužít ohroženou funkci ke spuštění libovolného kódu na vzdáleném počítači, čímž by mohl ohrozit tento počítač a získat přístup k jiným počítačům v síti.

Jakmile o problému víte, existuje několik způsobů, jak chránit před útoky prostřednictvím injektáže.

Příklad zranitelného kódu

Ohrožení zabezpečení injektáže kódu PowerShellu zahrnuje vstup uživatele, který obsahuje kód skriptu. Uživatelský vstup se přidá do zranitelného skriptu, kde se parsuje a spouští pomocí PowerShellu.

function Get-ProcessById
{
    param ($ProcId)

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

Funkce Get-ProcessById vyhledá místní proces podle hodnoty ID. Přebírá argument parametru $ProcId libovolného typu. Potom $ProcId se převede na řetězec a vloží se do jiného skriptu, který se parsuje a spustí pomocí rutiny Invoke-Expression . Tato funkce funguje správně, když se předá platné ID procesu.

Get-ProcessById $pid

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

Parametr $ProcId ale neurčí typ. Přijímá libovolnou řetězcovou hodnotu, která může obsahovat další příkazy.

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

V tomto příkladu funkce správně načetla proces identifikovaný $pid, ale také spustil vložený skript 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!

Způsoby ochrany před útoky prostřednictvím injektáže

Existuje několik způsobů, jak se chránit před útokem prostřednictvím injektáže.

Použití zadaného vstupu

Můžete zadat typ argumentu $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."

$ProcId Vstupní parametr je zde omezen na celočíselnou typ, takže při předání řetězce dojde k chybě, která se nedá převést na celé číslo.

Nepoužívat Invoke-Expression

Místo použití Invoke-Expression, přímé volání Get-Processa nechat powershellový pořadač parametrů ověřit vstup.

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

Osvědčeným postupem je vyhnout se použití Invoke-Expression, zejména při zpracování uživatelského vstupu. Invoke-Expression je nebezpečná, protože analyzuje a spouští jakýkoli obsah řetězce, který poskytnete, takže je zranitelný vůči útokům prostřednictvím injektáže. Lepší je spoléhat se na vazbu parametrů PowerShellu.

Zabalení řetězců v jednoduchých uvozovkách

Existují však časy, kdy použití Invoke-Expression není možné a potřebujete také zpracovat vstup uživatelského řetězce. Uživatelský vstup můžete bezpečně zpracovat pomocí jednoduchých uvozovek kolem každé vstupní proměnné řetězce. Jednoduchá uvozovka zajišťuje, aby analyzátor PowerShellu zachází se vstupem uživatele jako s jedním řetězcovým literálem.

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

Tato verze funkce ale ještě není zcela bezpečná před útoky prostřednictvím injektáže. Uživatel se zlými úmysly může ve svém vstupu použít jednoduché uvozovky k vložení kódu.

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

Tento příklad používá jednoduché uvozovky ve vstupu uživatele, aby funkce spustila tři samostatné příkazy, z nichž jeden je libovolný kód vložený uživatelem.

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

EscapeSingleQuotedStringContent() Použití metody

Pokud chcete chránit před uživatelem vkládáním vlastních jednoduchých uvozovek, abyste mohli funkci zneužít, musíte použít EscapeSingleQuotedStringContent() rozhraní API. Toto je statická veřejná metoda třídy PowerShell System.Management.Automation.Language.CodeGeneration . Tato metoda zajistí bezpečnost uživatelského vstupu tak, že uvozuje všechny jednoduché uvozovky zahrnuté ve vstupu uživatele.

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

Další informace naleznete v tématu EscapeSingleQuotedStringContent().

Detekce zranitelného kódu pomocí nástroje Injection Hunter

Injection Hunter je modul napsaný Lee Holmesem, který obsahuje pravidla analyzátoru skriptů PowerShellu pro detekci ohrožení zabezpečení injektáže kódu. K instalaci modulu z Galerie prostředí PowerShell použijte jeden z následujících příkazů:

# Use PowerShellGet v2.x
Install-Module InjectionHunter

# Use PowerShellGet v3.x
Install-PSResource InjectionHunter

Můžete ho použít k automatizaci analýzy zabezpečení během sestavování, procesů kontinuální integrace, nasazení a dalších scénářů.

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

Další informace naleznete v tématu PSScriptAnalyzer.