TCP, UDP
사용자 데이터그램 프로토콜
인터넷 프로토콜 스위트의 주요 프로토콜 가운데 하나로, 데이터그램으로 알려진 단문 메시지를 교환하기 위해서 사용
연결을 설정하지 않고 수신자가 데이터를 받을 준비를 확인하는 단계를 거치지 않고 단방향으로 정보 전송
신뢰성
수신자가 메시지를 수신했는지 확인할 수 없음
순서 정렬
메시지 도착 순서를 예측할 수 없음
부하
TCP 보다 속도가 일반적으로 빠르고 오버헤더가 적음
8바이트로 고정
출발지 포트, 목적지 포트
16비트 → 65,536개
길이
UDP 페이로드와 UDP 헤더를 더한 데이터그램의 크기
오류 검사
기본적으로 비활성화
전송 제어 프로토콜
인터넷 프로토콜 스위트(IP)의 핵심 프로토콜 중 하나로, IP와 함께 TCP/IP라는 명칭으로도 널리 불린다. TCP는 근거리 통신망이나 인트라넷, 인터넷에 연결된 컴퓨터에서 실행되는 프로그램 간에 일련의 옥텟을 안정적으로, 순서대로, 에러없이 교환할 수 있게 한다. TCP는 전송 계층에 위치한다. 네트워크의 정보 전달을 통제하는 프로토콜이자 인터넷을 이루는 핵심 프로토콜의 하나로서 국제 인터넷 표준화 기구(IETF)의 RFC 793에 기술되어 있다.
연결 지향형 프로토콜
수신 측이 데이터를 흘려버리지 않게 데이터의 흐름 제어(flow control)와 전송 중 에러가 발생한 경우 자동으로 재전송하는 에러 제어(error control) 등의 기능을 통해 데이터의 확실한 전송을 보장
TCP 헤더의 크기는 가변적
TCP Options에 따라 달라지고 Offset에서 지정
출발지와 목적지 포트
16비트 → 65,536
일련 번호(sequence number)
▫ 전송하는 데이터의 순서를 의미 → 수신 측에서 쪼개진 세그먼트의 순서를 파악해서 재조립 할 수 있도록 제공
▫ 최초로 데이터를 전송할 때는 랜덤한 수로 초기화하고, 이후에는 자신이 보낼 데이터의 1바이트 당 일련번호를 1씩 증가시켜서 데이터의 순서를 표현
확인 또는 승인 번호(knowledgement number)
▫ 수신자가 예상하는 다음 일련 번호를 의미
▫ 데이터를 주고 받을 때는 상대방이 보낸 일련 번호 + 자신이 받은 데이터의 바이트 수를 확인 번호로 설정
▫ 연결 설정과 연결 해제 과정에서는 상대방이 보낸 일련 번호 + 1을 확인 번호로 설정 (핸드쉐이킹 과정에서는 데이터를 주고 받지 않음)
오프셋
전체 세그먼트에서 헤더가 아닌 데이터가 시작되는 위치를 표시
📢 여기서 잠깐!
세그먼트 → TPC 헤더 + TCP 페이로드
데이터가 시작되는 위치 → TCP 헤더의 끝을 의미하는데 이는 TCP 헤더의 크기가 가변적이므로 필요
Flag | 뜻 |
---|---|
CWR (Congestion Window Reduced) | 혼잡 윈도우 크기 감소 신호 |
ECN (Explicit Congestion Notification) | 혼잡 신호 발생 |
URG (Urgent) | 긴급 데이터 |
ACK (Acknowledgement) | 확인 응답 신호 |
PSH (Push) | 수신 측에 데이터를 최대한 빠르게 응용 프로그램에게 전달 |
RST (Reset) | 연결을 강제로 초기화해달라는 요청 |
SYN (Synchronize) | 연결 생성 |
FIN (Finish) | 연결 종료 |
윈도우 크기
슬라이딩 윈도우(sliding window) 크기
= 한번에 전송할 수 있는 데이터의 양(크기)
오류 검사
데이터 송수신 중에 발생하는 오류를 검출하기 위해 사용
긴급 포인트
URG 플래그가 설정된 경우, 해당 데이터를 우선 처리
https://www.kisa.or.kr/2060204/form?postSeq=12&lang_type=KO&page=1#fnPostAttachDownload
16비트(65536개를 표현하는 것이 가능)로 구성된 가상적 주소
운영체제에서 응용 계층에 속하는 프로토콜을 고유한 식별자 번호로 인식할 때 사용하는 번호
IANA(Internet Assigned Numbers Authority) 기구에서 관리
잘 알려진 포트 번호(well known port)
▫ 0 ~ 1023
▫ 잘 알려진 특정 애플리케이션의 사용을 위해 ICANN(Internet Corporation for Assigned Names and Numbers)에서 할당한 포트
▫ 일반적으로 서버에서 사용
▫ c:\Windows\system32\drivers\etc\services
프로토콜 | 포트번호 | 비고 | 뜻 |
---|---|---|---|
ftp | 21/tcp | # FTP. control | |
ssh | 22/tcp | # SSH Remote Login Protocol | |
telnet | 23/tcp | ||
smtp | 25/tcp | # Simple Mail Transfer Protocol | |
domain | 53/tcp | # Domain Name Server | |
domain | 53/udp | # Domain Name Server | |
http | 80/tcp | www www-http | # World Wide Web |
pop3 | 110/tcp | # Post Office Protocol - Version 3 | |
https | 443/tcp | MCom | # HTTP over TLS/SSL |
포트번호 | 이름 | 비고 |
---|---|---|
1433 | MSQSQL | |
3306 | MySQL | |
8080 | HTTP | 개발용도 |
원격지 호스트를 대상으로 어떤 포트를 사용하고 있는지 확인하는 기법
✔ nmap
오픈소스 기반의 포트 스캐닝 도구
┌──(kali㉿kali)-[~]
└─$ nmap -p 80 bee.box
~~~~~ ~~~~~~~
| +-- 호스트
+-- 스캔할 포트 번호
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-25 04:07 EDT
Nmap scan report for bee.box (192.168.45.3)
Host is up (0.0018s latency).
PORT STATE SERVICE
80/tcp open http # 해당 포트로 서비스 중
Nmap done: 1 IP address (1 host up) scanned in 0.18 seconds
┌──(kali㉿kali)-[~]
└─$ nmap -p 9999 bee.box
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-25 04:10 EDT
Nmap scan report for bee.box (192.168.45.3)
Host is up (0.0060s latency).
PORT STATE SERVICE
9999/tcp closed abyss # 해당 포트로 서비스하지 않음
Nmap done: 1 IP address (1 host up) scanned in 0.42 seconds
아래 그림에서 (1)~(10)에 들어갈 값은?
SNY, ACK는 TCP 플래그 값을 SN,
AN는 Sequence number와 Acknowlegment number를 의미
클라이언트 서버
SYN=(1) SN=767 (1) 1 → 연결 요청 시 설정
ACK=(2) AN=(3) (2) 0
--------------------------------> (3) 0
ACK=(4) AN=(5) (4) 1
SYN=(6) SN=373 (5) 768 = 767 + 1
<-------------------------------- (6) 1
SYN=(7) SN=(8) (7) 0
ACK=(9) AN=(10) (8) 768
--------------------------------> (9) 1
(10) 374 = 373 + 1
kali 가상머신에서 https://drive.google.com/drive/folders/1JHymvvQZX1x8xkbGuoRqL9yCqv5Jjowq 공유 폴더에 있는 http.pcapng 파일 다운로드
응용 계층에서 페이로드를 생성하고 전송 전에 3단계 연결 설정을 수행
응용 계층에서 생성한 페이로드를 응용 계층 버퍼에 임시 보관하고 전송 계층에서 SYN 신호를 담은 세그먼트 한 개를 생성
SYN 세그먼트는 네트워크 계층, 데이터 링크 계층, 물리 계층을 통과해서 수신지로 전달
수신 측에서는 해당 SYN 신호를 전송 계층까지 끌어올린 후 전송 계층에서 SYN/ACK 신호를 담은 세그먼트를 생성해서 송신지로 전달
송신 측에서는 해당 SYN/ACK 신호를 전송 계층까지 끌어올린 후 전송 계층에서 ACK 신호를 담은 세그먼트를 생성해서 수신지로 전달해서 3단계 설정을 완료
3단계 연결 설정이 완료되면 운영체제는 응용 계층 버퍼에 저장했던 TCP 페이로드를 전송 계층으로 전달
전송 계층은 응용 계층에서 전달된 TCP 페이로드를 대상으로 단편화를 수행
📢 여기서 잠깐! 단편화(fragmentation)란?
전송 효율성과 데이터 기밀성을 위해 TCP 페이로드를 여러 개로 분할하는 기법
단편화가 끝나면 조각난 페이로드 앞에 출발지 포트와 목적지 포트 등을 담은 헤더가 붙으면서 여러 개의 세그먼트를 생성하고 각 세그먼트는 네트워크 계층으로 넘가면서 각각의 패킷을 생성
네트워크 계층(L3)에서 각 세그먼트/데이터그램 앞에 IP 주소를 추가한 것
일반적으로 IP 헤더는 20바이트 크기를 사용 (IP Option 항목을 이용해 21바이트 이상으로 사용이 가능)
서비스 종류(Type of Service)
해당 패킷의 전송 우선 순위를 지정 (회선이 혼잡할 경우 패킷의 전송 우선 순위를 부여할 때 사용)
전체 길이
IP 헤더를 포함한 패킷 전체의 길이
Identification, IP Flags, Fragement Offset
MTU(Maximum Transmission Unit, 최대 전송 단위)에 따른 패킷 분할 정보
IP Flags → 패킷 분할 여부를 표시
▫ D: Do not fragement
▫ M: More fragement
MTU 1500 바이트인 이더넷 구간을 1400 바이크 크기의 패킷이 통과하는 경우 → 패킷 분할 X
ID IP flags Fragment offset
X D M
-------------- ---------------- ----------------
0 0 1 0 0
ID IP flags Fragment offset
X D M
-------------- ---------------- ----------------
1234 0 0 1 0
1234 0 0 1 1500
1234 0 0 1 3000
1234 0 0 0 4500
생존 시간(TTL, Time To Live)
해당 패킷이 통과할 수 있는 라우터의 개수
프로토콜
상위 계층에 속한 프로토콜 번호
→ 수신 측에서 해당 패킷의 속성을 파악하는데 사용
헤더 오류 검사
비활성화 상태
출발지 IP 주소, 목적지 IP 주소
32비트의 IP 주소
https://scapy.net/
파이썬으로 제작된 패킷 조작 프로그램
패킷 캡처, 전송, 수정, 디코딩 등의 다양한 기능 제공
┌──(kali㉿kali)-[~]
└─$ sudo scapy
[sudo] password for kali:
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
aSPY//YASa
apyyyyCY//////////YCa |
sY//////YSpcs scpCY//Pp | Welcome to Scapy
ayp ayyyyyyySCP//Pp syY//C | Version 2.5.0
AYAsAYYYYYYYY///Ps cY//S |
pCCCCY//p cSSps y//Y | https://github.com/secdev/scapy
SPPPP///a pP///AC//Y |
A//A cyP////C | Have fun!
p///Ac sC///a |
P////YCpc A//A | To craft a packet, you have to be a
scccccp///pSP///p p//Y | packet, and learn how to swim in
sY/////////y caa S//P | the wires and in the waves.
cayCyayP//Ya pY/Ya | -- Jean-Claude Van Damme
sY/PsY////YCc aC//Yp |
sc sccaCY//PCypaapyCP//YSs
spCPY//////YPSps
ccaacs
using IPython 8.14.0
>>>
>>> ls() → 지원하는 프로트콜 목록
>>> ls(TCP) → 현재 설정된 TCP 헤더 정보 출력
sport : ShortEnumField = ('20')
dport : ShortEnumField = ('80')
seq : IntField = ('0')
ack : IntField = ('0')
dataofs : BitField (4 bits) = ('None')
reserved : BitField (3 bits) = ('0')
flags : FlagsField = ('<Flag 2 (S)>')
window : ShortField = ('8192')
chksum : XShortField = ('None')
urgptr : ShortField = ('0')
options : TCPOptionsField = ("b''")
>>> TCP().display()
###[ TCP ]###
sport = ftp_data
dport = http
seq = 0
ack = 0
dataofs = None
reserved = 0
flags = S
window = 8192
chksum = None
urgptr = 0
options = ''
>>> TCP().show()
###[ TCP ]###
sport = ftp_data
dport = http
seq = 0
ack = 0
dataofs = None
reserved = 0
flags = S
window = 8192
chksum = None
urgptr = 0
options = ''
>>> lsc() → 사용 가능한 기능 목록
>>> help(TCP) → 도움말
>>> help()
Welcome to Python 3.11's help utility!
If this is your first time using Python, you should definitely check out
the tutorial on the internet at https://docs.python.org/3.11/tutorial/.
Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules. To quit this help utility and
return to the interpreter, just type "quit".
To get a list of available modules, keywords, symbols, or topics, type
"modules", "keywords", "symbols", or "topics". Each module also comes
with a one-line summary of what it does; to list the modules whose name
or summary contain a given string such as "spam", type "modules spam".
help>
https://scapy.readthedocs.io/en/latest/installation.html#windows
>>> IP().show()
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = hopopt
chksum = None
src = 127.0.0.1
dst = 127.0.0.1
\options \
>>> ip = IP()
>>> ip.show()
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = hopopt
chksum = None
src = 127.0.0.1
dst = 127.0.0.1
\options \
>>> ip.dst = "192.168.40.130" → ping bee.box 를 통해 확인
bee.box 가상머신의 IP 주소
>>> ip.show()
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = hopopt
chksum = None
src = 192.168.40.129 → kali.linux 가상머신의 IP 주소
dst = 192.168.40.130 → bee.box 가상머신의 IP 주소
\options \
>>> ip = IP(dst="192.168.40.130") → 생성자에 매개변수의 값을
설정하는 방법으로 초기화
>>> ip.show()
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = hopopt
chksum = None
src = 192.168.40.129
dst = 192.168.40.130
\options \
네트워크 상에서 움직이는 트래픽을 염탐하는 행위
>>> sniff() → 시간이 조금 경과한 후 Ctrl+C
<Sniffed: TCP:20 UDP:784 ICMP:0 Other:1> → 스니핑 결과를 요약 출력
>>> sf = sniff() → Ctrl + C 로 중지
>>> sf.show()
0000 Ether / IP / UDP 3.112.113.156:20003 > 192.168.0.143:53955 / Raw
0001 Ether / IP / UDP 18.183.11.144:20003 > 192.168.0.143:57520 / Raw
0002 Ether / IP / UDP 192.168.0.143:57734 > 18.183.11.144:20003 / Raw
:
2110 Ether / IP / UDP / DNS Ans "b'googlehosted.l.googleusercontent.com.'"
# 연결 요청
2111 Ether / IP / TCP 192.168.0.143:53808 > 142.250.206.193:https S
2112 Ether / IP / UDP 18.183.11.144:20003 > 192.168.0.143:57734 / Raw
2113 Ether / IP / UDP 3.112.113.156:20003 > 192.168.0.143:53955 / Raw
2114 Ether / IP / UDP 192.168.0.143:57734 > 18.183.11.144:20003 / Raw
:
2124 Ether / IP / UDP 104.18.23.107:https > 192.168.0.143:50362 / Raw
2125 Ether / IP / UDP 18.183.11.144:20003 > 192.168.0.143:57520 / Raw
2126 Ether / IP / UDP 192.168.0.143:57734 > 18.183.11.144:20003 / Raw
2127 Ether / IP / UDP 192.168.0.143:49297 > 142.250.206.206:https / Raw
# 연결 수락
2128 Ether / IP / TCP 142.250.206.193:https > 192.168.0.143:53808 SA
# 연결 수락 확인
2129 Ether / IP / TCP 192.168.0.143:53808 > 142.250.206.193:https A
2130 Ether / IP / TCP 192.168.0.143:53808 > 142.250.206.193:https PA / Raw
2131 Ether / IP / UDP 192.168.0.143:53955 > 3.112.113.156:20003 / Raw
2132 Ether / IP / UDP 192.168.0.143:57520 > 18.183.11.144:20003 / Raw
2133 Ether / IP / UDP 192.168.0.143:53955 > 3.112.113.156:20003 / Raw
2134 Ether / IP / UDP 192.168.0.143:57734 > 18.183.11.144:20003 / Raw
>>> sf[2111].show() → 인덱스 2111번의 패킷 상세 조회
###[ Ethernet ]###
dst = 9c:a2:f4:e8:44:3c
src = d0:3c:1f:1f:e7:3f
type = IPv4
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 52
id = 59149
flags = DF
frag = 0
ttl = 128
proto = tcp
chksum = 0x0
src = 192.168.0.143
dst = 142.250.206.193
\options \
###[ TCP ]### sport = 53808
dport = https
seq = 1752058677
ack = 0
dataofs = 8
reserved = 0
flags = S
window = 64240
chksum = 0x1f1a
urgptr = 0
options = [('MSS', 1460), ('NOP', None), ('WScale', 8), ('NOP', None), ('NOP', None), ('SAckOK', b'')]
>>>
>>> sf = sniff(count=10) → 캡쳐할 패킷의 갯수 지정
>>> sf.show()
0000 Ether / IP / UDP 3.112.113.156:20003 > 192.168.0.143:53955 / Raw
0001 Ether / IP / TCP 104.18.22.107:https > 192.168.0.143:57984 PA / Raw
0002 Ether / IP / UDP 192.168.0.143:57734 > 18.183.11.144:20003 / Raw
0003 Ether / IP / UDP 192.168.0.143:57734 > 18.183.11.144:20003 / Raw
0004 Ether / IP / UDP 18.183.11.144:20003 > 192.168.0.143:57520 / Raw
0005 Ether / IP / UDP 192.168.0.143:53955 > 3.112.113.156:20003 / Raw
0006 Ether / IP / UDP 192.168.0.143:57520 > 18.183.11.144:20003 / Raw
0007 Ether / IP / UDP 192.168.0.143:57734 > 18.183.11.144:20003 / Raw
0008 Ether / IP / UDP 192.168.0.143:57734 > 18.183.11.144:20003 / Raw
0009 Ether / IP / TCP 192.168.0.143:57984 > 104.18.22.107:https A
https://code.visualstudio.com/docs/setup/linux
$ sudo apt-get install wget gpg
$ wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg
$ ls
Desktop Documents Downloads help.py Music packages.microsoft.gpg Pictures Public Templates test.py Videos
$ sudo install -D -o root -g root -m 644 packages.microsoft.gpg /etc/apt/keyrings/packages.microsoft.gpg
$ sudo sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list'
$ rm -f packages.microsoft.gpg
$ sudo apt install apt-transport-https
$ sudo apt update
$ sudo apt install code
$ sudo scapy
>>> tcp = TCP()
>>> tcp.show()
###[ TCP ]###
sport = ftp_data → 1024 이후의 임의 포트로 설정
dport = http
seq = 0
ack = 0
dataofs = None
reserved = 0
flags = S → SYN (연결요청)
window = 8192
chksum = None
urgptr = 0
options = ''
>>> tcp.sport = RandNum(1024, 65535)
>>> tcp.show()
###[ TCP ]###
sport = <RandNum>
dport = http
seq = 0
ack = 0
dataofs = None
reserved = 0
flags = S
window = 8192
chksum = None
urgptr = 0
options = ''
>>> ip = IP()
>>> ip.show()
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = hopopt
chksum = None
src = 127.0.0.1
dst = 127.0.0.1 → bee-box 가상머신의 IP 주소로 변경
\options \
>>> ip.dst = "192.168.40.130" → 다른 터미널에서 ping bee.box 명령으로 확인
>>> ip.show()
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = hopopt
chksum = None
src = 192.168.40.129
dst = 192.168.40.130
\options \
>>> syn = ip / tcp → TCP 세그먼트에 IP 헤더를 덧붙여 SYN 패킷 생성
>>> syn.show()
###[ IP ]###
version = 4
ihl = None
tos = 0x0
len = None
id = 1
flags =
frag = 0
ttl = 64
proto = tcp
chksum = None
src = 192.168.40.129
dst = 192.168.40.130
\options \
###[ TCP ]###
sport = <RandNum>
dport = http
seq = 0
ack = 0
dataofs = None
reserved = 0
flags = S
window = 8192
chksum = None
urgptr = 0
options = ''
>>> syn_ack = sr1(syn) → 전송하고 첫번째 응답이 올 때까지 대기
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
>>> syn_ack.show()
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 44
id = 0
flags = DF
frag = 0
ttl = 64
proto = tcp
chksum = 0x6878
src = 192.168.40.130
dst = 192.168.40.129
\options \
###[ TCP ]###
sport = http
dport = 3952
seq = 2694158463
ack = 1
dataofs = 6
reserved = 0
flags = SA
window = 5840
chksum = 0x661c
urgptr = 0
options = [('MSS', 1460)]
###[ Padding ]###
load = '\x00\x00'
>>> ack = ip / TCP(sport=syn_ack[TCP].dport, dport=syn_ack[TCP].sport, flags="A", seq=syn_ack[TCP].ack, ack=syn_ack[TCP].seq+1)
>>> send(ack)
.
Sent 1 packets.
kali linux 가상머신에서 진행
from scapy.all import *
# tcp = TCP()
# tcp.sport = RnadNum(1024, 65535)
# tcp.dport = "80"
# tcp.flags = "S"
tcp = TCP(sport=RandNum(1024, 65535), dport=80, flags='S')
# ip = IP()
# ip.src = "192.168.40.129"
# ip.dst = "192.168.40.130"
ip = IP(src="192.168.40.129", dst="192.168.40.130")
syn = ip / tcp
syn_ack = sr1(syn)
ack = ip / TCP(sport=syn_ack[TCP].dport, dport=syn_ack[TCP].sport, flags="A", seq=syn_ack[TCP].ack, ack=syn_ack[TCP].seq+1)
send(ack)
┌──(kali㉿kali)-[~]
└─$ sudo python3 handshaking.py
[sudo] password for kali:
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
.
Sent 1 packets.
$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
$ sudo iptables -A OUTPUT -p tcp --tcp-flags RST RST -s 192.168.40.129 -j DROP
iptables: No chain/target/match by that name. ~~~~~~~~~~~~~~
# kali IP
$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DROP tcp -- kali.linux anywhere tcp flags:RST/RST