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 injektážními útoky.

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 PowerShell analyzuje a spouští ho.

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. Invoke-Expression rutina analyzuje a spustí zadaný řetězec. 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žijte psaný vstup

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

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

Nepoužívat Invoke-Expression

Místo použití Invoke-Expression, přímo zavolejte Get-Process a nechte PowerShellův 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 textu, který poskytnete, takže je zranitelná vůči injekčním útokům. Lepší je spoléhat se na vazbu parametrů PowerShellu.

Zabalte řetězce do jednoduchých uvozovek

Jsou však chvíle, kdy je použití Invoke-Expression nevyhnutelné a také potřebujete zvládnout vstup uživatelského řetězce. Uživatelský vstup můžete bezpečně zpracovat pomocí jednoduchých apostrofů kolem každé řetězcové proměnné. Jednoduchá uvozovka zajišťuje, že analyzátor v PowerShellu zachází s uživatelským vstupem 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 není odolná vůči injekčním útokům. 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!

Použijte metodu EscapeSingleQuotedStringContent()

Aby se zabránilo možnosti, že uživatel vloží vlastní apostrofy a tím zneužije funkci, musíte použít rozhraní EscapeSingleQuotedStringContent() API. EscapeSingleQuotedStringContent() je veřejná statická metoda třídy PowerShell System.Management.Automation.Language.CodeGeneration . Tato metoda zajistí bezpečnost vstupu poskytnutého uživatelem tak, že uvozuje všechny apostrofy obsažené 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. Pro instalaci modulu z Galerie 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

Tento modul můžete 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.