PYTHON黑帽編程 4.1 SNIFFER(嗅探器)之數據捕獲(下)


 

上一節(《4.1 SNIFFER(嗅探器)之數據捕獲(上)》)中, 我們講解了通過Raw Socket的方式來編寫Sniffer的基本方法。 本節我們繼續來編寫Sniffer,只不過使用現成的庫,可以大大 縮短我們的工作時間和編程難度,和上一篇文章對比就知道了。

4.1.6 使用Pypcap編寫Sniffer

如果在你的電腦上找不到pypcap模塊,需要手動進行安裝一下。在Kali中使用下面的命令進行安裝:

apt-get install libpcap-dev
pip install pypcap

 

安裝過程如圖1,圖2:

 

圖1

 

圖2

調用pcap模塊的pcap方法可以返回一個用來捕獲數據包的pcap對象。

 

圖3

如圖3,pcap方法接收5個參數:

  • name,監聽的網卡名稱。
  • snaplen,捕獲的每個數據包的最大長度。
  • promisc,是否開啟混雜模式
  • timeout_ms,接收數據包的超時時間
  • immediate,立即模式,如果啟用則不會緩存數據包

每一個參數都有默認值,如果有多個網卡的話,需要設置第一個參數的值,傳入網卡名稱。下面 我們定義一個方法,返回一個pcap對象。

import pcap

def getSniffer(ifName=None,filter=''):
    pc = pcap.pcap('eth0',65535,True)
    if(filter != ''):
        pc.setfilter(filter)
    return pc

 

在上面的代碼中,我們創建了一個pcap對象,然后調用了setfilter方法,設置數據包過濾器。 pcap使用的過濾器為符合BPF格式的數據包過濾字符串。

什么是BPF

伯克利包過濾(Berkeley Packet Filter,BPF)語言。讓你能夠通過比較第2、3、4層協議中各個數據字段值的方法對流量進行過濾。BPF中內置了一些“基元”來指代一些常用的協議字段。可以用“host”、"prot"之類的基元寫出非常簡潔的BPF過濾規則,也可以檢測位於指定偏移量上的字段(甚至可以是一個位)的值。BPF過濾器也可以由詳盡的條件鏈和嵌套的邏輯“與”、“或”操作組成。

BPF基元

現在,構造一個BPF過濾器的最簡單的辦法就是使用BPF“基元”來指定協議、協議元素或者其他抓包規則。基元通常是由一個id(名稱或序號)再加上一個或多個限定符組成的。 \

  • type限定符:規定了id名或id序號指的是哪種類型的數據,可能的type有host、net、prot和protrange
  • dir限定符:規定了流量是從id流進還是流出的(或兩種兼有)。可能的dir有src、dst、ser or dst、src and dst、addr1、addr2、addr3和addr4
  • Proto限定符:規定了所匹配的協議。可能的proto有:ether、fddi、tr、wlan、ip、ip6、arp、rarp、decnet、tcp和udp \

最常用的BPF基元要數“host id”,它是用來過濾與某台主機相關的流量的,其中id一欄中應該填上一個地址或主機名。輸入“tcp and host 10.10.10.10”這樣的過濾規則,將值獲取流入/流出得做10.10.10.10的TCP流量,其他的所有幀都會被過濾掉。 \ 舉例說明:\ 假設我們現在希望僅僅獲取IP地址為192.168.0.1的計算機與除IP地址10.1.1.1之外的其他所有計算機在138、139和445端口上發送的所有通信,下面這個BPF過濾規則就能完成上述任務:

'host 192.168.0.1 and not host 10.1.1.1 and (port 138 or port 139 or port 445)'

常用的BPF基元有:

  • host id , dst host id , src host id
  • net id , dst net id , src net id
  • ether host id , ether dst host id , ether src host id
  • port id , dst port id , src port id
  • gateway id , ip proto id , ether proto id
  • tcp, udp, icmp, arp
  • vlan id

    根據字節的值過濾數據包

BPF語言也可以用來檢查幀內任意一個單字節字段(或多字節字段)的值是不是規定值。下面是一些例子:

ip[8]<64

