본문 바로가기
프로그래밍/NETWORK HACKING

[네트워크 보안] TCP 통신 직접 구현 해보기 / tcping.py

by B T Y 2017. 7. 19.
반응형

TCP 통신 직접 만들어 보기(raw) / tcping.py에 대해서 정리한다.



! 로우 소켓을 이용한 TCP 통신을 직접 만들어봄으로써 TCP 통신 과정을 이해한다.



1. tcp 동기화


2. 데이터 송/수신


3. 동기화 해제




  - raw 패킷으로 TCP 통신 직접 구현



* 직접 만들어보면서 TCP 통신을 이해하는 과정이기 때문에 순서대로 하나씩 구현 해봤다.

* TCP 통신을 하기 위해서 이전에 만들었던 TCP 에코서버를 사용했다.

* 클라이언트 측에서 SYN 패킷을 보내면 서버와 3-way handshake 과정을 거치고 서로 간의 세션 연결이 되면 

   클라이언트 측에서 'hello'라는 데이터를 PSH+ACK을 보내게 되고 에코 서버이기 때문에 

   클라이언트가 보낸 데이터를 그대로 다시 보내주게 된다. 그 이후에 서버쪽에서 close()가 실행 되면서 FIN을 

   보내면 클라이언트는 ACK로 응답해주고 마찬가지로 FIN을 서버에게 보낸다음 서버가 ACK 응답을 하게 되면 

   서로 간의 세션 연결이 종료된다.

  ( 실습 했던 내용을 말로 그대로 풀어쓴 내용이다 )


서버클라이언트 TCP 통신

 ( 위에 TCP 통신 실습 내용을 간단하게 정리하면 아래와 같고 서버와 클라이언트를 색으로 구분했다 )


* 세션 연결 과정 ( 3-way handshake )  :  SYN  ->  SYN + ACK  ->  ACK 

  데이터 송/수신 과정  :  PSH + ACK  ->  ACK

  세션 종료 과정 ( 4-way handshake )  :  FIN  ->  ACK  ->  FIN  ->  ACK

   ( 저번에도 적어놨지만 세션 종료 과정에는 꼭 4-way handshake 상황만 있는게 아니라 3번이나 1번만에 끝나는 상황들도 있다 )


tcping.py


from header.eth import *

from header.ip import *

from header.tcp import *

from header.packet import *


import socket

import struct

import random



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



port = random.randrange( 1, 65535 )

client_seq = random.randrange( 1, 4000000000 )

server_seq = 0


sock = socket.socket( socket.AF_PACKET, socket.SOCK_RAW )

sock.bind( ('eth0', socket.SOCK_RAW) )


eth = Eth()

ip = Ip()

tcp = Tcp()



tcp.src = port

tcp.dst = 63751

tcp.seq = client_seq

tcp.ack = 0

tcp.flag = 2

tcp.length = 0

tcp.window_size = 65535

tcp.chksum = 0

tcp.point_or_dummy = 0

tcp.data = ''

tcp.length = len( tcp.header )


ip.ver = 4

ip.length = 20

ip.service = 0

ip.total = ip.length + tcp.length

ip.id = 0x1234

ip.flag = 0

ip.offset = 0

ip.ttl = 64

ip.type = 6

ip.chksum = 0

ip.src = '192.168.30.112'

ip.dst = '192.168.30.116'


ip.chksum = make_chksum( ip.header )

length = struct.pack('!H', tcp.length)

pseudo_header = ip._src + ip._dst + b'\x00' + ip._type + length + tcp.header

tcp.chksum = make_chksum( pseudo_header )


eth.dst = 00:0c:29:a0:43:a2

eth.src = 00:0C:29:DC:F9:73

eth.type = 0x0800


# SYN

sock.send( eth.header + ip.header + tcp.header )


packet=''

while True:


  data, addr = sock.recvfrom( 65535 )

  packet = Packet( data )


  if packet.eth.type == 0x0800 and packet.ip.dst == '192.168.30.112' and packet.ip.type == 6 \

     and packet.tcp.dst == port and packet.tcp.ack == client_seq + 1:


    print( packet.ip.src + ':' + str(packet.tcp.src) + ' -> ' + \

           packet.ip.dst + ':' + str(packet.tcp.dst) )

    print( "seq: " + str( packet.tcp.seq ) + ' | ' + "ack: " + str( packet.tcp.ack ) )

    print( "flag: " + str( packet.tcp.flag ) )


    # SYN/ACK

    break


server_seq = packet.tcp.seq

client_seq = client_seq + 1

server_seq = server_seq + 1


tcp.seq = client_seq

tcp.ack = server_seq

tcp.chksum = 0

tcp.flag = 16

tcp.length = len( tcp.header )


length = struct.pack('!H', tcp.length)

pseudo_header = ip._src + ip._dst + b'\x00' + ip._type + tcp.header

tcp.chksum = make_chksum( pseudo_header )


# ACK

sock.send( eth.header + ip.header + tcp.header )



client_seq = client_seq

server_seq = server_seq


tcp.seq = client_seq

tcp.ack = server_seq

tcp.chksum = 0

tcp.length = 0

tcp.flag = 24

