📚 네트워크 · 패킷 분석 › 03. Wireshark 패킷 분석 — 122편
이전 글: 121. TCP 3-Way Handshake 분석 · 다음 글: 123. SYN Packet 분석
FIN과 RST의 의미 차이, TIME_WAIT 같은 종료 상태는 42. TCP 상태 전이 — LISTEN부터 TIME_WAIT까지과 45. TCP 연결 종료 — FIN과 RST의 차이에서 다뤘습니다. 이 글은 한 연결(tcp.stream)의 마지막 구간을 보고 "어떻게 끝났는가"를 분류하는 방법을 다룹니다. FIN 패킷 하나, RST 패킷 하나의 필드는 126. FIN Packet 분석, 127. RST Packet 분석에서 따로 봅니다.
종료 분석에 쓰는 필드입니다.
| 필드 | 의미 | 활용 |
|---|---|---|
tcp.flags.fin, tcp.flags.reset | FIN·RST 비트 | 종료 패킷 찾기 |
tcp.connection.fin | Expert Info "Connection finish (FIN)" | FIN 패킷 표시 (Chat 등급) |
tcp.connection.rst | Expert Info "Connection reset (RST)" | RST 패킷 표시 (Warning 등급) |
tcp.connection.fin_active / fin_passive | 먼저 닫은 쪽 / 뒤따라 닫은 쪽의 FIN | 종료 주체 판별 (최근 버전에서 제공) |
tcp.completeness | 16(FIN), 32(RST) 비트 | 스트림 단위 종료 방식 분류 |
tcp.time_relative | 스트림 시작 이후 경과 시간 | 연결 지속 시간 |
정상 종료가 패킷 목록에 나타나는 모습입니다 (A = 먼저 닫는 쪽).
A → B [FIN, ACK] seq = a ← fin_active, A는 더 보낼 데이터 없음
↓
B → A [ACK] ack = a + 1 ← FIN이 seq 1개를 소비했으므로 +1
↓ (B가 남은 데이터를 보낼 수 있음: 반쪽 종료 구간)
B → A [FIN, ACK] seq = b ← fin_passive
↓
A → B [ACK] ack = b + 1 ← A는 TIME_WAIT로 이동
종료 패턴 분류
| 스트림 마지막에 보이는 것 | 분류 | 흔한 원인 |
|---|---|---|
| FIN → ACK → FIN → ACK (또는 3개) | 정상 종료 | 요청·응답 완료 |
| FIN 한쪽만, 반대쪽은 데이터 계속 | 반쪽 종료 진행 중 | 업로드 끝난 뒤 응답 대기 |
| FIN 교환 후 RST | 정상 종료 뒤 늦은 패킷 거부 | 종료 후 도착한 데이터 |
| FIN 없이 RST | 강제 중단 | 애플리케이션 abort, 방화벽·IPS 차단 |
| FIN·RST 모두 없음 | 미종료 | 캡처 종료 시점에 연결 유지 중, 경로 단절 |
| FIN 재전송 반복 | 종료 확인을 못 받음 | 상대 다운, 경로 차단 |
completeness로 본 종료 방식 (Handshake 7 + 데이터 8 기준)
| 값 | 의미 |
|---|---|
| 31 | 성립·데이터·FIN 종료까지 완전 |
| 47 | 성립·데이터 후 RST (FIN 없이) |
| 63 | FIN과 RST가 모두 관찰됨 |
| 15 | 종료 미관찰 |
실습 예시 — 본인 VM에서 웹 요청 몇 건을 캡처해 종료 방식을 분류합니다. 명령과 출력은 예시(값은 환경마다 다름)입니다.
sudo tshark -i ens33 -f "tcp port 80 and host 192.168.10.30" -w /tmp/close.pcapng &
for i in 1 2 3; do curl -s -o /dev/null http://192.168.10.30/; done
sudo pkill -INT tshark
# 종료 관련 패킷만: 누가, 어떤 Flag로
tshark -r /tmp/close.pcapng -Y 'tcp.flags.fin == 1 || tcp.flags.reset == 1' -T fields -E header=y \
-e frame.number -e tcp.stream -e ip.src -e tcp.srcport -e tcp.flags.str \
-e tcp.seq -e tcp.ack -e tcp.time_relative
# 먼저 닫은 쪽 (필드를 지원하는 버전에서)
tshark -r /tmp/close.pcapng -Y 'tcp.connection.fin_active' -T fields -e tcp.stream -e ip.src
# 스트림별 종료 방식 요약
tshark -r /tmp/close.pcapng -2 -T fields -e tcp.stream -e tcp.completeness \
| awk '$2 > m[$1] {m[$1] = $2} END {for (s in m) print s, m[s]}' | sort -n
첫 번째 추출 결과의 형식 예시입니다.
frame stream ip.src srcport flags.str seq ack time_relative
9 0 192.168.10.20 51010 ·······A···F 79 616 0.004210
10 0 192.168.10.30 80 ·······A···F 616 80 0.004502
| 확인 포인트 | 읽는 법 |
|---|---|
| frame 9 출발지가 클라이언트 | curl이 응답을 받은 뒤 먼저 닫음 (fin_active) |
frame 10의 ack 80 | frame 9의 seq 79 + FIN 1 → FIN을 확인하며 자신도 FIN |
| 이후 클라이언트의 ACK 한 개 | 3개 패킷 종료. completeness 31 |
📷 [실습 화면 삽입 위치] Display Filter
tcp.stream == 0을 적용해 마지막 [FIN, ACK] → [FIN, ACK] → [ACK] 세 줄이 보이는 Packet List 화면
📷 [실습 화면 삽입 위치] Analyze → Expert Information에서 Chat의 "Connection finish (FIN)"과 Warning의 "Connection reset (RST)" 항목 개수가 보이는 화면
| 관찰 | 가능한 해석 | 확인할 것 |
|---|---|---|
| 데이터 교환 직후 RST로 끝나는 연결이 특정 서버에 집중 | IPS 차단, 애플리케이션 오류 | RST 출발지·TTL (127. RST Packet 분석) |
| 짧은 데이터 후 서버가 먼저 FIN | 서버 측 인증 실패 후 종료 가능성 | 로그인 반복 여부 (브루트포스는 232편에서 다룸) |
| FIN·RST 없이 수 시간 지속되는 외부 연결 | 원격 제어·터널 가능성 | 주기적 소량 데이터, 목적지 평판 (147. 외부 비정상 통신 분석) |
| 연결 없이 FIN만 도착 (ACK 비트 없음) | FIN 스캔 | 126. FIN Packet 분석, 221편 |
| 대용량 전송 도중 RST | 전송 차단 또는 전송 도구 강제 종료 | 전송 바이트, 방향 |
| 흔적 위치 | 확인할 수 있는 것 |
|---|---|
| 패킷 캡처 | 종료 Flag, 종료 주체, 지속 시간 |
| 방화벽 세션 로그 | 종료 사유(예: tcp-fin, tcp-rst-from-server, aged-out 등, 표기는 장비마다 다름) |
| IDS/IPS | 차단으로 RST를 보냈다는 이벤트 |
| 서버 | ss -tan 의 TIME-WAIT·CLOSE-WAIT 수 |
관제자가 확인할 질문
오탐 주의: 브라우저·HTTP 클라이언트는 빠른 정리를 위해 RST로 연결을 닫는 경우가 있고, 로드밸런서의 유휴 타임아웃도 RST를 만듭니다. "RST = 공격"이 아니며, 캡처 종료 시점에 열려 있던 연결은 미종료로 보이는 것이 정상입니다.
tcp.stream 단위로 마지막 구간의 FIN·RST를 보고 정상 종료·강제 중단·미종료로 분류합니다.tcp.connection.fin_active로 먼저 닫은 쪽을 찾고, 서비스 특성과 맞는지 확인합니다.tcp.completeness 31(FIN)과 47(RST)로 스트림 전체의 종료 방식을 빠르게 분류할 수 있습니다.