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-Process
a 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.