Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Scripts do PowerShell, como outras linguagens de programação, podem ser vulneráveis a ataques de injeção. Um ataque de injeção ocorre quando um usuário fornece entrada para uma função vulnerável que inclui comandos extras. A função vulnerável executa os comandos extras, o que pode ser uma vulnerabilidade de segurança grave. Por exemplo, um usuário mal-intencionado pode abusar da função vulnerável para executar código arbitrário em um computador remoto, possivelmente comprometendo esse computador e obtendo acesso a outros computadores na rede.
Depois que você estiver ciente do problema, há várias maneiras de se proteger contra ataques de injeção.
Exemplo de código vulnerável
As vulnerabilidades de injeção de código do PowerShell envolvem a entrada do usuário que contém código de script. A entrada do usuário é adicionada ao script vulnerável em que o PowerShell o analisa e executa.
function Get-ProcessById
{
param ($ProcId)
Invoke-Expression -Command "Get-Process -Id $ProcId"
}
A Get-ProcessById função procura um processo local pelo seu valor de ID. Ele usa um $ProcId argumento de parâmetro de qualquer tipo. Depois, $ProcId é convertido em uma cadeia de caracteres e inserido em outro script.
Invoke-Expression o cmdlet analisa e executa a cadeia de caracteres fornecida. Essa função funciona bem quando um identificador de processo que seja um número inteiro válido é passado.
Get-ProcessById $PID
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
97 50.09 132.72 1.20 12528 3 pwsh
No entanto, o $ProcId parâmetro não especifica um tipo. Ele aceita qualquer valor arbitrário de cadeia de caracteres que possa incluir outros comandos.
Get-ProcessById "$PID; Write-Host 'pwnd!'"
Neste exemplo, a função recuperou corretamente o processo identificado por $PID, mas também executou o script Write-Host 'pwnd!'injetado.
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
92 45.66 122.52 1.06 21736 3 pwsh
pwnd!
Maneiras de se proteger contra ataques de injeção
São várias maneiras de se proteger contra um ataque de injeção.
Usar entrada tipada
Você pode especificar um tipo para o $ProcId argumento.
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."
Aqui, o $ProcId parâmetro de entrada é restrito a um tipo inteiro, portanto, ocorre um erro quando uma cadeia de caracteres é passada que não pode ser convertida em um inteiro.
Não use Invoke-Expression
Em vez de usar Invoke-Expression, chamar Get-Processdiretamente e permitir que o associador de parâmetros do PowerShell valide a entrada.
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."
Como prática recomendada, você deve evitar o uso Invoke-Expression, especialmente ao lidar com a entrada do usuário.
Invoke-Expression é perigoso porque analisa e executa qualquer conteúdo de cadeia de caracteres que você fornece, tornando-o vulnerável a ataques de injeção. É melhor confiar na associação de parâmetros do PowerShell.
Encapsular cadeias de caracteres em aspas simples
No entanto, há momentos em que o uso Invoke-Expression é inevitável e você também precisa lidar com a entrada da cadeia de caracteres do usuário. Você pode manipular com segurança a entrada do usuário usando aspas simples em torno de cada variável de entrada de cadeia de caracteres. A única aspa garante que o analisador do PowerShell trate a entrada do usuário como uma única string literal.
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."
No entanto, essa versão da função não está segura contra ataques de injeção. Um usuário mal-intencionado ainda pode usar aspas únicas em sua entrada para injetar código.
Get-ProcessById "$PID'; Write-Host 'pwnd!';'"
Este exemplo usa aspas simples na entrada do usuário para forçar a função a executar três instruções separadas, uma das quais é o código arbitrário injetado pelo usuário.
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
97 46.08 183.10 1.08 2524 3 pwsh
pwnd!
Usar o método EscapeSingleQuotedStringContent()
Para proteger contra o usuário que insere seus próprios caracteres de aspas simples para explorar a função, você deve usar a EscapeSingleQuotedStringContent() API.
EscapeSingleQuotedStringContent() é um método estático público da classe System.Management.Automation.Language.CodeGeneration do PowerShell. Esse método torna a entrada fornecida pelo usuário segura, escapando de todas aspas individuais incluídas na entrada do usuário.
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."
Para obter mais informações, consulte EscapeSingleQuotedStringContent().
Detectando código vulnerável com o Caçador de Injeção
O Caçador de Injeção é um módulo escrito por Lee Holmes que contém regras do Analisador de Scripts do PowerShell para detectar vulnerabilidades de injeção de código. Use um dos seguintes comandos para instalar o módulo da Galeria do PowerShell:
# Use PowerShellGet v2.x
Install-Module InjectionHunter
# Use PowerShellGet v3.x
Install-PSResource InjectionHunter
Você pode usar este módulo para automatizar a análise de segurança durante builds, processos de integração contínua, implantações e outros cenários.
$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.
Para obter mais informações, consulte PSScriptAnalyzer.