인코딩된 PowerShell 명령을 디코딩하는 방법
- 경보, 프로세스 생성 이벤트, EDR 콘솔에서 명령줄 전체를 복사해 명령줄 또는 Base64에 붙여넣으세요. Base64를 감싼 따옴표가 있어도 됩니다.
- 디코더가 어떤 약어(
-e,-ec,-enc등,-나/모두)로 쓴-EncodedCommand인수든 찾아 디코딩합니다. - 상태 줄에 사용한 문자 인코딩이 표시됩니다. PowerShell이 기대하는 UTF-16LE, 또는 바이트가 UTF-16처럼 보이지 않을 때는 UTF-8입니다.
- 디코딩된 스크립트를 읽으세요.
[Convert]::FromBase64String('…')리터럴이 있으면 감지된 형식과 크기와 함께 아래에 나열됩니다. 텍스트 페이로드는 출력 창에서 열리고, 압축된 페이로드(GzipStream과DeflateStream에 쓰이는 gzip, zlib, raw deflate)에는 압축 해제 버튼이 붙으며, 그 밖의 바이너리 페이로드는 파일로 저장할 수 있습니다.
무해한 예시입니다.
powershell.exe -NoP -NonI -W Hidden -Enc VwByAGkAdABlAC0ATwB1AHQAcAB1AHQAIAAnAGgAZQBsAGwAbwAnAA==
이것은 Write-Output 'hello'로 디코딩됩니다. 같은 텍스트를 UTF-8 Base64로 쓰면 V3JpdGUtT3V0cHV0ICdoZWxsbyc=인데, PowerShell은 이를 거부하거나 잘못 읽습니다.
로그에서 인코딩된 명령 알아보기
UTF-16LE 때문에 인코딩된 스크립트의 시작 부분은 알아보기 쉬운 Base64 형태를 띱니다. 탐지 규칙은 다음 형태와 일치하는지 봅니다.
| Base64 시작 부분 | 스크립트 시작 부분 |
|---|---|
JAB | $ (변수 대입. 예: JABzAD0A는 $s=) |
SQBFAFgA | IEX |
aQBlAHgA | iex |
SQBuAHYAbwBrAGUALQBFAHgAcAByAGUAcwBzAGkAbwBuAA | Invoke-Expression |
SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0AA | Invoke-WebRequest |
TgBlAHcALQBPAGIAagBlAGMAdAA | New-Object |
WwBDAG8AbgB2AGUAcgB0AF0AOgA6AEYAcgBvAG0AQgBhAHMAZQA2ADQAUwB0AHIAaQBuAGcA | [Convert]::FromBase64String |
이 형태는 맨 앞에서만 성립합니다. 스크립트 중간에서는 같은 단어라도 바이트 오프셋을 3으로 나눈 나머지에 따라 Base64 표기가 세 가지이므로, 로그에서 한 가지 표기만 검색하면 나머지 둘을 놓칩니다.
의심스러운 명령을 안전하게 분석하기
인코딩된 명령은 프로세스 목록을 대충 훑어서는 스크립트가 보이지 않게 숨기는 흔한 방법입니다. 경보에 이런 명령이 나타나면 다음을 지키세요.
- 디코딩만 하세요. 이 페이지는 텍스트를 변환할 뿐 어디로도 보내지 않습니다. 명령을 PowerShell 창에 붙여넣지 말고, 디코딩한 출력을 절대
iex에 넘기지 마세요. - 의도와 지표를 읽어 내세요. URL, 도메인, IP 주소, 파일 경로, 레지스트리 키, 예약 작업 이름을 사고 기록과 차단 목록용으로 적어 두세요.
- 추가 계층을 찾으세요. 중첩된
FromBase64String호출,IO.Compression.DeflateStream이나GzipStream, 문자 코드에 대한-join, 문자열 뒤집기가 흔한 래퍼입니다. 계층마다 같은 방식으로 디코딩하세요. - 추출한 바이너리는 샘플로 다루세요. 중첩 목록에서 저장한 페이로드는 악성 코드일 수 있습니다. 해시를 구하고 격리된 환경에서만 분석하세요.
- 이미 평문이 남아 있는 로그를 확인하세요. 스크립트 블록 로깅이 켜져 있으면 Windows는 디코딩된 스크립트를
Microsoft-Windows-PowerShell/Operational에 이벤트 4104로 기록합니다. 프로세스 생성 이벤트(명령줄 감사가 켜진 Security 4688, 또는 Sysmon 이벤트 1)는 인코딩된 명령줄 자체를 기록합니다.
정상적인 용도와 인코딩 탭
관리자는 스크립트가 cmd.exe, 예약 작업, 원격 셸, 구성 관리 도구를 거칠 때의 따옴표 문제를 피하려고 -EncodedCommand를 씁니다. 스크립트 인코딩이 이 인수를 만듭니다. 스크립트를 입력하고, 명령 접두사(powershell -NoProfile -EncodedCommand, pwsh -NoProfile -EncodedCommand, powershell -enc 또는 Base64만)를 고르고 복사하세요. 결과가 cmd.exe의 명령줄 제한인 8,191자를 넘으면 경고가 나타납니다.
Python과 PowerShell에서 디코딩하기
import base64
script = base64.b64decode(b64).decode("utf-16-le")
$script = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b64))
둘 다 텍스트만 돌려줍니다. 인코딩 쪽은 PowerShell Base64 페이지와 UTF-16을 Base64로 변환기에서 더 다룹니다.
자주 생기는 문제
- 출력이 한자처럼 보입니다: UTF-8 Base64를 UTF-16으로 디코딩했습니다. 바이트 패턴이 UTF-16에 맞지 않으면 도구가 UTF-8로 대체하며, 어떤 문자 인코딩을 썼는지 상태 줄에 표시됩니다.
- 올바르지 않은 Base64: 명령이 로그 필드 길이 제한에 잘렸거나 여러 줄로 나뉘었습니다. 조각을 이어 붙이고, Base64 뒤에 붙은 무관한 부분을 지우세요.
- 명령줄이 전혀 디코딩되지 않습니다: Base64가
-EncodedCommand뒤가 아니라-Command "…FromBase64String('…')…"문자열 안에 들어 있을 수 있습니다. Base64 문자열만 붙여넣으세요. UTF-16 텍스트가 아니라면 Base64 디코더나 Base64를 파일로가 그 정체를 보여 줍니다.
자주 묻는 질문
powershell -enc는 무엇을 하나요?
-enc는 -EncodedCommand의 약어입니다. PowerShell은 Base64 인수를 UTF-16LE 텍스트로 디코딩해 스크립트로 실행합니다. -e, -ec 같은 다른 약어도 받습니다.
악성 PowerShell 명령을 여기서 디코딩해도 안전한가요?
디코딩은 텍스트 변환일 뿐 아무것도 실행되지 않으며, 이 페이지의 Content Security Policy가 Cloudflare 조회수 집계를 제외한 모든 네트워크 요청을 막습니다. 무엇을 하는지 보려고 디코딩한 스크립트를 실행하지 마세요. 저장한 바이너리 페이로드는 격리된 분석 환경에서만 다루세요.
Base64에서 한 글자 건너 A가 나오는 이유는 무엇인가요?
PowerShell은 UTF-16LE를 기대하는데, 여기서는 모든 ASCII 문자 뒤에 0 바이트가 붙습니다. 이 0 바이트가 반복되는 A 패턴을 만듭니다. 예를 들어 Write-는 VwByAGkAdABlAC0A입니다.
PowerShell에서 실행하지 않고 -EncodedCommand를 디코딩하려면 어떻게 하나요?
[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b64))를 쓰세요. 텍스트만 돌려줍니다. 결과를 Invoke-Expression이나 iex로 파이프하지 마세요.