PowerShell 스크립트는 다른 프로그래밍 언어와 마찬가지로 삽입 공격에 취약할 수 있습니다. 삽입 공격은 사용자가 추가 명령을 포함하는 취약한 함수에 입력을 제공하는 경우에 발생합니다. 취약한 함수는 심각한 보안 취약성이 될 수 있는 추가 명령을 실행합니다. 예를 들어 악의적인 사용자는 취약한 함수를 악용하여 원격 컴퓨터에서 임의 코드를 실행하여 해당 컴퓨터를 손상시키고 네트워크의 다른 컴퓨터에 액세스할 수 있습니다.
이 문제를 알고 나면 삽입 공격으로부터 보호하는 여러 가지 방법이 있습니다.
취약한 코드의 예
PowerShell 코드 삽입 취약성에는 스크립트 코드가 포함된 사용자 입력이 포함됩니다. 사용자 입력은 PowerShell이 구문 분석하여 실행하는 취약한 스크립트에 추가됩니다.
function Get-ProcessById
{
param ($ProcId)
Invoke-Expression -Command "Get-Process -Id $ProcId"
}
함수는 Get-ProcessById ID 값으로 로컬 프로세스를 조회합니다. 모든 형식의 $ProcId 매개 변수 인수를 사용합니다.
$ProcId 그런 다음 문자열로 변환되고 다른 스크립트에 삽입됩니다.
Invoke-Expression cmdlet은 제공된 문자열을 구문 분석하고 실행합니다. 이 함수는 유효한 프로세스 ID 정수가 전달될 때 정상적으로 작동합니다.
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() 사용해야 합니다.
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()를 참조하세요.
삽입 헌터를 사용하여 취약한 코드 검색
삽입 헌터 는 코드 삽입 취약성을 감지하기 위한 PowerShell 스크립트 분석기 규칙을 포함하는 Lee Holmes가 작성한 모듈입니다. 다음 명령 중 하나를 사용하여 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