共用方式為


防止腳本插入式攻擊

PowerShell 腳本和其他程式設計語言一樣,很容易遭受插入式攻擊。 當使用者提供包含額外命令之易受攻擊函式的輸入時,就會發生插入式攻擊。 易受攻擊的函式會執行額外的命令,這可以是嚴重的安全性弱點。 例如,惡意使用者可能會濫用易受攻擊的函式,在遠端計算機上執行任意程式碼,可能會危害該計算機,並取得網路上其他計算機的存取權。

一旦你了解這個問題,有幾種方法可以防範注射攻擊。

易受攻擊程式碼的範例

PowerShell 程式代碼插入弱點牽涉到包含腳本程式代碼的用戶輸入。 使用者輸入會被加入有漏洞的腳本,PowerShell 會解析並執行。

function Get-ProcessById
{
    param ($ProcId)

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

函數 Get-ProcessById 會依其 ID 值查閱本地程序。 它接受 $ProcId 作為任意類型的參數。 $ProcId接著會被轉換成字串並插入另一個腳本中。 Invoke-Expression cmdlet 解析並執行提供的字串。 當傳入有效的進程標識碼整數時,此函式會正常運作。

Get-ProcessById $PID

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

不過, $ProcId 參數不會指定類型。 它接受任何可包含其他命令的任意字串值。

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

在這個範例中,函式已正確擷取 $PID 所識別的進程,但也執行了插入的腳本 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!

防範注入攻擊的方法

有幾種方式來防範注入攻擊。

使用鍵入輸入

您可以指定 自變數的類型 $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 輸入參數會限制為整數類型,因此當傳入無法轉換成整數的字串時,就會發生錯誤。

請勿使用 Invoke-Expression

不要使用 Invoke-Expression,而是直接呼叫 Get-Process,並讓PowerShell的參數係結器驗證輸入。

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

最佳做法是,您應該避免使用 Invoke-Expression,尤其是在處理使用者輸入時。 Invoke-Expression 很危險,因為它會剖析和執行您提供的任何字串內容,使其容易受到插入式攻擊。 最好依賴PowerShell參數綁定。

以單引號括住字串

不過,有時候使用 Invoke-Expression 是不可避免的,您也需要處理使用者字串輸入。 您可以使用每個字串輸入變數周圍的單引號安全地處理使用者輸入。 單引號可確保 PowerShell 的解析器將使用者輸入視為純字串。

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

然而,這個版本的功能並不能完全抵禦注射攻擊。 惡意使用者仍然可以在其輸入中使用單引號來插入程序代碼。

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

這個範例會使用使用者輸入中的單引號來強制函式執行三個不同的語句,其中一個是使用者插入的任意程序代碼。

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

使用EscapeSingleQuotedStringContent()方法

為了防止使用者插入自己的單引號字元來利用此功能,您必須使用 EscapeSingleQuotedStringContent() API。 EscapeSingleQuotedStringContent()PowerShell System.Management.Automation.Language.CodeGeneration 類別的公開靜態方法。 此方法透過對使用者輸入中的單引號進行跳脫,來確保輸入的安全性。

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

如需詳細資訊,請參閱 EscapeSingleQuotedStringContent()

使用 Injection Hunter 偵測易受攻擊的程式碼

插入獵人 是由 Lee Holmes 撰寫的模組,其中包含用來偵測程式代碼插入弱點的 PowerShell 腳本分析器規則。 使用下列其中一個命令,從 PowerShell 資源庫安裝模組:

# Use PowerShellGet v2.x
Install-Module InjectionHunter

# Use PowerShellGet v3.x
Install-PSResource InjectionHunter

你可以利用此模組在建置、持續整合流程、部署及其他情境中自動化安全分析。

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

如需詳細資訊,請參閱 PSScriptAnalyzer