82. 메일 프로토콜 SMTP·POP3·IMAP

changseop lee·6일 전

📚 네트워크 · 패킷 분석 › 02. 포트 · 프로토콜 분석 — 82편
이전 글: 81. Web Server Port · 다음 글: 83. DB 포트(3306·1433·5432·1521·6379) 노출 점검
참고: 70. DNS 레코드와 질의 유형 — 메일 서버를 찾는 MX 레코드

1. 왜 알아야 하는가

침해 사고의 시작점으로 가장 자주 꼽히는 것이 이메일입니다. 피싱 메일, 악성 첨부파일, 발신자 위조 모두 메일 프로토콜 위에서 일어납니다. 또 감염된 내부 PC가 스팸 발송기가 되거나, 탈취된 계정으로 외부에 메일을 대량 발송하는 사고도 있습니다.

관제에서 메일은 "보안 장비(메일 게이트웨이)가 알아서 막는 영역"으로 생각하기 쉽지만, 경보를 해석하려면 다음을 구분할 수 있어야 합니다.

  • 이 연결은 메일을 보내는 것(SMTP) 인가, 읽는 것(POP3/IMAP) 인가?
  • 25번과 587번은 무엇이 다른가? 일반 PC가 외부 25번으로 접속하면 왜 이상한가?
  • 메일 화면에 보이는 보낸 사람과 실제 전달에 쓰인 발신자는 왜 다를 수 있는가?

2. 핵심 개념

2-1. 역할별 프로토콜과 포트

프로토콜포트역할암호화
SMTPTCP 25메일 서버(MTA) 간 전달STARTTLS로 선택적 암호화
SMTP SubmissionTCP 587사용자(메일 클라이언트) → 자기 메일 서버로 제출, 인증 필수STARTTLS
SMTPSTCP 465제출용, 접속 즉시 TLS암묵적 TLS
POP3TCP 110메일함에서 내려받기(보통 서버에서 삭제)STARTTLS(STLS) 선택
POP3STCP 995POP3 over TLS암묵적 TLS
IMAPTCP 143메일함을 서버에 둔 채 동기화STARTTLS 선택
IMAPSTCP 993IMAP over TLS암묵적 TLS

웹메일 사용자는 브라우저 → 웹메일 서버로 HTTPS(443)만 사용하므로, 사용자 PC에서는 위 포트가 보이지 않을 수 있습니다.

2-2. 봉투(Envelope)와 헤더(Header)

메일은 우편과 비슷하게 봉투와 편지지로 나뉩니다.

구분봉투 (SMTP 명령)헤더 (메일 본문 안)
발신자MAIL FROM:<...>From:
수신자RCPT TO:<...>To:, Cc:
누가 보나메일 서버(전달에 사용)사용자(메일 화면에 표시)
위조서버가 검증하지 않으면 가능본문 일부라 쉽게 작성 가능

두 값이 달라도 SMTP는 전달합니다. 발신자 위조를 줄이기 위해 SPF(보낼 수 있는 서버 IP 목록), DKIM(서명), DMARC(정책·정렬 검사)를 DNS TXT 레코드로 운영합니다. 수신 서버는 결과를 Authentication-Results 헤더에 기록합니다.

2-3. 명령과 응답

프로토콜주요 명령응답 형식
SMTPEHLO, STARTTLS, AUTH, MAIL FROM, RCPT TO, DATA, QUIT3자리 코드: 220 준비, 250 성공, 354 본문 입력, 221 종료, 4xx 일시 오류, 5xx 영구 오류
POP3USER, PASS, STAT, LIST, RETR, DELE, QUIT+OK / -ERR
IMAPa1 LOGIN, a2 SELECT INBOX, a3 FETCH, a4 LOGOUT태그 + OK / NO / BAD

3. 동작 원리

메일 전달 경로
그림 1. 메일 한 통이 거치는 구간과 구간별 포트

3-1. 메일 한 통의 경로

 [보내는 사람 PC]
      │ ① SMTP Submission (587, STARTTLS + AUTH)
      ↓
 [보내는 쪽 메일 서버 (MTA)]  mail.example.com
      │ ② DNS: 받는 도메인의 MX 레코드 질의 → mx.example.net
      │ ③ SMTP (25) 서버 간 전달, STARTTLS 가능하면 사용
      ↓
 [받는 쪽 메일 서버 (MTA) + 스팸/보안 필터]
      │ SPF·DKIM·DMARC 검사, 첨부 검사 → 메일함 저장
      ↓
 [받는 사람 PC]
      ④ IMAP(993) 또는 POP3(995)로 메일함 조회
  • 25번은 서버와 서버, 587/465는 사용자와 자기 서버, 993/995는 사용자와 메일함 구간입니다.
  • 그래서 일반 사용자 PC가 외부 여러 IP의 25번으로 직접 접속한다면, 정상 메일 클라이언트 동작이 아니라 스팸 발송 악성코드를 의심합니다. 많은 조직과 ISP가 사용자 대역의 외부 25번 발신을 차단하는 이유입니다.

3-2. SMTP 대화 예