這個過濾規則規定要抓取的是:所有自ip頭偏移8個字節的那個單字節字段的值小於64的IP包。被檢查的這個字段表示的是“包的存活時間”或稱“TTL”。大多數Windows系統中TTL的默認值是128,所以這個過濾規則將丟棄局域網中所有來自Windows系統的流量,只獲取所有來自Linux系統的流量(因為在LInux系統中TTL的默認起始值是64)

ip[9]!=1

這一過濾規則規定要抓取的是所有IP頭部偏移9個字節的那個單字節字段的值不等於“1”的幀。因為IP頭部偏移9個字節的這個字段表示的是嵌入協議,如果等於“1”則表示“ICMP”協議,所以這個過濾規則將抓取除ICMP包之外的所有流量。這一表達式也等價於基元“not icmp”。

icmp[0] = 3 and icmp[1] = 0

這個語句規定要抓取的是:所有ICMP頭部偏移0個字節的那個單字節字段等於3,且偏移1個字段的單字節字段等於0的ICMP數據包。換而言之,這一過濾規則將只抓取ICMPtype為3,code為0的“網絡不可達”消息。

tcp[0:2] = 31337

這個語句檢查了一個多字節字段,它檢查的是:TCP頭部偏移0個字節起的一個多字節字段(2個字節),該字段表示的是TCP源端口。所以這個表達式就等價於BPF基元“src prot 31337”

ip[12:4] = 0xC0A80101

我們看到的這是一個4字節的比較,它檢查的是IP頭部偏移12個字節起的4個字節里存放的數據——源IP地址。注意這個表達式里使用了十六進制表示法。轉換成十進制數字,它就是192.168.1.1(0xC0=192,0xA8=168,0x01=1)。所以這一過濾規則將捕獲所有源IP地址為192.168.1.1的流量。

根據位(bit)的值過濾數據包

BPF語言還提供了一種方法讓我們能檢查更小的字段或精度更高的偏移量。具體做法是:我們先引用相關的字節,或多個字節,然后再用“位掩碼”逐位地把我們需要檢查的位分離出來。

假設要過濾所有IP頭部中可選字段被啟用的包(就是IP頭的長度大於20個字節的包)。IP頭部的低半個字節表示的是IP頭的長度,以“word”(字)為單位(一個word等於4個字節)。我們只需要找出這半個字節的值大於5(5word*4個字節/word=20個字節)的包就等於找出所有IP頭部大於20個字節的包了。具體做法是用位掩碼“00001111”(或者0x0F)創建一個BPF過濾規>>>則,通過邏輯“與”運算提取目標值。

ip[0] & 0x0F > 0x05 與之類似,如果我們要找出所有“不分片”標志位(位於IP頭部偏移6個字節位置上的一位二進制位)被置1的IP包,我們亦可用二進制位掩碼“01000000”(0x40)來表示我們只關心IP頭部偏移6個字節位置上那個第二最高位的bit值是是不是1。

在構造位掩碼是,如果對應的那一位是我們需要檢查的,那就用1表示,否則就用0表示。

ip[6] & 0x40 != 0

接下來我們嘗試調用getSniffer方法。

sniffer = getSniffer('eth0','tcp port 80')
for ptime,data in sniffer:
    print ptime,data

 

這段代碼中,調用getSniffer方法得到pcap對象,然后我們循環讀取監聽到的數據。 這里我在虛擬機運行這段代碼,然后在從宿主機中訪問網頁,可以看到打印的數據,證明 監聽成功。

 圖4

4.1.7 使用Scapy編寫Sniffer

又到了強大的Scapy出場的時候了,通過前面章節的介紹,相信大家已經對它不陌生了,在 底層網絡編程方面,Scapy機會是萬能的存在。下面我們看看使用Scapy編寫Sniffer的代碼:

from scapy.all import *

def packetHandler(pkt):
    src=pkt[IP].src
    srcPort=pkt[IP].dst
    if src=='192.168.1.20':
        print 'ok'

sniff(filter='tcp and port 80',prn=packetHandler,iface='eth0')

 

先看上面這段簡單的代碼,最下面一行是調用的scapy的sniff方法,該方法就是用來監聽 數據的,我們可以在scapy的交互窗口中使用help來查看sniff方法的說明。

