패킷(Packet)이란?
1. 특징
- 네트워크를 통해 전송되는 기본 정보 단위이다.
- 데이터가 패킷으로 형식이 바뀔 때, 네트워크는 장문 메시지를 더 효과적이고 신뢰성 있게 보낼 수 있다.
- 패킷은 데이터의 한 단위라고 할 수 있다.
2. 구성 - 헤더 + 페이로드(데이터/내용)
헤더(header)
- 패킷 헤더에는, 패킷의 주소(송수신 주소) 등 주요 제어 정보들이 포함되어있다.
ex) TCP헤더, UDP헤더, IP헤더, MAC헤더
캡슐화(EnCapsulation)
컴퓨터가 다른 컴퓨터에게 데이터를 전송하기 위해서 상위계층인 Application Layer(응용 계층)에서 데이터가
Transport Layer(전송 계층)로 내려간다.
데이터를 다시 하위계층으로 전송하기 위해 UDP 헤더와 데이터 정보를 캡슐화하여 Internet Layer(인터넷 계층)로 내려보낸다.
다시 IP 헤더와 데이터를 캡슐화하여 하위계층으로 전송한다.
반대로 데이터를 전송 받은 컴퓨터는 하위계층에서부터 헤더와 캡슐화된 정보를 제거하면서 상위계층으로 전달한다.
데이터가 Application Layer에 전달되었을때 정보의 전달이 완료된다.
패킷을 여러 개의 헤더로 나누어서 분석해보자.
1.b'\x00\x0c)o\xad\x1a\x00PV\xcc\xcc\x10\x08\x00E\x00\x00!\x00\x00@\x00@\x11\xa2H
\xc0\xa8\x0b\x8d\xc0\xa8\x0b\xa6\x82\xb5u0\x00\r+\x98hello\x00\x00\x00\x00\x00\
x00\x00\x00\x00\x00\x00\x00\x00'
2.b'\x00PV\xcc\xcc\x10\x00\x0c)o\xad\x1a\x08\x00E\x00\x00!\x00\x00@\x00@\x11\xa2H
\xc0\xa8\x0b\xa6\xc0\xa8\x0b\x8du0\x82\xb5\x00\r\x98\xa2hello'
이렇게 두가지의 패킷을 확인할 수 있는데 우선 두번째 패킷부터 분석해보자.
전송 계층(Tranport Layer/4)
- 대표적인 프로토콜 : TCP, UDP
- 주소 체계 : PORT
UDP 헤더 - u0\x82\xb5\x00\r\x98\xa2hello
- 데이터를 뺀 나머지 헤더의 길이는 8바이트(byte)로 고정 크기를 갖는다.
- UDP 헤더의 실제 길이는 데이터를 포함한 길이(가변적)
- header(8바이트) + data(5바이트 ex-'hello') = total (13바이트)
- TCP 헤더는 더 많은 필드를 가지고 있다.
출발지 포트번호 |
2byte |
u0 |
0x75 0x30 |
30000 |
도착지 포트번호 |
2byte |
\x82\xb5 |
0x82 0xb5 |
33461 |
헤더의 전체 크기 |
2byte |
\x00\r |
0x00 0x0d |
13 |
체크섬 |
2byte |
\x98\xa2 |
0x98 0xa2 |
39074 |
데이터 | 5byte | hello |
|
|
패킷 분석하는 방법
1. 계산기를 이용한다.
도착지 포트번호를 계산기를 이용해서 분석해보자
프로그래머용 계산기를 킨다. HEX는 16진수 DEC는 10진수를 뜻한다.
도착지 포트 번호 - 0x82 0xb5
계산기에 그대로 값을 넣어주면 DEX에 도착지 포트번호 33461이 나온것을 확인할 수 있다.
그럼 헤더의 전체 크기인 \x00\r 는 어떻게 변환할까 여기서 r은 문자가 아니다.
\x00r 과 \x00\r은 다르다. 이스케이프 표를 확인해보자
문자 'r'은 0x72의 값을 갖고
'\r'은 0x0D의 값을 갖는다.
항상 계산기로 변환해주면 귀찮으므로 다른 방법을 보자.
2. 파이썬에서 내장 함수 이용
파이썬에서 내장 함수를 이용해 출발지 포트번호 u0을 변환해보자.
여기서 'u'와 '0' 둘다 1바이트 크기의 문자이다.
>>> a = b'u0' // 파이썬에서 문자열은 유니코드이므로, 아스키코드로 바꿔준다.
아스키코드는 1바이트이며 0~127 사이의 숫자에 코드가 있다.
>>> a = hex(a[0]) // a[0]은 'u'의 아스키코드 값 117이다. hex()는 10진수를 117을 16진수 0x75로 바꿔준다.
>>> b = hex(a[1]) // a[1]은 48 hex(48)은 0x30
>>> (a << 8) | b // 0x75 와 0x30을 2바이트 하나로 계산해야하기 때문에 0x75를 왼쪽으로 8비트 시프트 연산 해준다.
30000
a = 0111 0101 b = 0011 0000 인데 우리가 원하는 값은 0111 0101 0011 0000 이다.
그럼 a를 왼쪽 시프트 연산으로 8비트 계산하면
a = 0111 0101 0000 0000
b = 0000 0000 0011 0000
----------------------------------------------------- OR
0111 0101 0011 0000 = 30000
3. struct 모듈 사용
>>> import struct
>>> byte = b'u0\x82\xb5\x00\r\x98\xa2hello'
>>> struct.unpack('!HHHH', byte[:8])
(30000, 33461, 13, 39074)
>>> a = (30000, 33461, 13, 39074)
>>> struct.pack('!HHHH', a[0], a[1], a[2], a[3])
b'u0\x82\xb5\x00\r\x98\xa2'
'Hacking > Network' 카테고리의 다른 글
[7일차] 이더넷 헤더 패킷 분석하기 (0) | 2017.09.20 |
---|---|
[6일차] IP 헤더 패킷 분석하기 (0) | 2017.09.19 |
Raw 소켓 프로그래밍 (0) | 2017.09.15 |
[4일차] 파이썬을 이용한 UDP 소켓 프로그래밍 (0) | 2017.09.14 |
파이썬을 이용한 TCP 소켓 프로그래밍 (0) | 2017.09.13 |
WRITTEN BY