S: 220 mail.example.com ESMTP Postfix
C: EHLO client.example.com
S: 250-mail.example.com
S: 250-STARTTLS
S: 250 ...
C: MAIL FROM:<alice@example.com>        ← 봉투 발신자
S: 250 2.1.0 Ok
C: RCPT TO:<bob@example.com>            ← 봉투 수신자
S: 250 2.1.5 Ok
C: DATA
S: 354 End data with <CR><LF>.<CR><LF>
C: From: "CEO" <ceo@example.com>        ← 헤더 발신자 (봉투와 다를 수 있음)
C: Subject: test
C:
C: body
C: .
S: 250 2.0.0 Ok: queued as 3F2A1C0001   ← 큐 ID (로그 추적 키)
C: QUIT

4. 실제 명령어 / 실습

실습 환경: 본인 소유 Linux VM (Rocky Linux 또는 Ubuntu), 인터페이스는 ens33을 예시로 사용합니다. Postfix를 로컬 전용(localhost만 수신)으로 설치해 VM 내부 계정끼리만 메일을 주고받습니다. 외부로 메일을 보내지 않습니다.

4-1. 설치

# Rocky Linux (기본 설정이 inet_interfaces = localhost)
sudo dnf install -y postfix s-nail nmap-ncat tcpdump
sudo systemctl enable --now postfix

# Ubuntu (설치 중 설정 화면에서 "Local only" 선택)
sudo apt install -y postfix mailutils netcat-openbsd tcpdump
항목Rocky LinuxUbuntu
메일 로그/var/log/maillog/var/log/mail.log
메일 명령 패키지s-nailmailutils
nc 패키지nmap-ncatnetcat-openbsd
# 수신 범위와 리슨 상태 확인
postconf inet_interfaces
sudo ss -tlnp | grep ':25 '

127.0.0.1:25(및 [::1]:25)로만 리슨하는지 확인합니다. 0.0.0.0:25라면 설정을 localhost로 바꾼 뒤 진행합니다.

4-2. SMTP 대화 직접 해 보기

# 터미널 1: 루프백 25번 캡처
sudo tcpdump -i lo -nn -A 'tcp port 25'
# 터미널 2: -C 옵션으로 줄 끝을 CRLF로 전송
nc -C 127.0.0.1 25

접속 후 아래를 한 줄씩 입력합니다(본인계정은 VM의 실제 사용자 이름).

EHLO lab.local
MAIL FROM:<test@lab.local>
RCPT TO:<본인계정@localhost>
DATA
From: "Notice" <notice@lab.local>
Subject: SMTP lab

hello
.
QUIT

📷 [실습 화면 삽입] nc 화면에서 220 → 250 → 354 → 250 2.0.0 Ok: queued as ... 응답 흐름

4-3. 수신 확인과 로그

# 메일함 확인 (s-nail / mailutils 모두 mail 명령 제공)
mail

# 메일 로그
sudo tail -n 20 /var/log/maillog    # Rocky
sudo tail -n 20 /var/log/mail.log   # Ubuntu

📷 [실습 화면 삽입] 메일 로그에서 같은 큐 ID로 이어지는 smtpd → cleanup → qmgr → local 줄


5. 결과 확인

Postfix 로그 (형식 예시(값은 환경마다 다름))

postfix/smtpd[2201]: connect from localhost[127.0.0.1]
postfix/smtpd[2201]: 3F2A1C0001: client=localhost[127.0.0.1]
postfix/cleanup[2204]: 3F2A1C0001: message-id=<...@lab.local>
postfix/qmgr[1990]: 3F2A1C0001: from=<test@lab.local>, size=412, nrcpt=1 (queue active)
postfix/local[2205]: 3F2A1C0001: to=<user@localhost>, relay=local, delay=12, status=sent (delivered to mailbox)
postfix/qmgr[1990]: 3F2A1C0001: removed
postfix/smtpd[2201]: disconnect from localhost[127.0.0.1] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
로그 요소의미
3F2A1C0001 (큐 ID)메일 한 통을 끝까지 추적하는 키
client=메일을 넘겨준 상대 호스트·IP
from=봉투 발신자 (헤더 From이 아님)
to=, relay=, status=수신자, 전달 방식, 결과(sent / deferred / bounced)

점검 체크리스트

  • Postfix가 localhost에서만 리슨하는 것을 확인했다
  • SMTP 대화에서 220 / 250 / 354 / 250 queued 흐름을 확인했다
  • 봉투 발신자(MAIL FROM)와 헤더 From:을 다르게 넣어도 전달되는 것을 확인했다
  • 메일 로그의 from=이 봉투 발신자라는 것을 확인했다
  • 큐 ID 하나로 접수부터 전달까지 로그를 이어서 읽었다
  • 받은 메일 헤더(Received: 줄)에 전달 경로가 기록된 것을 확인했다

6. 패킷 / 로그 분석

6-1. 판단 기준