sniff(count=0, store=1, offline=None, prn=None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, *arg, **karg)
    Sniff packets
    sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets

      count: number of packets to capture. 0 means infinity
      store: wether to store sniffed packets or discard them
        prn: function to apply to each packet. If something is returned,
             it is displayed. Ex:
             ex: prn = lambda x: x.summary()
    lfilter: python function applied to each packet to determine
             if further action may be done
             ex: lfilter = lambda x: x.haslayer(Padding)
    offline: pcap file to read packets from, instead of sniffing them
    timeout: stop sniffing after a given time (default: None)
    L2socket: use the provided L2socket
    opened_socket: provide an object ready to use .recv() on
    stop_filter: python function applied to each packet to determine
                 if we have to stop the capture after this packet
                 ex: stop_filter = lambda x: x.haslayer(TCP)

 

參數說明已經很清楚了,過濾數據包可以使用filter,lfilter,stop_filter,filter是過濾表達式, lfilter 和stopfilter 是python函數。前兩者作用一樣,用來過濾我們需要的數據包,或者 是一個終止監聽的判斷條件。 prn是數據包的處理函數,我們要在此做數據包的解析,分析等工作。 數據包的解析,我們會在下一節做詳細的講解,大家在練習的時候一定要結合以太網數據包的格式來 調試分析數據包對象,相互加深,會有事半功倍的效果。

 

圖5

上面代碼的運行結果如下:

 

圖6

 

4.1.8  使用Pcapy進行數據捕獲

在網絡數據分析的工具中,tcpdump絕對是大名鼎鼎,tcpdump底層是libpcap庫,由C語言編寫。 Pcapy模塊則是基於libpcap的Python接口。pcapy在github上的項目地址為: https://github.com/CoreSecurity/pcapy。

下面我們來看看如何使用pcapy實現數據包的捕獲。

 1 #!/usr/bin/python
 2 
 3 import pcapy
 4 
 5 dev = "eth0"
 6 filter = "tcp and port 80"
 7 
 8 
 9 def handle_packet(hdr, data):
10     print data
11 
12 pcap = pcapy.open_live(dev, 1500, 0, 100)
13 pcap.setfilter(filter)
14 pcap.loop(0, handle_packet)

 

上面的代碼很簡單,首先導入pcapy模塊,之后定義了兩個變量,dev為要監聽的網卡, filter是BPF 格式的過濾表達式,這里我們只捕獲http協議的數據。 handle_packet方法是用來處理捕獲的數據包的邏輯, 這里我們只是簡單的打印捕獲的數據,在之后的文章中,我們會繼續擴展該方法,用來 做數據解析。

最后三行代碼是我們使用pcapy進行數據捕獲的具體應用。

pcap = pcapy.open_live(dev, 1500, 0, 100)

open_live方法第一個參數是要打開的設備,第二個參數是捕獲數據包的大小, 第三個參數是否打開混雜模式,第四個參數是等待數據包的延遲時間,該方法返回一個 pcapy對象。

pcap.setfilter(filter)

調用setfilter方法,設置過濾器。

pcap.loop(0, handle_packet)

調用loop方法,開始執行數據包捕獲,該方法的第一個參數為執行次數,小於或等於0為不限制, 第二個參數為數據包處理函數。

好了,就補充說明這么多,運行結果如下:


 

4.1.9 小結

本節主要講了如何利用Pypcap、Scapy和Pcapy來編寫Sniffer,完成了監聽數據的功能,當然這只是 完成了前置功能,嗅探器的核心是數據分析。下一節我將從協議分析、數據內容分析、數據匯總 三個方面為大家講解。請關注《Python 黑帽編程4.2 Sniffer之數據分析》。

4.2節《4.1 Sniffer(嗅探器)之數據分析》已經在微信訂閱號搶先發布,進入訂閱號(二維碼在下方),從菜單“精華”—>”Python黑帽編程進入即可。

 

查看完整系列教程,請關注我的微信訂閱號(xuanhun521,下方二維碼),回復“python”。問題討論請加qq群:Hacking (1群):303242737   Hacking (2群):147098303。

 

玄魂工作室-專注原創


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM