yon11b

[SK 쉴더스 루키즈] notepad++ 무결성 검증하기 본문

보안/SK 쉴더스 루키즈

[SK 쉴더스 루키즈] notepad++ 무결성 검증하기

yon11b 2026. 5. 9. 00:20
반응형

들어가며

여러분이 매일 다운로드 받는 프로그램들, 정말 안전할까요?

"공식 사이트에서 받았으니까 괜찮겠지" 라고 생각하기 쉽지만, 현실은 그렇지 않습니다. 2017년 가짜 Notepad++ 사이트 사건, 2020년 SolarWinds 공급망 공격, 2024년 xz-utils 백도어 사건 — 모두 "정식 다운로드처럼 보이지만 실제로는 변조된 파일" 이 핵심이었어요.

만약 Notepad++ 업데이트 서버가 공격당해서 악성코드가 심긴 설치 파일이 배포된다면, 우리는 그걸 어떻게 알아챌 수 있을까요?

 

이 글에서는 GPG 서명 검증을 통해 무결성을 검증하는 방법을 실습해봅니다.

 

 

GPG란?

GPG(GNU Privacy Guard) 는 파일이나 메시지를 암호화하고 디지털 서명하는 오픈소스 도구입니다. 공개키 암호 기반으로 동작합니다.

 

GPG의 3가지 역할

  1. 암호화 — 메시지를 수신자만 읽을 수 있게 만들기
  2. 디지털 서명 — "이 파일은 진짜 내가 만든 것이며 변조되지 않았다"를 증명
  3. 키 관리— 공개키-개인키 쌍 생성과 배포 관리

이번 실습에서 활용할 기능은 2번 디지털 서명입니다.

 

실습에서 등장하는 두 종류의 파일

파일 정체 역할
GPG Signature (.sig)  디지털 서명 특정 파일이 변조되지 않았음을 증명
GPG Public Key (.asc) 공개키 서명을 검증할 때 사용

 

 

디지털 서명의 동작 원리

개발자 측: 서명 만들기

Notepad++ 개발자가 새 버전을 배포하기 전에 하는 일:

1. 원본 파일(notepad.exe)의 SHA-256 해시 계산
   H = SHA-256(notepad.exe)
   
2. 그 해시값을 자신의 개인키로 서명
   S = Sign(H, 개인키)
   
3. S를 .sig 파일로 저장하여 함께 배포

핵심 포인트: 파일 전체를 암호화하는 게 아니라 해시값만 서명합니다. 1GB 파일이든 1KB 파일이든 해시는 32바이트라서 빠르게 처리됩니다.

 

 

사용자 측: 서명 검증하기

다운로드 받은 파일이 진짜인지 확인하는 과정:

1. 받은 원본 파일의 해시 직접 계산
   H1 = SHA-256(notepad.exe)
   
2. 받은 서명 S를 공개키로 검증(복호화)하여 원래 해시 추출
   H2 = Verify(S, 공개키)
   
3. 두 해시값 비교
   H1 == H2  →  ✅ Good signature
   H1 != H2  →  ❌ BAD signature

 

 

왜 이게 위변조를 잡아내는가

세 가지 공격 시나리오를 통해 살펴봅시다.

 

시나리오 1: 파일을 변조했다

공격자가 notepad.exe에 악성코드를 심었지만 서명은 그대로:

H1 = SHA-256(변조된 exe)  = ABC123...
H2 = Verify(원본 sig)      = 7A3F2C...
H1 ≠ H2  →  ❌ 검증 실패

해시는 1바이트만 바뀌어도 완전히 달라지므로 즉시 발각됩니다.

 

시나리오 2: 파일도 바꾸고 서명도 새로 만들었다

공격자가 변조된 파일에 자기 개인키로 새 서명을 만든 경우:

H2 = Verify(가짜 sig, Notepad++ 공개키)
   = (의미 없는 값)
H1 ≠ H2  →  ❌ 검증 실패

공격자에게는 Notepad++ 개발자의 개인키가 없기 때문에, 그 공개키와 짝이 맞는 서명을 만들 수 없습니다.

 

시나리오 3: 다른 버전의 서명을 가져다 붙였다

8.8.4의 sig 파일을 변조된 8.8.5에 붙이는 경우:

H1 = SHA-256(변조된 8.8.5 exe)  = XYZ789...
H2 = Verify(8.8.4의 sig)        = 9B2E1F...
H1 ≠ H2  →  ❌ 검증 실패

서명은 특정 해시값에 종속되어 있어서 다른 파일에는 사용할 수 없습니다.

 

실습: Notepad++ 서명 검증 자동화 스크립트

이제 실제로 검증을 해봅시다. 아래 스크립트는 GPG 키 등록부터 파일 다운로드, 검증까지 한 번에 처리합니다.

#!/bin/bash

# ───── 1. GPG 공개키 등록 (한 번만 하면 됨) ─────
wget https://notepad-plus-plus.org/gpg/nppGpgPub.asc
gpg --import nppGpgPub.asc

# ───── 2. 설치 파일과 서명 파일 주소 ─────
EXE_URL="https://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v8.8.5/npp.8.8.5.Installer.x64.exe"
SIG_URL="https://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v8.8.5/npp.8.8.5.Installer.x64.exe.sig"
EXE_FILE="npp.8.8.5.Installer.x64.exe"
SIG_FILE="npp.8.8.5.Installer.x64.exe.sig"

# ───── 3. 파일 다운로드 ─────
echo "[+] 파일 다운로드"
curl -L -o "$EXE_FILE" "$EXE_URL"
curl -L -o "$SIG_FILE" "$SIG_URL"

# ───── 4. GPG 서명 검증 ─────
echo "[+] GPG 서명 검증"
gpg --verify "$SIG_FILE" "$EXE_FILE"

 

gpg --verify 한 줄이 내부적으로 하는 일

gpg --verify notepad.exe.sig notepad.exe

 

이 명령어 한 줄의 내부 동작을 단계별로 보면:

1. notepad.exe 파일을 읽어 SHA-256 해시 계산
   → H1 = SHA-256(notepad.exe)

2. notepad.exe.sig 파일을 읽어 서명 데이터 추출
   → S = 서명 바이트열

3. GPG 키링에서 적절한 공개키 검색
   (sig 파일에 어떤 키 ID로 서명됐는지 메타데이터로 명시됨)
   → public_key 획득

4. 서명 S를 공개키로 검증하여 원래 해시값 복원
   → H2 = Verify(S, public_key)

5. H1과 H2 비교
   → 일치  → "Good signature"
   → 불일치 → "BAD signature"

이 5단계가 한 줄 명령어 뒤에서 자동으로 일어나는 일입니다.

 

결과


Good signature 메시지가 핵심입니다. 이게 보이면 파일이 변조되지 않았음이 수학적으로 증명된 것입니다.

💡 WARNING은 왜 뜨는가?

"이 공개키가 진짜 Notepad++ 개발자의 키인지 GPG가 자동으로 보증할 수 없다"는 의미입니다. 공식 사이트에 게시된 키 지문(fingerprint)과 위 출력의 지문을 직접 비교하면 더 확실해집니다.

 

 

.exe파일을 변조한 뒤 다시 검증을 시도해봅니다.

Bad signature가 출력됩니다.

 

 

 

 

 

 

 

 

 

 

728x90