Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Скрипты PowerShell, как и другие языки программирования, могут быть уязвимы для инъекционных атак. Атака на внедрение возникает, когда пользователь предоставляет входные данные уязвимой функции, которая включает дополнительные команды. Уязвимая функция запускает дополнительные команды, которые могут быть серьезной уязвимостью безопасности. Например, злоумышленник может злоупотреблять уязвимой функцией для выполнения произвольного кода на удаленном компьютере, возможно, компрометации этого компьютера и получения доступа к другим компьютерам в сети.
После того как вы узнаете о проблеме, существует несколько способов защиты от внедренческих атак.
Пример уязвимого кода
Уязвимости внедрения кода PowerShell включают входные данные пользователя, содержащие код скрипта. Входные данные пользователя добавляются в уязвимый скрипт, который обрабатывает их и выполняет в среде PowerShell.
function Get-ProcessById
{
param ($ProcId)
Invoke-Expression -Command "Get-Process -Id $ProcId"
}
Функция Get-ProcessById
ищет локальный процесс по значению идентификатора. Он принимает $ProcId
аргумент параметра любого типа. Затем $ProcId
конвертируется в строку и вставляется в другой скрипт, который разбирается и запускается с помощью командлета Invoke-Expression
. Эта функция хорошо работает при передаче допустимого целого числа идентификатора процесса.
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()
Чтобы защититься от введения пользователем собственных символов одинарной кавычки для эксплуатации функции, необходимо использовать 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
Охотник за внедрением — это модуль, написанный Ли Холмсом, который содержит правила анализатора скриптов 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.
Связанные ссылки
PowerShell