>> 이너뎃(Ethernet) 헤더 + 아이피(IP) 헤더 사용
Ethernet 헤더 : 같은 네트워크 상에서 Mac 주소를 이용한 통신
IP 헤더 : 다른 네트워크 상에 있는 호스트와 ip주소를 사용하여 통신
1. ip packet 을 통해서 전달할 데이터
데이터 : ICMP ( ping )
ICMP 메세지는 오류보고 메세지와 질의 메세지로 나뉨
오류보고 메세지 : 라우터나 호스트가 IP 패킷을 처리하는 도중에 탐지하는 문제를 보고
질의 메세지 : 호스트나 네트워크 관리자가 라우터나 다른 호스트로부터 특정 정보를 획득하기 위해 사용
2. ICMP 헤더
- 매우 단순한 구조 - 원래는 네트워크 상에 에러를 제어할 목적으로 나왔으나 현재는 잘 사용되지 않는다 - Internet Contorl Message Protocol
--> ping은 icmp이지만 icmp는 ping이 아니다
icmp == ping
type(1)+code(1)+checksum(2) =4byte 1) 공통헤더 -type (1byte) -code(1byte) -chksum(2byte)
2) 타입별 헤더
- identifier(2byte) - sequencenumber(2byte) - payload(가변길이)
Type (1byte )
Code(1byte )
checksum (2byte)
id(2byte )
sequncenumber(2byte )
payloade(가변길이 )
* 데이터를 보내면 에코 리플레이가 도착하면 정상동작 도착하지 않으면 정상동작 x
[ #vi ip.py ]
( 클래스정의 , set 함수 정의 )
ip.py 접기
i mport struct
class Ip: def __init__(self,data=None): if data !=None: (self.ver_and_len,)=struct.unpack('!B',data[:1]) self.ver = self.ver_and_len >> 4 self.len=self.ver_and_len& 0b_0000_1111 self.len=self.len <<2 (self.service_field,)=struct.unpack('!B',data[1:2]) (self.total_len,)=struct.unpack('!H',data[2:4]) (self.id,)=struct.unpack('!H',data[4:6]) (self.flag,)=struct.unpack('!H',data[6:8]) self.flag=self.flag >>13 (self.offset,)=struct.unpack('!H',data[6:8]) self.offset &= 0b_0001_1111_1111_1111 self.offset = self.offset <<3 self.ttl=data[8] self.type=data[9]
(self.chksum,)=struct.unpack('!H',data[10:12]) self.src=struct.unpack('!BBBB',data[12:16]) self.src='{:d}.{:d}.{:d}.{:d}'.format(*self.src) self.dst=struct.unpack('!BBBB',data[16:20]) self.dst='{:d}.{:d}.{:d}.{:d}'.format(*self.dst)
else: self.ver=0 self.len=0 self.service_field=b'\x00' self.total_len=b'' self.id=b'' self.flag=0 self.offset=0 self.ttl=b'\x00' self.type=b'\x00' self.chksum=b'\x00\x00' self.src=b'\x00\x00\x00\x00' self.dst=b'\x00\x00\x00\x00'
def get_header(self):
ver_len=(self.ver << 4) + (self.len >>2) ver_len=struct.pack('!B',ver_len)
flag_offset=(self.flag <<13)+(self.offset >> 3) flag_offset=struct.pack('!H',flag_offset)
return ver_len+self.service_field+self.total_len+self.id+flag_offset+self.ttl+self.type+self.chksum+self.src+self.dst def set_ver(self,ver): self.ver=ver def set_len(self,len): self.len=len
def set_service_field(self,service_field): self.service_field=struct.pack('!B',service_field) def set_total_len(self, total_len): self.total_len=struct.pack('!H',total_len) def set_id(self,id): self.id = struct.pack('!H',id) def set_flag(self,flag): self.flag=flag def set_offset(self, offset): self.offset=offset def set_ttl(self, ttl): self.ttl=struct.pack('!B',ttl) def set_type(self,type): self.type=struct.pack('!B',type) def set_chksum(self,chksum): self.chksum=struct.pack('!H',chksum) def set_src(self,src): src=src.split('.') src=[int(x) for x in src ] self.src=struct.pack('!BBBB',*src)
def set_dst(self,dst): dst=dst.split('.') dst=[int(x) for x in dst] self.dst=struct.pack('!BBBB',*dst)
접기
확인 )
#python3 -i ip.py
>>> ip=Ip() >>> ip.get_header() b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' >>> ip.set_ver(4) >>> ip.set_len(20) >>> ip.set_total_len(20+30) >>> ip.set_id(1234) >>> ip.set_ttl(64) >>> ip.set_type(1) >>> ip.set_flag(0) >>> ip.set_offset(0) >>> ip.set_src('192.168.219.106') >>> ip.set_dst('192.168.219.180') >>> ip.get_header() b'E\x00\x002\x04\xd2\x00\x00@\x01\x00\x00\xc0\xa8\xdbj\xc0\xa8\xdb\xb4' >>> len(ip.get_header()) 20 # 총 바이트의 길이가 20인것을 확인 할 수 있다
[#vi ping.py ]
ping.py 접기
from socket import* import struct
import eth as _eth import ip as _ip
#checksum 함수
def make_chksum(header): size =len(header) if (size %2) !=0: header=header+b'\x00' size=len(header) header=struct.unpack('!'+str(size//2)+'H',header) chksum=sum(header) carry=chksum & 0b_1111_1111_0000_0000_0000_0000 carry = chksum >>16 while carry !=0: chksum =chksum & 0b_0000_0000_1111_1111_1111_1111 chksum =chksum +carry carry=chksum & 0b_1111_1111_0000_0000_0000_0000 carry = chksum >> 16 chksum = chksum ^ 0b_1111_1111_1111_1111 return chksum
ip=_ip.Ip() eth=_eth.Eth()
icmp=b'' icmp += struct.pack('!B',8) #type 1byte의 타입(8번) icmp += struct.pack('!B',0) #code icmp += struct.pack('!H',0) #chksum icmp += struct.pack('!H',1234) #identifier icmp += struct.pack('!H',1) #sequence number(시퀀스) icmp += 'ABCDEFGHIJ'.encode() #payload(10글자)
icmp_chksum=make_chksum(icmp) icmp_chksum=struct.pack('!H',icmp_chksum) icmp=icmp[:2]+icmp_chksum+icmp[4:]
ip.set_ver(4) ip.set_len(20) ip.set_total_len(20+len(icmp)) ip.set_id(1234) ip.set_type(1) ip.set_ttl(64) ip.set_flag(0b_000) ip.set_offset(0) ip.set_chksum(0) ip.set_src('192.168.219.106') ip.set_dst('192.168.219.180') ip.set_chksum(make_chksum(ip.get_header()))
eth.set_dst('00:0c:29:52:30:da') eth.set_src('00:0c:29:fb:2e:6f') eth.set_type(0x0800)
sock=socket(AF_PACKET,SOCK_RAW) sock.bind(('eth0',SOCK_RAW))
sock.send(eth.get_header()+ip.get_header()+icmp)
접기
[#vi sniffer2.py]
sniffer.py 접기
from socket import* import eth as _eth import ip as _ip
sock=socket(AF_PACKET,SOCK_RAW) sock.bind(('eth0',SOCK_RAW))
while True: (raw,_)=sock.recvfrom(65535)
eth=_eth.Eth(raw[:14])
if eth.type=='0x0800': ip=_ip.Ip(raw[14:34]) if ip.type ==1:
#if ip.src=='192.168.219.180' or ip.dst== '192.168.219.180' :
print('src:{:s} -> dst:{:s} ,type:{:s}'.format(eth.src,eth.dst,eth.type)) print('id:0x{:04x} | flag:{:03b} | offset: {:d} type:{:d}'.format(ip.id,ip.flag, ip.offset, ip.type))
접기
<실행 결과>
1))
#python3 sniffer2.py
--> 192.168.219.106 에서 siniffer.py 파일을 실행시킨다
#python3 ping.py
--> 192.168.219.106 에서 ping.py 파일을 실행 시킨다
2))
ping으로 보냈을 떄
#python3 sniffer2.py
#ping 192.168.219.180
<<실습>>
▶ DNS (168.126.63.1) 서버에서 응답 받아오기
호스트 -> 라우터 -> 다른 네트워크 상의 호스트
: 패킷이 라우터를 통해 외부로 빠져나온후 응답
--> DNS의 맥 어드레스의 서버를 알수 없으므로 라우터의 맥 어드레스를 받아온다
>> cmd 에서 arp -a 사용
>> 게이트 웨이의 맥어드래스를 찾음 ( 192.168.219.1 )
[ #vi ping.py ]
ping.py 접기
from socket import* import struct import ip as _ip import eth as _eth
def make_chksum(header): size=len(header) if (size %2)!=0: header=header+b'\x00' size=len(header) header=struct.unpack('!'+str(size//2)+'H',header) chksum=sum(header) carry=chksum & 0b_1111_1111_0000_0000_0000_0000 carry=chksum >>16 while carry !=0: chksum=chksum & 0b_0000_0000_1111_1111_1111_1111 chksum = chksum +carry carry =chksum & 0b_1111_1111_0000_0000_0000_0000 carry=chksum >>16 chksum =chksum ^ 0b_1111_1111_1111_1111 return chksum ip=_ip.Ip() eth=_eth.Eth()
icmp=b'' icmp +=struct.pack('!B',8) icmp +=struct.pack('!B',0) icmp +=struct.pack('!H',0) icmp +=struct.pack('!H',0) icmp +=struct.pack('!H',1) icmp += 'ABCDEFGHIJ'.encode()
icmp_chksum=make_chksum(icmp) icmp_chksum = struct.pack('!H',icmp_chksum) icmp=icmp[:2]+icmp_chksum+icmp[4:]
ip.set_ver(4) ip.set_len(20) ip.set_total_len(20+len(icmp)) ip.set_id(0) ip.set_flag(0b_000) ip.set_offset(0) ip.set_ttl(64) ip.set_type(1) ip.set_chksum(0) ip.set_src('192.168.219.106') ip.set_dst('168.126.63.1') #DNS 서버 IP주소 ip.set_chksum(make_chksum(ip.get_header()))
eth.set_dst('00:27:1c:db:6d:92' ) # 라우터의 Mac address (gate way) eth.set_src('00:0c:29:fb:2e:6f') eth.set_type(0x0800)
sock=socket(AF_PACKET,SOCK_RAW) sock.bind(('eth0',SOCK_RAW))
sock.send(eth.get_header()+ip.get_header()+icmp)
접기
[ # vi sniffer2.py ]
sniffer2.py 접기
import socket import struct import time import eth as eth_header import ip as ip_header import udp as udp_header import arp as arp_header import ip as _ip import eth as _eth import arp as _arp
def make_chksum(header):
size=len(header) #짝수를 맞춰줌 if (size %2) !=0 : header=header+b'\x00' size=len(header)
header=struct.unpack('!'+str(size//2)+'H',header) chksum=sum(header) #올림수 있는지 확인 carry=chksum & 0b_1111_1111_0000_0000_0000_0000 carry >>=16 while carry !=0: chksum =chksum & 0b_0000_0000_1111_1111_1111_1111 chksum =chksum +carry carry=chksum & 0b_1111_1111_0000_0000_0000_0000 carry >>=16 #xor 계산 ^ chksum =chksum ^ 0b_1111_1111_1111_1111 return chksum
sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) sock.bind(('eth0', socket.SOCK_RAW))
while(True): (raw,_) = sock.recvfrom(65535)
eth=_eth.Eth(raw[:14]) if eth.type=='0x0800': ip=_ip.Ip(raw[14:34]) # if ip.src=='192.168.219.180' or ip.dst=='192.168.219.180': if ip.type==1: data=raw[14:34] print(data) print('src:{:s} -> dst:{:s} ,type:{:s}'.format(eth.src,eth.dst,eth.type)) print('id:0x{:04x} | flag:{:03b} | offset: {:d}, type :{:d}'.format(ip.id,ip.flag, ip.offset,ip.type))
접기
< 실행 결과 >
#python3 sniffer2.py
--> 실행 시켜 놓는다
#python3 ping2.py 파일 실행