115. IP 헤더 분석 — TTL·Flags·Fragment·Checksum 필드 읽는 법

changseop lee·2일 전

네트워크 · 패킷 분석

목록 보기
115/300

📚 네트워크 · 패킷 분석 › 03. Wireshark 패킷 분석 — 115편
이전 글: 114. ARP 패킷 필드 분석 — opcode와 Sender·Target 필드로 IP-MAC 매핑 검증하기 · 다음 글: 116. IPv6 Packet 분석
참고(리눅스 시스템 기초): IP / TCP / UDP / Port — IP 주소와 포트의 기본 개념

1. 왜 알아야 하는가

방화벽·IDS 로그에 남는 IP 정보는 대부분 출발지·목적지 주소와 프로토콜 정도입니다. 그러나 pcap에는 IPv4 헤더의 모든 필드가 남아 있고, 이 필드들은 로그만으로는 답할 수 없는 질문에 단서를 줍니다.

  • 이 패킷은 출발지에서 몇 개의 라우터를 거쳐 왔을까? (ip.ttl)
  • 큰 데이터가 조각(fragment) 으로 나뉘어 왔는가? 조각이 정상적으로 이어지는가? (ip.flags.mf, ip.frag_offset, ip.id)
  • 같은 출발지 IP인데 TTL이 갑자기 달라지지 않았는가?
  • Wireshark가 "체크섬 오류"라고 표시하는 패킷은 정말 손상된 패킷인가, 캡처 환경 때문인가?

TTL과 라우팅의 개념은 17. 게이트웨이와 라우팅 기초 — 다른 네트워크로 패킷은 어떻게 가는가에서, MTU와 단편화의 개념은 28. MTU와 IP 단편화 — 큰 패킷이 쪼개질 때에서 다룹니다. 이 글은 그 개념이 실제 패킷의 어떤 필드에 어떤 값으로 나타나는지에 집중합니다.


2. 핵심 개념

IPv4 헤더 구조
그림 1. IPv4 헤더 필드와 Wireshark 필드명

2-1. IPv4 헤더 필드와 Wireshark 필드명

헤더 항목크기Wireshark 필드분석 시 의미
Version4비트ip.version4 (IPv4)
IHL (헤더 길이)4비트ip.hdr_len바이트로 표시. 옵션이 없으면 20
DS Field8비트ip.dsfield (ip.dsfield.dscp, ip.dsfield.ecn)QoS 표시, 혼잡 알림
Total Length16비트ip.lenIP 헤더 + 데이터 전체 길이
Identification16비트ip.id같은 원본 패킷의 조각을 묶는 번호
Flags3비트ip.flags (ip.flags.rb, ip.flags.df, ip.flags.mf)예약 비트 / 단편화 금지 / 뒤에 조각 더 있음
Fragment Offset13비트ip.frag_offset원본 데이터에서 이 조각의 위치
TTL8비트ip.ttl라우터를 지날 때마다 1씩 감소
Protocol8비트ip.proto1 ICMP, 6 TCP, 17 UDP
Header Checksum16비트ip.checksum (ip.checksum.status)헤더 오류 검출값과 검증 결과
Source / Destination각 32비트ip.src, ip.dst, ip.addr출발지·목적지 주소

2-2. Flags와 Fragment Offset 읽는 법

상황ip.flags.dfip.flags.mfip.frag_offset
단편화되지 않은 일반 패킷 (DF 설정)100
단편화되지 않은 일반 패킷 (DF 미설정)000
첫 번째 조각010
중간 조각010보다 큼
마지막 조각000보다 큼

ip.frag_offset에는 버전별 표시 차이가 있어 주의가 필요합니다. 헤더에 실제로 기록되는 값은 8바이트 단위입니다. Wireshark 4.2 기준으로 상세 트리에는 바이트로 환산한 값(예: Fragment Offset: 1480)이 표시되지만, 필터와 -T fields 출력에는 8바이트 단위 원시값(185)이 사용됩니다. 그래서 ip.frag_offset == 1480은 아무것도 찾지 못하고 ip.frag_offset == 185가 해당 조각을 찾습니다. 다른 버전에서는 표시 방식이 다를 수 있으므로, 필터를 쓰기 전에 -T fields 출력으로 단위를 먼저 확인하는 습관이 안전합니다.

2-3. TTL — 거쳐 온 거리의 단서

TTL 초기값은 OS·장비마다 다르며, 일반적으로 Linux·macOS는 64, Windows는 128, 네트워크 장비는 255를 쓰는 경우가 많습니다. 수신 측에서 본 ip.ttl이 57이라면 "초기값 64에서 7홉을 거쳐 왔을 가능성"을 추정할 수 있습니다. 단, 초기값은 설정으로 바꿀 수 있으므로 OS를 확정하는 근거가 아니라 일관성을 비교하는 기준으로만 씁니다.

2-4. Checksum 검증 상태

ip.checksum.status의미상세 트리 표시
2검증하지 않음 (기본값)[validation disabled], Unverified
1검증 결과 정상Good
0검증 결과 불일치incorrect, should be 0x....

Wireshark는 기본적으로 IP 체크섬을 검증하지 않습니다(ip.check_checksum: FALSE). 이유는 3절의 체크섬 오프로딩 때문입니다.


3. 동작 원리

3-1. 단편화된 패킷을 Wireshark가 다시 조립하는 과정

원본: ICMP 데이터 3008바이트, MTU 1500 구간 통과
          ↓ (출발지 또는 라우터에서 단편화)
조각 1: ip.id=0x7777  mf=1  frag_offset=0    ip.len=1500  → "Fragmented IP protocol"
조각 2: ip.id=0x7777  mf=1  frag_offset=185  ip.len=1500  → "Fragmented IP protocol"
조각 3: ip.id=0x7777  mf=0  frag_offset=370  ip.len=68    → 마지막 조각
          ↓ (Wireshark: 같은 출발지·목적지·프로토콜·ip.id 조각을 모음)
조각 3 프레임에 [3 IPv4 Fragments (3008 bytes): #10(1480), #11(1480), #12(48)] 표시
          ↓
재조립된 ICMP가 조각 3 프레임에서 해석됨

그래서 단편화된 트래픽은 마지막 조각 프레임에서만 상위 프로토콜(ICMP, UDP 등)로 표시되고, 앞선 조각은 IPv4로만 보입니다. 앞 조각을 필터로 찾으려면 icmp가 아니라 ip.flags.mf == 1 || ip.frag_offset > 0을 써야 합니다.

3-2. 체크섬 오프로딩 — "잘못된 체크섬"의 흔한 원인

[송신 호스트 내부]
애플리케이션 → 커널 TCP/IP 스택 → (캡처 지점: tshark/libpcap) → NIC 드라이버 → NIC 하드웨어
                                        ↑                                         ↑
                            여기서는 체크섬이 아직 비어 있을 수 있음      여기서 체크섬 계산 (오프로드)

NIC가 체크섬 계산을 대신하도록 설정되어 있으면, 호스트가 자신이 보내는 패킷을 캡처할 때 체크섬 칸이 비어 있거나 틀린 값으로 보입니다. Linux에서는 IPv4 헤더 체크섬을 커널이 직접 계산하는 경우가 많고 오프로드는 주로 TCP·UDP 체크섬에 적용되지만, OS와 NIC 설정(예: Windows NIC의 IPv4 체크섬 오프로드 옵션)에 따라 IP 헤더 체크섬도 영향을 받을 수 있습니다. 검증을 켜면 Wireshark도 may be caused by "IP checksum offload"?라는 안내를 함께 표시합니다.

결론적으로 송신 측 호스트에서 캡처한 자기 패킷의 체크섬 오류는 대부분 증거 가치가 없습니다. 미러링 포트나 다른 장비에서 캡처한 패킷에서 오류가 보일 때 의미가 있습니다.


4. 실제 명령어 / 실습

실습 환경: 본인 소유 Linux VM (Rocky Linux 또는 Ubuntu). 인터페이스 이름은 ens33을 예시로 사용합니다. tshark 설치는 112편과 같습니다(Rocky: sudo dnf install -y wireshark-cli, Ubuntu: sudo apt install -y tshark).

4-1. 캡처와 트래픽 발생

# 터미널 1: ICMP만 캡처 (단편화 조각도 포함되도록 ip proto 기준)
sudo tshark -i ens33 -f "icmp" -w /tmp/pcap09-ip.pcapng

# 터미널 2
ping -c 3 <게이트웨이 IP>                 # 일반 패킷
ping -c 1 -s 3000 <게이트웨이 IP>         # MTU보다 큰 데이터 → 단편화 발생
ping -c 1 -M do -s 1472 <게이트웨이 IP>   # DF 설정 강제 (1472+8+20 = 1500)

Capture Filter icmp는 첫 조각 뒤의 조각도 IP 프로토콜 번호(1)로 매칭되므로 함께 캡처됩니다. ping -M do는 iputils ping의 옵션으로, DF 비트를 강제로 설정합니다.

📷 [실습 화면 삽입] ping -s 3000 실행 후 Wireshark 목록에 "Fragmented IP protocol"이 보이는 화면

4-2. 필드 단위로 읽기

F=/tmp/pcap09-ip.pcapng

# (1) 주요 IP 헤더 필드
tshark -r $F -T fields -E header=y -E occurrence=f \
  -e frame.number -e ip.src -e ip.dst -e ip.hdr_len -e ip.len \
  -e ip.id -e ip.flags.df -e ip.flags.mf -e ip.frag_offset -e ip.ttl -e ip.proto

# (2) 단편화 조각만
tshark -r $F -Y "ip.flags.mf == 1 || ip.frag_offset > 0" -T fields \
  -e frame.number -e ip.id -e ip.flags.mf -e ip.frag_offset -e ip.len

# (3) 출발지별 TTL 분포 (같은 IP에 TTL이 여러 개인지)
tshark -r $F -T fields -E occurrence=f -e ip.src -e ip.ttl | sort | uniq -c

# (4) 체크섬 검증을 켜고 불일치 패킷 찾기
tshark -r $F -o ip.check_checksum:TRUE -Y "ip.checksum.status == 0" \
  -T fields -e frame.number -e ip.src -e ip.checksum

4-3. 오프로드 설정 확인 (읽기 전용)

# Rocky: sudo dnf install -y ethtool / Ubuntu: sudo apt install -y ethtool
ethtool -k ens33 | grep -i checksum

tx-checksumming: on 이면 송신 패킷의 일부 체크섬이 NIC에서 계산된다는 뜻입니다. 설정은 바꾸지 않고 해석할 때 참고만 합니다.

📷 [실습 화면 삽입] Wireshark 상세 창의 Internet Protocol Version 4 트리 (Flags, Fragment Offset, TTL, Header Checksum 부분)


5. 결과 확인

아래는 형식 예시(값은 환경마다 다름) 입니다.

frame  ip.src         ip.dst         hdr_len  len   ip.id   df     mf     frag_offset  ttl  proto
1      192.168.10.20  192.168.10.1   20       84    0x1a2b  True   False  0            64   1
2      192.168.10.1   192.168.10.20  20       84    0x3c4d  False  False  0            64   1
5      192.168.10.20  192.168.10.1   20       1500  0x7777  False  True   0            64   1
6      192.168.10.20  192.168.10.1   20       1500  0x7777  False  True   185          64   1
7      192.168.10.20  192.168.10.1   20       68    0x7777  False  False  370          64   1
  • 5~7번: 같은 ip.id(0x7777)를 공유하는 세 조각. 마지막 조각만 mf=False
  • frag_offset 185 × 8 = 1480바이트 위치에서 두 번째 조각이 시작
  • 1번은 DF가 설정된 일반 패킷 (Linux ping은 환경에 따라 DF를 설정해 보내는 경우가 많음)

확인 체크리스트

  • ip.hdr_len이 20인 것(옵션 없음)을 확인했다
  • 단편화 조각들이 같은 ip.id를 공유하는 것을 확인했다
  • 마지막 조각에서만 ip.flags.mf가 0인 것을 확인했다
  • ip.frag_offset 값의 단위(8바이트)를 트리 표시와 비교해 확인했다
  • 같은 출발지의 ip.ttl이 일관적인지 확인했다
  • 체크섬 검증을 켰을 때 나온 오류가 자기 송신 패킷(오프로드)인지 구분했다

6. 패킷 / 로그 분석

관찰정상일 수 있는 경우의심해야 하는 경우
같은 출발지 IP의 ip.ttl이 두 가지 이상NAT 뒤의 여러 OS, 경로 변경, 로드밸런서같은 세션 안에서 TTL이 튐 (위조·삽입 패킷 가능성)
매우 작은 ip.ttl (예: 1~3)traceroute, 멀리서 온 패킷내부 서버로 향하는 일반 트래픽인데 TTL이 비정상적으로 작음
단편화 조각 존재큰 UDP(DNS 응답 등), 터널 구간의 MTU 차이매우 작은 조각, 겹치는 조각(ip.fragment.overlap), 끝나지 않는 조각
ip.flags.rb == 1(일반적으로 정상 트래픽에서 사용되지 않음)예약 비트가 설정된 패킷 → 조작된 패킷 가능성
ip.hdr_len > 20 (IP 옵션)일부 특수 프로토콜일반 트래픽에서 IP 옵션 출현
ip.checksum.status == 0송신 호스트 캡처의 오프로드미러링 구간 캡처에서 반복되는 체크섬 오류

확인 명령 예시입니다.

# 같은 출발지에서 TTL 값이 2개 이상인 IP
tshark -r $F -T fields -E occurrence=f -e ip.src -e ip.ttl | sort -u \
  | awk '{c[$1]++; t[$1]=t[$1]" "$2} END {for (i in c) if (c[i]>1) print i, t[i]}'

# 겹치는 조각, 예약 비트, IP 옵션
tshark -r $F -Y "ip.fragment.overlap || ip.flags.rb == 1 || ip.hdr_len > 20"

# TTL이 작은 패킷 (ip.ttl#1 = 바깥쪽 첫 번째 IP 헤더의 TTL)
tshark -r $F -Y "ip.ttl#1 < 5" -T fields -E occurrence=f \
  -e frame.number -e ip.src -e ip.dst -e ip.ttl

ip.ttl < 5로만 쓰면 TTL 초과 ICMP 메시지 안에 들어 있는 원본 헤더의 TTL(1)까지 조건에 걸려 엉뚱한 패킷이 검색됩니다. #1은 몇 번째 계층의 필드인지 지정하는 레이어 연산자로, Wireshark 4.2 기준으로 지원됩니다. 구버전에서 지원되지 않으면 !icmp && ip.ttl < 5처럼 ICMP를 따로 분리해 확인합니다.

TTL을 비교할 때는 같은 방향·같은 세션끼리 비교해야 합니다. 서로 다른 서버에서 온 패킷의 TTL이 다른 것은 당연하기 때문입니다. 또한 ICMP 오류 메시지 안에는 원본 IP 헤더가 한 번 더 들어 있으므로(117편에서 다룸), -E occurrence=f로 바깥 헤더 값만 뽑는 것이 안전합니다.


7. 보안관제 관점

흔적이 남는 곳

  • IDS(Suricata, Snort 등)는 단편화 조각을 재조립한 뒤 검사하며, 비정상 조각(겹침, 잘못된 길이 등)에 대한 이벤트를 따로 기록할 수 있습니다(탐지 규칙은 06. 방화벽 · IDS/IPS 분석 시리즈에서 다룸).
  • 방화벽 로그에는 보통 TTL·ID 같은 헤더 세부값이 남지 않으므로, 이런 세부 판단은 pcap이 있어야 가능합니다.
  • 경로 구조와 TTL 변화의 관계는 17. 게이트웨이와 라우팅 기초 — 다른 네트워크로 패킷은 어떻게 가는가의 traceroute 설명과 함께 보면 이해가 쉽습니다.

한계와 오탐 주의

  • TTL 초기값은 설정으로 바꿀 수 있고, NAT·프록시·로드밸런서를 거치면 원래 값을 알기 어렵습니다. TTL만으로 OS나 위조 여부를 확정하지 않습니다.
  • ip.id 생성 방식은 OS마다 다르고(증가, 무작위, 0 고정 등), 버전에 따라 달라지기도 합니다. ID 패턴으로 결론을 내리지 않고, 조각을 묶는 용도로 주로 씁니다.
  • 체크섬 오류는 캡처 위치에 따라 의미가 완전히 달라집니다. 반드시 어디서 캡처했는지를 함께 기록합니다(증거 기록은 148. pcap 증거 보존과 해시 검증 참고).

8. 핵심 정리

  • IP 헤더 분석의 핵심 필드는 ip.ttl, ip.id, ip.flags.df·ip.flags.mf, ip.frag_offset, ip.proto, ip.checksum입니다.
  • 단편화 조각은 같은 ip.id를 공유하고, 마지막 조각만 mf=0이며, Wireshark는 마지막 조각 프레임에서 재조립 결과를 보여 줍니다.
  • ip.frag_offset은 8바이트 단위 값이며, 트리 표시(바이트)와 필터 값의 단위가 다를 수 있으니 -T fields로 확인합니다.
  • TTL은 OS·경로 추정의 단서일 뿐이고, 같은 세션 안에서의 일관성을 보는 데 가장 유용합니다.
  • Wireshark는 기본적으로 체크섬을 검증하지 않으며, 송신 호스트에서 캡처한 체크섬 오류는 오프로딩 때문인 경우가 대부분입니다.

다음 글: 117. ICMP 패킷 분석 — Type·Code와 오류 메시지 속 원본 헤더 읽기

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

0개의 댓글