Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Los scripts de PowerShell, como otros lenguajes de programación, pueden ser vulnerables a ataques por inyección. Un ataque por inyección se produce cuando un usuario proporciona una entrada a una función vulnerable que incluye comandos adicionales. La función vulnerable ejecuta los comandos adicionales, lo que puede ser una vulnerabilidad de seguridad grave. Por ejemplo, un usuario malintencionado podría abusar de la función vulnerable para ejecutar código arbitrario en un equipo remoto, lo que podría poner en peligro ese equipo y obtener acceso a otras máquinas de la red.
Una vez que sepa el problema, hay varias maneras de protegerse frente a ataques por inyección.
Ejemplo de código vulnerable
Las vulnerabilidades de inyección de código de PowerShell implican la entrada del usuario que contiene código de script. La entrada del usuario se agrega al script vulnerable donde PowerShell lo analiza y ejecuta.
function Get-ProcessById
{
param ($ProcId)
Invoke-Expression -Command "Get-Process -Id $ProcId"
}
La Get-ProcessById
función busca un proceso local por su valor id. Toma un parámetro $ProcId
de cualquier tipo.
$ProcId
se convierte en una cadena de texto e insertada en otro script que es analizado y ejecutado usando el Invoke-Expression
cmdlet. Esta función funciona correctamente cuando se le pasa un entero válido de Id de proceso.
Get-ProcessById $PID
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
97 50.09 132.72 1.20 12528 3 pwsh
Sin embargo, el $ProcId
parámetro no especifica un tipo. Acepta cualquier valor arbitrario de cadena que pueda incluir otros comandos.
Get-ProcessById "$PID; Write-Host 'pwnd!'"
En este ejemplo, la función recuperó correctamente el proceso identificado por $PID
, pero también ejecutó el script Write-Host 'pwnd!'
insertado .
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
92 45.66 122.52 1.06 21736 3 pwsh
pwnd!
Formas de protegerse contra ataques por inyección
Son varias maneras de protegerse contra un ataque por inyección.
Usar entrada por teclado
Puede especificar un tipo para el $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."
Aquí, el $ProcId
parámetro de entrada está restringido a un tipo entero, por lo que se produce un error cuando se pasa una cadena que no se puede convertir en un entero.
No use Invoke-Expression
.
En lugar de usar Invoke-Expression
, llame directamente a Get-Process
y permita que el enlazador de parámetros de PowerShell valide la 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 procedimiento recomendado, debe evitar el uso de Invoke-Expression
, especialmente al manejar la entrada del usuario.
Invoke-Expression
es peligroso porque analiza y ejecuta el contenido de cadena que proporcione, por lo que es vulnerable a los ataques por inyección. Es mejor confiar en la vinculación de parámetros de PowerShell.
Encapsular cadenas entre comillas simples
Sin embargo, hay ocasiones en las que el uso de Invoke-Expression
es inevitable y también es necesario controlar la entrada de texto del usuario. Puede controlar de forma segura la entrada del usuario mediante comillas simples alrededor de cada variable de entrada de cadena. La comilla simple garantiza que el analizador sintáctico de PowerShell trate la entrada del usuario como un literal de cadena único.
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."
Sin embargo, esta versión de la función aún no es completamente segura frente a ataques de inyección. Un usuario malintencionado todavía puede usar comillas simples en su entrada para insertar código.
Get-ProcessById "$PID'; Write-Host 'pwnd!';'"
En este ejemplo se usan comillas simples en la entrada del usuario para forzar que la función ejecute tres instrucciones independientes, una de las cuales es código arbitrario insertado por el usuario.
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
97 46.08 183.10 1.08 2524 3 pwsh
pwnd!
Uso del EscapeSingleQuotedStringContent()
método
Para evitar que el usuario inserte sus propios caracteres de comillas simples para explotar la función, debe utilizar la API EscapeSingleQuotedStringContent()
. Se trata de un método público estático de la clase System.Management.Automation.Language.CodeGeneration de PowerShell. Este método hace que la entrada del usuario sea segura mediante el escape de las comillas simples incluidas en la entrada del usuario.
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 obtener más información, vea EscapeSingleQuotedStringContent().
Detección de código vulnerable con el Cazador de inyección
Injection Hunter es un módulo escrito por Lee Holmes que contiene reglas del Analizador de scripts de PowerShell para detectar vulnerabilidades de inyección de código. Use uno de los siguientes comandos para instalar el módulo desde la Galería de PowerShell:
# Use PowerShellGet v2.x
Install-Module InjectionHunter
# Use PowerShellGet v3.x
Install-PSResource InjectionHunter
Puede usarlo para automatizar el análisis de seguridad durante las compilaciones, los procesos de integración continua, las implementaciones y otros escenarios.
$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 obtener más información, consulte PSScriptAnalyzer.