📚 네트워크 · 패킷 분석 › 03. Wireshark 패킷 분석 — 126편
이전 글: 125. ACK Packet 분석 · 다음 글: 127. RST Packet 분석
FIN은 "이 방향으로 더 보낼 데이터가 없다"는 신호입니다. 연결 종료 전체 순서는 122. TCP Connection 종료 분석, FIN과 RST의 개념 차이는 45. TCP 연결 종료 — FIN과 RST의 차이에서 다뤘습니다. 이 글은 FIN 비트가 켜진 패킷 하나를 펼쳤을 때 확인할 필드와, 정상 종료에 쓰인 FIN과 연결과 상관없이 날아온 FIN을 구분하는 방법에 집중합니다.
| 확인 항목 | Wireshark 필드 | 정상 FIN에서의 모습 |
|---|---|---|
| Flag 조합 | tcp.flags | 0x011 (FIN, ACK) 또는 0x019 (FIN, PSH, ACK) |
| ACK 비트 | tcp.flags.ack | 1 (성립한 연결의 FIN에는 항상 켜짐) |
| 데이터 | tcp.len | 0이 많지만 마지막 데이터와 함께 올 수 있음 |
| 다음 seq | tcp.nxtseq | seq + len + 1 (FIN이 1 소비) |
| Expert Info | tcp.connection.fin | "Connection finish (FIN)" |
| 종료 주체 | tcp.connection.fin_active / fin_passive | 먼저 닫은 쪽 / 뒤따른 쪽 (버전에 따라 제공) |
| 재전송 여부 | tcp.analysis.retransmission | 없어야 정상 |
FIN 패킷의 seq·ack가 어떻게 이어지는지 Wireshark 상대값으로 보면 다음과 같습니다.
Client → Server [PSH, ACK] seq=1 len=78 nxtseq=79
Server → Client [PSH, ACK] seq=1 len=615 nxtseq=616
Client → Server [FIN, ACK] seq=79 len=0 nxtseq=80 ← FIN이 seq 1 소비
↓
Server → Client [FIN, ACK] seq=616 ack=80 nxtseq=617 ← 클라이언트 FIN 확인 + 자기 FIN
↓
Client → Server [ACK] seq=80 ack=617 ← 서버 FIN 확인
FIN이 포함된 Flag 조합별 해석
tcp.flags | Info 열 | 해석 |
|---|---|---|
| 0x011 | [FIN, ACK] | 가장 흔한 정상 종료 |
| 0x019 | [FIN, PSH, ACK] | 마지막 데이터와 종료를 한 번에 (정상) |
| 0x001 | [FIN] | ACK 없는 FIN. 성립 연결에서는 나오지 않음 → FIN 스캔 가능성 |
| 0x029 | [FIN, PSH, URG] | Xmas 스캔으로 불리는 조작 조합 |
| 0x003 | [SYN, FIN] | 정상 흐름에 없음 → 조작 패킷 |
FIN 관련 필터
| 목적 | Display Filter |
|---|---|
| 모든 FIN | tcp.flags.fin == 1 |
| ACK 없는 FIN (스캔 의심) | tcp.flags.fin == 1 && tcp.flags.ack == 0 |
| 데이터가 실린 FIN | tcp.flags.fin == 1 && tcp.len > 0 |
| 재전송된 FIN | tcp.flags.fin == 1 && tcp.analysis.retransmission |
| 먼저 닫은 쪽의 FIN | tcp.connection.fin_active |
실습 예시 — 본인 VM 간 HTTP 요청의 FIN을 추출해 seq 관계를 검증합니다. 명령과 출력은 예시(값은 환경마다 다름)입니다.
sudo tshark -i ens33 -f "tcp port 80 and host 192.168.10.30" -w /tmp/fin.pcapng &
curl -s -o /dev/null http://192.168.10.30/
sudo pkill -INT tshark
# FIN 패킷과 그 직후 ACK를 한 번에 보기 (FIN 또는 FIN을 확인한 ACK)
tshark -r /tmp/fin.pcapng -Y 'tcp.flags.fin == 1 || (tcp.flags == 0x010 && tcp.len == 0)' \
-T fields -E header=y -e frame.number -e tcp.stream -e ip.src -e tcp.flags.str \
-e tcp.seq -e tcp.len -e tcp.nxtseq -e tcp.ack | tail -4
# ACK 없는 FIN이 있는지 (정상 캡처라면 결과 없음)
tshark -r /tmp/fin.pcapng -Y 'tcp.flags.fin == 1 && tcp.flags.ack == 0' | wc -l
형식 예시입니다.
frame stream ip.src flags.str seq len nxtseq ack
7 0 192.168.10.20 ·······A···· 79 0 616
8 0 192.168.10.20 ·······A···F 79 0 80 616
9 0 192.168.10.30 ·······A···F 616 0 617 80
10 0 192.168.10.20 ·······A···· 80 0 617
| 확인 포인트 | 읽는 법 |
|---|---|
| frame 7 → 8 seq 그대로 79 | 순수 ACK는 seq를 소비하지 않음 |
frame 8 nxtseq 80 | 데이터 0 + FIN 1 → seq 79의 다음은 80 |
frame 9 ack 80 | 클라이언트 FIN을 정확히 확인 |
frame 10 ack 617 | 서버 FIN(616) + 1 → 종료 완료 |
tcp.nxtseq는 데이터나 SYN·FIN이 없는 순수 ACK에는 표시되지 않습니다(버전에 따라 표시 방식이 다를 수 있음).
📷 [실습 화면 삽입 위치] [FIN, ACK] 패킷 Details에서 Flags의 Fin 비트,
[Next Sequence Number], Expert Info "Connection finish (FIN)"이 함께 보이는 화면
| 관찰 | 가능한 해석 | 확인할 것 |
|---|---|---|
| SYN 없이 ACK 없는 FIN이 여러 포트로 | FIN 스캔 (221편) | 대상의 응답: 닫힌 포트는 RST, 열린 포트는 대개 무응답 |
| FIN·PSH·URG 조합, SYN+FIN 조합 | 조작 패킷, 필터 우회 시도 | 출발지의 다른 스캔 흔적 |
| FIN 재전송 반복 후 RST | 상대가 사라짐, 경로 차단 | 같은 시각 다른 연결 상태 |
| 데이터 전송 도중 서버의 즉시 FIN | 서버 측 거부·오류 후 종료 | 마지막 응답 내용 (134. Follow TCP Stream) |
FIN 스캔에서 "무응답 = 열림"이라는 해석은 RFC 793 규칙을 따르는 스택 기준이며, 일부 OS는 포트 상태와 무관하게 RST를 보내므로 결과를 단정하지 않습니다.
| 흔적 위치 | 확인할 수 있는 것 |
|---|---|
| 패킷 캡처 | FIN Flag 조합, seq 관계, 종료 주체 |
| 방화벽 로그 | 세션 없는 FIN 차단(invalid 등), 세션 종료 사유 |
| IDS/IPS | FIN·Xmas·NULL 스캔 시그니처 |
| 플로우 로그 | 세션 누적 Flag에 FIN 포함 여부 |
관제자가 확인할 질문
tcp.stream에 SYN·데이터)에 속하는가?오탐 주의: 방화벽 세션이 먼저 만료된 뒤 도착한 늦은 FIN/ACK도 "세션 없는 FIN"으로 차단 로그에 남습니다. ACK 비트 유무와 반복 대상 수를 함께 보고 스캔 여부를 판단합니다.
tcp.connection.fin으로 FIN을, fin_active로 먼저 닫은 쪽을 찾습니다.