tcp.data = 'hello'

tcp.length = len( tcp.header ) - len( tcp.data )


ip.total = len( ip.header ) + len( tcp.header )

ip.chksum = 0

ip.chksum = make_chksum( ip.header )


length = tcp.length + len(tcp.data)

length = struct.pack('!H', length)

pseudo_header = ip._src + ip._dst + b'\x00' + ip._type + tcp.header

tcp.chksum = make_chksum( pseudo_header )


# PSH/ACK

sock.send( eth.header + ip.header + tcp.header )



packet=''

while True:


  data, addr = sock.recvfrom( 65535 )

  packet = Packet( data )


  if packet.eth.type == 0x0800 and packet.ip.dst == '192.168.30.112' and packet.ip.type == 6 \

     and packet.tcp.dst == port and packet.tcp.ack == client_seq + len(tcp.data):


    print( packet.ip.src + ':' + str(packet.tcp.src) + ' -> ' + \

           packet.ip.dst + ':' + str(packet.tcp.dst) )

    print( "seq: " + str( packet.tcp.seq ) + ' | ' + "ack: " + str( packet.tcp.ack ) )

    print( "flag: " + str( packet.tcp.flag ) )


    # ACK

    break


client_seq = client_seq + len( tcp.data )



packet=''

while True:


  data, addr = sock.recvfrom( 65535 )

  packet = Packet( data )


  if packet.eth.type == 0x0800 and packet.ip.dst == '192.168.30.112' and packet.ip.type == 6 \

     and packet.tcp.dst == port and packet.tcp.ack == client_seq:


    print( packet.ip.src + ':' + str(packet.tcp.src) + ' -> ' + \

           packet.ip.dst + ':' + str(packet.tcp.dst) )

    print( "seq: " + str( packet.tcp.seq ) + ' | ' + "ack: " + str( packet.tcp.ack ) )

    print( "flag: " + str( packet.tcp.flag ) )


    # PSH/ACK

    break



server_seq = server_seq + len( packet.tcp.data )


tcp.seq = client_seq

tcp.ack = server_seq

tcp.chksum = 0

tcp.length = 0

tcp.flag = 16

tcp.data = ''

tcp.length = len( tcp.header ) - len( tcp.data )


ip.total = len( ip.header ) + len( tcp.header )

ip.chksum = 0

ip.chksum = make_chksum( ip.header )


length = tcp.length + len(tcp.data)

length = struct.pack('!H', length)

pseudo_header = ip._src + ip._dst + b'\x00' + ip._type + tcp.header

tcp.chksum = make_chksum( pseudo_header )


# ACK

sock.send( eth.header + ip.header + tcp.header )



packet=''

while True:


  data, addr = sock.recvfrom( 65535 )

  packet = Packet( data )


  if packet.eth.type == 0x0800 and packet.ip.dst == '192.168.30.112' and packet.ip.type == 6 \

     and packet.tcp.dst == port and packet.tcp.ack == client_seq:


    print( packet.ip.src + ':' + str(packet.tcp.src) + ' -> ' + \

           packet.ip.dst + ':' + str(packet.tcp.dst) )

    print( "seq: " + str( packet.tcp.seq ) + ' | ' + "ack: " + str( packet.tcp.ack ) )

    print( "flag: " + str( packet.tcp.flag ) )


    # FIN

    break



server_seq = server_seq + 1


tcp.seq = client_seq

tcp.ack = server_seq

tcp.chksum = 0

tcp.flag = 16

tcp.data = ''

tcp.length = len( tcp.header )


ip.total = len( ip.header ) + len( tcp.header )

ip.chksum = 0

ip.chksum = make_chksum( ip.header )


length = struct.pack('!H', tcp.length)

pseudo_header = ip._src + ip._dst + b'\x00' + ip._type + tcp.header

tcp.chksum = make_chksum( pseudo_header )


# ACK

sock.send( eth.header + ip.header + tcp.header )



tcp.seq = client_seq

tcp.ack = server_seq

tcp.chksum = 0

tcp.flag = 1

tcp.data = ''

tcp.length = len( tcp.header )


ip.total = len( ip.header ) + len( tcp.header )

ip.chksum = 0

ip.chksum = make_chksum( ip.header )


length = struct.pack('!H', tcp.length)

pseudo_header = ip._src + ip._dst + b'\x00' + ip._type + tcp.header

tcp.chksum = make_chksum( pseudo_header )


# FIN

sock.send( eth.header + ip.header + tcp.header )



packet=''

while True:


  data, addr = sock.recvfrom( 65535 )

  packet = Packet( data )


  if packet.eth.type == 0x0800 and packet.ip.dst == '192.168.30.112' and packet.ip.type == 6 \

     and packet.tcp.dst == port and packet.tcp.ack == client_seq + 1:


    print( packet.ip.src + ':' + str(packet.tcp.src) + ' -> ' + \

           packet.ip.dst + ':' + str(packet.tcp.dst) )

    print( "seq: " + str( packet.tcp.seq ) + ' | ' + "ack: " + str( packet.tcp.ack ) )

    print( "flag: " + str( packet.tcp.flag ) )


    # ACK

    break


반응형

댓글