IP Fragment( 단편화 )에 대해서 정리한다.
IP Fragmentation( 단편화 )
3계층
- 최대전송사이즈(MTU)
- Maximum Transfer Unit: 1500byte ( Default 값 )
- ip packet의 최소 사이즈: 8byte
identification
- 단편화된 아이피 패킷을 식별
flag
- 000: 단편화(분할)되지 않은 경우
- 010: 단편화를 하지 않는 경우
- 001: 단편화가 된 경우( 이 뒤에 단편화된 패킷이 존재 )
fragment offset
- 단편화 된 패킷의 원래 위치( 시작 위치 )
! 도착지에서 재조립 하기 위해 필요한 정보
실제 데이터의 크기 = 1500 - 아이피 헤더(20) + icmp 헤더(8) = 1472
4계층
- 최대전송사이즈(MSU)
- Maximum Segment Unit: 1500byte
* fragrouter는 fragment 기능과 router기능을 가지고 있는 툴
- IP Fragment : 20 + 20 + 20
original packet
icmp(8) + payload(52)
fragment #1
ip header
- total: 40
- id: 0x1234
- flag: 1
- offset: 0
icmp(8) + payload(12)
fragment #2
- total: 40
- id: 0x1234
- flag: 1
- offset: 20
payload(20)
fragment #3
- total: 40
- id: 0x1234
- flag: 0
- offset: 40
payload(20)
파이썬에서 offset 해결책
- bit shift시에 값의 유실이 일어난다.
- 해결책1: rotate shift를 사용 ( 파이썬에서는 rotate shift하게 해주는 함수가 있다 )
- 해결책2: 8의 배수로 사이즈
- offset 8, 16, 24, ...
- 24바이트 icmp echo 전송: 8바이트 분할
1. icmp(8)
id: 0x1234
flag: 1
offset: 0
2. payload(8)
id:0x1234
flag: 1
offset: 8
3. payload(8)
id: 0x1234
flag: 0
offset: 8
- 3계층을 이용한 공격 종류
tiny attack
- offset을 일부러 크거나 작게 만드는 방식
- offset 값을 작게 만들어서 덮어써서 방화벽을 우회하거나 크게 만들어 운영체제를 마비시킨다.
smurf attack ICMP Echo를 이용해서 증폭기( 같은 네트워크 안에 있는 다른 PC들 )를 이용해서 시작 IP 주소를
피해자(Victim) PC로 속여 브로드캐스트로 다른 PC들에게 ICMP Request를 요청해 피해자 PC로
모든 응답이 가게 하는 공격 방식
LAND attack 출발지/도착지 아이피가 동일한 공격방식
* 3계층 해당 공격들은 대부분 현재는 패치가 되어서 현재는 통하지 않는다.
IP Fragment( 단편화 ) 실습
( sniffer.py와 packet.py에 변경된 소스는 분홍색으로 표시 )
* 단편화를 통해서 패킷(ICMP Request)를 보내서 응답(ICMP Reply)가 오는지 확인 해본다.
sock.send( ip2.header + payload3 )
import socket
from header.eth import *
from header.ip import *
from header.icmp 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()
echo = Echo()
ip = Ip()
ip1 = Ip()
ip2 = Ip()
echo.type = 8
echo.code = 0
echo.chksum = 0
echo.id = 0xabcd
echo.seq = 1
echo.payload = '12345667890123456'
echo.chksum = make_chksum( echo.header )
echo.payload = ''
ip.ver = 4
ip.length = 20
ip.service = 0
ip.total = 20 + len( echo.header )
ip.id = 0x1234
ip.offset = 0
ip.ttl = 64
ip.type = 1
ip.chksum = 0
ip.src = '192.168.6.112'
ip.dst = '168.126.63.1'
ip.chksum = make_chksum( ip.header )
payload2 = '12345678'.encode()
ip1.ver = 4
ip1.length = 20
ip1.service = 0
ip1.total = 20 + len( payload2 )
ip1.id = 0x1234
ip1.flag = 1
ip1.offset = 8
ip1.ttl = 64
ip1.type = 1
ip1.chksum = 0
ip1.src = '192.168.6.112'
ip1.dst = '168.126.63.1'
ip1.chksum = make_chksum( ip1.header )
payload3 = '91234567'.encode()
ip2.ver = 4
ip2.length = 20
ip2.service = 0
ip2.total = 20 + len( payload3 )
ip2.id = 0x1234
ip2.flag = 0
ip2.offset = 16
ip2.ttl = 64
ip2.type = 1
ip2.chksum = 0
ip2.src = '192.168.6.112'
ip2.dst = '168.126.63.1
ip2.chksum = make_chksum( ip2.header )
eth.dst = '00:05:66:23:30:19'
eth.src = '00:50:56:3B:25:F8'
eth.type = 0x0800
sock = socket.socket( socket.AF_PACKET, socket.SOCK_RAW )
sock.bind( ('eth0', socket.SOCK_RAW) )
sock.send( eth.header + ip.header + echo.header )
sock.send( ip1.header + payload2 )
sock.send( ip2.header + payload3 )
import struct
class Eth:
def __init__( self, raw=None ):
if raw != None:
self._dst = raw[:6]
self._src = raw[6:12]
self._type = raw[12:14]
@property
def header( self ):
return self._dst + self._src + self._type
@property
def dst( self ):
dst = struct.unpack('!6B', self._dst)
dst = '%02x:%02x:%02x:%02x:%02x:%02x' % dst
return dst
@dst.setter
def dst( self, mac ):
mac = mac.split(':')
for i in range( len(mac) ):
mac[i] = int( mac[i] )
self._dst = b''
for i in range( len(mac) ):
self._dst += struct.pack('!B', dst[i])
@property
def src( self ):
src = struct.unpack('!6B', self._src)
src = '%02x:%02x:%02x:%02x:%02x:%02x' % src
return src
@src.setter
def src( self, ip ):
ip = ip.split('.')
for i in range( len(ip) ):
ip[i] = int( ip[i] )
self._src = b''
for i in range( len(ip) ):
self._src += struct.pack('!B', ip[i])
@property
def type( self ):
(type,) = struct.unpack('!H', self._type)
return type
@type.setter
def type( self, type ):
self._type = struct.pack('!H', type)
import struct
class Ip:
def __init__( self, raw=None ):
if raw != None:
self._verlen = raw[:1]
self._service = raw[1:2]
self._total = raw[2:4]
self._id = raw[4:6]
self._flag_and_offset = raw[6:8]
self._ttl = raw[8:9]
self._type = raw[9:10]
self._check_sum = raw[10:12]
self._src = raw[12:16]
self._dst = raw[16:20]
else:
self._verlen = b'\x00'
self._flag_and_offset = b'\x00\x00'
@property
def header( self ):
return self._verlan + self._service + self._total + self._id + self._flag_and_offset + self._ttl + self._type + self._check_sum + self._src + self._dst
@property
def ver( self ):
(ver,) = struct.unpack('!B', self._verlen)
ver = verlen >> 4
return ver
@ver.setter
def ver( self, ver ):
(len,) = struct.pack('!B', self._verlen)
len = len & 0x0F
ver = ver << 4
tmp = ver + len
self._verlen = struct.pack('!B', tmp)
@property
def length( self ):
(len,) = struct.unpack('!B', self._verlen)
@length.setter
def length( self, len ):
(ver,) = struct.unpack('!B', self._verlen)
ver = ver & 0xF0
tmp = ver + len
self._verlen = struct.pack('!B', tmp)
@property
def service( self ):
(service,) = struct.unpack('!B', self._service)
return service
@service.setter
def service( self, service ):
self._service = struct.pack('!B', service)
@property
def total( self ):
(total,) = sturct.unpack('!H', self._total)
return total
@total.setter
def total( self, total ):
self._total = struct.pack('!H', total)
@property
def id( self ):
(id,) = struct.unpack('!H', self._id)
return id
@id.setter
def id( self, id ):
self._id = struct.pack('!H', id)
@property
def flag( self ):
(flag,) = struct.unpack('!H', self._flag_and_offset)
flag = flag >> 13
return flag
@flag.setter
def flag( self, flag ):
(offset,) = struct.unpack('!H', self._flag_and_offset)
offset = offset & 0x1FFF
tmp = flag + offset
self._flag_and_offset = struct.pack('!H', tmp)
@property
def offset( self ):
(offset,) = struct.unpack('!H', self._flag_and_offset)
offset = (offset & 0x1FFF) << 2
return offset
@offset.setter
def offset( self, offset ):
(flag,) = struct.unpack('!H', self._flag_and_offset)
flag = flag & 0xE000
tmp = flag + offset
self._flag_and_offset = struct.pack('!H', tmp)
@property
def ttl( self ):
(ttl,) = struct.unpack('!B', self._ttl)
return ttl
@ttl.setter
def ttl( self, ttl ):
self._ttl = struct.pack('!B', ttl)
@property
def type( self ):
(type,) = struct.unpack('!B', self_type)
@type.setter
def type( self, type ):
self._type = struct.pack('!B', type)
@property
def check_sum( self ):
(check_sum,) = struct.unpack('!H', self._check_sum)
@check_sum.setter
def check_sum( self, chksum ):
self._check_sum = struct.pack('!H', chksum)
@property
def src( self ):
src = struct.unpack('!4B', self._src)
src = '%d.%d.%d.%d' % src
return src
@src.setter
def src( self, ip ):
ip = ip.split('.')
for i in range( len(ip) ):
ip[i] = int( ip[i] )
self._src = b''
for i in range( len(ip) ):
self._src += struct.pack('!B', ip[i])
@property
def dst( self ):
dst = struct.unpack('!4B', self._dst)
dst = '%d.%d.%d.%d' % dst
return dst
@dst.setter
def dst( self, ip ):
ip = ip.split('.')
for i in range( len(ip) ):
ip[i] = int( ip[i] )
self._dst = b''
for i in range( len(ip) ):
self._dst += struct.pack('!B', ip[i])
import struct
class Icmp:
def __init__( self, raw=None ):
if raw != None:
self._type = raw[:1]
self._code = raw[1:2]
self._chksum = raw[2:4]
@property
def header( self ):
return self._type + self._code + self._chksum
@property
def type( self ):
(type,) = struct.unpack('!B', self._type)
return type
@type.setter
def type( self, type ):
self._type = struct.pack('!B', type)
@property
def code( self ):
(code,) = struct.unpack('!B', self._code)
return code
@code.setter
def code( self, code ):
self._code = struct.pack('!B', code)
@property
def chksum( self ):
(chksum,) = struct.unpack('!H', chksum)
return chksum
@chksum.setter
def chksum( self, chksum ):
self._chksum = struct.pack('!H', chksum)
class Echo( Icmp ):
def __init__( self, raw=None ):
if raw != None:
self._id = raw[:2]
self._seq = raw[2:4]
self._payload = raw[4:]
@property
def header( self ):
return self._type + self._code + self._chksum + self._id + self._seq + self._payload
@property
def id( self ):
(id,) = struct.unpack('!H', self._id)
return id
@id.setter
def id ( self, id ):
self._id = struct.pack('!H', id)
@property
def seq( self ):
seq = struct.unpack('!H', self._seq)
return seq
@seq.setter
def seq( self ):
self._seq = struct.pack('!H', seq)
@property
def payload( self ):
return payload.decode( errors='ignore' )
@payload.setter
def payload( self, payload ):
self._payload = payload.encode()
from header.eth import *
from header.ip import *
from header.udp import *
from header.arp import *
from header.icmp import *
class Packet:
def __init__( self, raw ):
self._eth = Eth( raw[:14] )
if self._eth.type == 0x0800:
self.analyze_ip( raw[14:] )
if self._eth.type == 0x0806:
self.analyze_arp( raw[14:] )
def analyze_ip( self, raw ):
self._ip = Ip( raw )
if self._ip.type == 17:
self.analyze_udp( raw[20:] )
elif self._ip.type == 1:
if self._ip.offset == 0:
self.analyze_icmp( raw[20:] )
else:
self._raw = raw[20:]
def analyze_udp( self, raw ):
self._udp = Udp( raw )
def analyze_arp( self, raw ):
self._arp = Arp( raw )
def analyze_icmp( self, raw ):
self._icmp = Icmp( raw )
@property
def raw( self ):
return self._raw
@property
def eth( self ):
return self._eth
@property
def ip( self ):
return self._ip
@property
def arp( self ):
return self._arp
@property
def icmp( self ):
return self._icmp
sniffer.py
import socket
import struct
import time
from header.packet import *
raw = socket.socket( socket.PF_PACKET, socket.SOCK_RAW )
raw.bind( ('eth0', socket.SOCK_RAW) )
while True:
data, addr = raw.recvfrom( 65535 )
packet = Packet( data )
if packet.eth.type == 0x0800 and \
(packet.ip.src == '168.126.63.1' or packet.ip.dst == '168.126.63.1') \
and packet.ip.type == 1:
print("data: ", data)
print(packet.ip.src + ' -> ' + packet.ip.dst)
print("id: ", packet.ip.id, "flag: ", packet.ip.flag, "offset: ", \
packet.ip.offset)
if packet.ip.offset == 0:
print("type: ", pakcet.icmp.type, "code: ", packet.icmp.code)
print()
else:
print( packet.raw )
'프로그래밍 > NETWORK HACKING' 카테고리의 다른 글
[네트워크 보안] UDP를 이용한 DDOS - UDP Flooding (0) | 2017.07.05 |
---|---|
[네트워크 보안] udp 체크섬 계산 / 포트 스캐닝 (0) | 2017.07.04 |
[네트워크 보안] 2계층, 3계층 개념 및 프로토콜 종류 / ip헤더 체크섬 계산 / DNS서버에 에코 리퀘스트 전송 실습 (0) | 2017.07.02 |
[네트워크 보안] ARP Cache Poisoning을 이용한 ARP Spoofing (0) | 2017.06.23 |
[네트워크 보안] ARP 클래스 setter 추가 / arping.py (0) | 2017.06.22 |
댓글