관찰정상일 수 있는 경우의심해야 하는 경우
내부 PC → 외부 25번거의 없음(메일은 사내 서버 경유)여러 외부 IP로 25번 직접 접속 = 스팸 봇 감염 의심
Relay access denied 증가설정 오류 클라이언트 몇 건외부에서 제3자 도메인으로 릴레이 시도 반복 (오픈 릴레이 탐색)
SASL ... authentication failed 반복비밀번호 변경 후 클라이언트 미갱신다수 계정·다수 IP 시도 (계정 대입)
한 계정의 발송량 급증공지 메일 발송계정 탈취 후 스팸·피싱 대량 발송
봉투 From ≠ 헤더 From메일링 리스트, 대행 발송 서비스사내 임원 이름·도메인 사칭 + SPF/DMARC 실패
POP3/IMAP 로그인 해외 IP출장 중 사용자짧은 시간 내 서로 먼 국가에서 로그인
평문 110/143 로그인레거시 클라이언트암호화 포트 정책인데 평문 인증 성공

6-2. 로그 예와 확인 명령

# 형식 예시(값은 환경마다 다름)
postfix/smtpd[3310]: NOQUEUE: reject: RCPT from unknown[203.0.113.45]: 554 5.7.1 <x@example.org>: Relay access denied; from=<a@example.net> to=<x@example.org> proto=ESMTP helo=<pc01>
postfix/smtpd[3322]: warning: unknown[198.51.100.23]: SASL LOGIN authentication failed: authentication failure
LOG=/var/log/maillog        # Ubuntu는 /var/log/mail.log

# 릴레이 거부 출발지 집계
sudo grep "Relay access denied" $LOG | grep -oE 'from [^ ]+\[[0-9.]+\]' | sort | uniq -c | sort -rn

# 인증 실패 출발지 집계
sudo grep "authentication failed" $LOG | grep -oE '\[[0-9.]+\]' | sort | uniq -c | sort -rn

# 특정 큐 ID 전체 추적
sudo grep "3F2A1C0001" $LOG

# 봉투 발신자별 발송 건수
sudo grep "qmgr.*from=<" $LOG | grep -oE 'from=<[^>]*>' | sort | uniq -c | sort -rn | head

7. 보안관제 관점

흔적이 남는 곳

위치남는 정보
메일 게이트웨이/스팸 필터발신 IP, SPF·DKIM·DMARC 결과, 첨부 검사, 차단 사유
MTA 로그 (Postfix 등)큐 ID, 봉투 발신·수신자, 릴레이 거부, 인증 실패
메일 헤더Received: 경로, Authentication-Results, Message-ID
방화벽사용자 대역의 외부 25번 발신 시도
POP3/IMAP 서버 로그로그인 성공·실패, 접속 IP (Dovecot 등 서버 종류별 형식 상이)

관제 시 핵심 포인트

  • 사용자 대역 → 외부 25번은 대부분 차단 정책 대상이며, 차단 로그가 반복되면 해당 PC의 감염 여부를 확인합니다.
  • 피싱 분석 시 메일 화면의 보낸 사람보다 봉투 발신자, Received: 첫 홉 IP, 인증 결과를 먼저 봅니다.
  • 계정 탈취는 "로그인 성공(IMAP/웹메일) → 대량 발송 또는 전달 규칙 생성"의 순서로 나타나는 경우가 많습니다. 인증 로그와 발송 로그를 계정 기준으로 연결합니다.

한계와 오탐 주의

  • STARTTLS·TLS 구간에서는 네트워크 장비가 본문·첨부를 볼 수 없습니다. 내용 검사는 메일 서버·게이트웨이 단에서만 가능합니다.
  • 봉투와 헤더 발신자가 다른 것은 메일링 리스트·마케팅 대행 서비스에서 흔한 정상 동작입니다. SPF/DKIM/DMARC 결과와 함께 판단합니다.
  • SPF는 봉투 발신자 도메인 기준으로 검사하므로, 헤더 From만 위조된 경우에는 DMARC 정렬 검사가 있어야 잡힙니다.
  • 헤더의 Received: 줄은 아래(먼저 거친 곳)에서 위로 쌓이며, 공격자가 가짜 Received: 줄을 미리 넣을 수 있으므로 자기 조직 서버가 기록한 줄부터 신뢰합니다.

8. 핵심 정리

  • SMTP 25는 서버 간 전달, 587/465는 사용자 제출(인증), POP3 110/995·IMAP 143/993은 메일함 조회입니다.
  • 메일에는 봉투(MAIL FROM/RCPT TO) 와 헤더(From/To) 가 따로 있어, 발신자 위조가 가능하며 SPF·DKIM·DMARC로 보완합니다.
  • Postfix 로그는 큐 ID로 접수부터 전달까지 추적하며, from=은 봉투 발신자입니다.
  • 관제에서는 내부 PC의 외부 25번 발신, 릴레이 거부 반복, SASL 인증 실패 급증, 계정별 발송량 급증을 주의합니다.
  • 암호화 구간에서는 내용을 볼 수 없으므로 메일 서버·게이트웨이 로그와 헤더 분석이 핵심 근거가 됩니다.

다음 글: 14. SMB와 445 포트 — 내부 확산의 통로

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글