#실습에 앞서 방화벽에서 RST패킷의 전송을 차단해야 합니다
#iptables -A OUTPUT -o eth0 -p tcp --tcp-flags RST RST -j DROP
#iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
이전에 만들어 놓았던 TCP서버 파일을 이용해 2개의 서버에 대해 세션을 형성하도록 하겠습니다
#python3 tcp_server.py => 서버와 포트번호 개방 ( 2개의 가상머신에서 이루어져야함 )
1> SYN패킷 전송 ( Client -> Server )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | import random import socket from header.udp import * from header.eth import * from header.ip import * from header.tcp import * def make_chksum( header ): size = len( header ) if size % 2: header = header + b'\x00' size = len( header ) size = size // 2 header = struct.unpack('!' + str(size) + 'H', header ) chksum = sum( header ) carry = chksum & 0xFF0000 carry = carry >> 16 while carry != 0: chksum = chksum & 0xFFFF chksum = chksum + carry carry = chksum & 0xFF0000 carry = carry >> 16 chksum = chksum ^ 0xFFFF return chksum eth = Eth() ip = Ip() tcp = Tcp() tcp.src = 53917 tcp.dst = 39269 tcp.sequence_number = 1 tcp.acknowledge_number = 0 tcp.hlen = 0 tcp.flag = 2 tcp.window_size = 14 tcp.chksum = 0 tcp.urgent_point = 15 tcp.data ='' tcp.hlen = len(tcp.header) ip.ver = 4 ip.length = 20 ip.service = 0 ip.total = 20 + len( tcp.header ) ip.id = 0x1234 ip.flag = 0 ip.offset = 0 ip.ttl = 64 ip.type = 6 ip.chksum = 0 ip.src ='192.168.6.123' ip.dst ='192.168.6.200' ip.chksum = make_chksum( ip.header ) pseudo = ip._src + ip._dst + b'\x00' + ip._type + b'\x00\x14' + tcp.header tcp.chksum = make_chksum(pseudo) eth.dst = '00:50:56:31:a8:43' eth.src = '00:0C:29:F0:62:73' eth.type = 0x0800 sock = socket.socket(socket.AF_PACKET , socket.SOCK_RAW) sock.bind(('eth0',socket.SOCK_RAW)) sock.send( eth.header + ip.header + tcp.header ) | #cs |
2> SYN+ACK패킷으로 응답 ( Server -> Client )
3> ACK패킷 전송 ( Client -> Server )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | import random import socket from header.udp import * from header.eth import * from header.ip import * from header.tcp import * def make_chksum( header ): size = len( header ) if size % 2: header = header + b'\x00' size = len( header ) size = size // 2 header = struct.unpack('!' + str(size) + 'H', header ) chksum = sum( header ) carry = chksum & 0xFF0000 carry = carry >> 16 while carry != 0: chksum = chksum & 0xFFFF chksum = chksum + carry carry = chksum & 0xFF0000 carry = carry >> 16 chksum = chksum ^ 0xFFFF return chksum #a = random.randrange( 1,255) #b = random.randrange( 1,255) #c = random.randrange( 1,255) #d = random.randrange( 1,255) #src = str(a) + '.' + str(b) + '.' + str(c) + '.' + str(d) eth = Eth() ip = Ip() tcp = Tcp() tcp.src = 18762 tcp.dst = 42721 tcp.sequence_number = 2 tcp.acknowledge_number = 2836578417 tcp.hlen = 0 tcp.flag = 16 tcp.window_size = 14 tcp.chksum = 0 tcp.urgent_point = 15 tcp.data ='' tcp.hlen = len(tcp.header) ip.ver = 4 ip.length = 20 ip.service = 0 ip.total = 20 + len( tcp.header ) ip.id = 0x1234 ip.flag = 0 ip.offset = 0 ip.ttl = 64 ip.type = 6 ip.chksum = 0 ip.src ='192.168.6.123' ip.dst ='192.168.6.200' ip.chksum = make_chksum( ip.header ) pseudo = ip._src + ip._dst + b'\x00' + ip._type + b'\x00\x14' + tcp.header tcp.chksum = make_chksum(pseudo) eth.dst = '00:50:56:31:a8:43' eth.src = '00:0C:29:F0:62:73' eth.type = 0x0800 sock = socket.socket(socket.AF_PACKET , socket.SOCK_RAW) sock.bind(('eth0',socket.SOCK_RAW)) sock.send( eth.header + ip.header + tcp.header ) | cs |
4> ACK + FIN ( Server -> Client ) //TCP세션연결 후 자동 접속 종료되게 프로그래밍 하였음
[ 그림1 ]
#1 SYN 클라이언트에서 서버로 SYN패킷을 전송한다
Flag = 2 ( SYN )
Sequence Number = 1
#2 SYN + ACK 서버는 클라이언트에게 SYN패킷을 받았다고 응답해준다 ( 클라이언트의 시퀀스 번호 +1증가 시킨다 )
Flag = 18 ( ACK + SYN )
Sequence Number = 2836578416 ( 서버에서 생성한 값 )
Acknowledge = 2 ( 서버에서 클라이언트에게 보내는 값 // Client의 ISN = ISN + 1 )
[ 그림2 ]
#1 ACK 클라이언트는 서버에서 보낸 SYN+ACK에 대한 응답으로 ACK패킷을 서버에게 전송한다 ( 서버의 시퀀스번호 +1증가시킨다 )
Flag = 16 ( ACK)
Sequence Number = 2
Acknowledge = 2836578417 ( 서버의 ISN + 1 값을 보낸다 )
#2 ACK + FIN 서버는 클라이언트에서 보낸 ACK에 대한 응답으로 ACK패킷을 보냄 = 세션연결 성공 !
( ※ 서버에서 세션연결 후 종료되도록 설정해놓았더니, FIN 패킷과 함께 오는 현상 발생 )
Flag = 17 ( ACK + FIN )
Sequence Number = 2836578416
Acknowledge Number = 2