21.3 Python 使用DPKT分析封包

2023-10-20 21:00:40

dpkt專案是一個Python模組,主要用於對網路封包進行解析和操作。它可以處理多種協定,例如TCPUDPIP等,並提供了一些常用的網路操作功能,例如計算校驗和、解析DNS封包等。由於其簡單易用的特性,dpkt被廣泛應用於網路安全領域,例如流量分析、漏洞利用、入侵檢測等。使用該庫可以快速解析通過各類抓包工具抓到的封包,從而提取分析包內的引數。

  • 安裝DPKT工具:pip install dpkt

在分析封包之前我們需要抓取特定封包並儲存為*.pcap格式,通常情況下這種封包格式可通過WireShark等工具抓取到,當然也可以使用上一篇提到的Scapy庫實現,該庫中存在一個sniff函數,該函數可以實現網路抓包功能,如下一個演示案例我們分別通過sniff(count=2)函數抓取兩個封包並使用wrpcap()函數將其儲存到檔案內,當需要分析時可通過呼叫rdpcap()函數開啟封包即可實現分析。

>>> from scapy.all import *
>>>
>>> packets = sniff(count=2)                            # 動態抓取2個封包
>>>
>>> wrpcap("d://lyshark.pcap",packets)                  # 儲存封包
>>> pcap_packets = rdpcap("d://lyshark.pcap")           # 讀取封包
>>>
>>> pcap_packets
<lyshark.pcap: TCP:2 UDP:0 ICMP:0 Other:0>
>>>
>>> pcap_packets.show()
0000 Ether / IP / TCP 192.168.1.101:63995 > 172.217.24.10:https S
0001 Ether / IP / TCP 192.168.1.101:63907 > 103.235.46.191:https A / Raw
>>>
>>> pcap_packets.summary()
Ether / IP / TCP 192.168.1.101:63995 > 172.217.24.10:https S
Ether / IP / TCP 192.168.1.101:63907 > 103.235.46.191:https A / Raw
>>>
>>> pcap_packets[0].dst
'FF:2d:1e:0f:1e:a1'
>>>
>>> pcap_packets[0].src
'a4:7e:33:ee:cc:b3'
>>>
# 如下分別代表: 鏈路層 [Ethernet]、網路層[IP]、傳輸層[TCP/UDP]、應用層[RAW]
>>> pcap_packets[0].show()
>>>
# 抓包後直接輸出
>>> sniff(prn=lambda x: x.show(), count=1)

通過上方的抓包流程讀者即可實現簡單的抓包功能,當然sniff函數引數眾多我們完全可以在抓包時增加不同的抓包條件,同時該函數也支援回撥函數,當由新的請求被觸發時則自動執行回撥函數,如下則是使用Scapy抓包的完整案例,該案例展示了抓取60秒封包,並將其儲存至d://lyshark.pcap目錄。

from scapy.all import *
import scapy.all as scapy

# 封包回撥函數
def packet_callback(packet):
    if packet[TCP].payload:
        m_packet = str(packet[TCP].payload)
        print("主機地址: {} ---> 封包內容: {}".format(packet[IP].dst,packet[TCP].payload))

if __name__ == "__main__":
    # 抓取80埠的封包並輸出到螢幕
    # sniff(filter="tcp port 80", prn=packet_callback, store=0)

    # 抓取 過濾出tcp協定 抓取1分鐘後儲存到檔案中
    package=sniff(filter="tcp", timeout=60, prn=packet_callback, store=1)
    wrpcap("d://lyshark.pcap", package)

執行上方抓包程式,讀者可看到如下圖所示的輸出結果,等待60秒後即可看到d://lyshark.pcap檔案。

當讀者抓取到這些封包之後,下一步則是解析這些封包,解析的方法有許多可以使用DPKT解析,也可以使用scapy自帶的工具解析,本章首先介紹如何使用Scapy工具實現解析封包內的HTTP請求,並輸出的功能,如下是完整的程式碼實現;

from scapy.all import *
import scapy.all as scapy

# 解析獲取到的封包
def get_http_pcap(pcap_path):
    pcap_infos = list()
    packets = scapy.rdpcap(pcap_path)
    for p in packets:
        if p.haslayer("IP"):
            src_ip = p["IP"].src
            dst_ip = p["IP"].dst
        if p.haslayer("TCP"):
            raw_http = p["TCP"].payload.original
            sport = p["TCP"].sport
            dport = p["TCP"].dport
        if p.haslayer("HTTPRequest"):
            host = p["HTTPRequest"].Host
            uri = p["HTTPRequest"].Path
            http_fields = p["HTTPRequest"].fields
            # print("主機地址: {} --> URI: {}".format(host,uri))
        print("原IP地址: {}:{} --> 目標IP地址: {}:{}".format(src_ip,sport,dst_ip,dport))

if __name__ == "__main__":
    get_http_pcap("d://lyshark.pcap")

讀者可自行執行上述程式碼,並傳入剛才抓取到的lyshark.pcap封包,此時則可解析出當前封包中所有HTTP存取資料,如下圖所示;

對於封包的解包功能,Dpkt工具包也可以很好的完成,對於使用Dpkt解包而言,首先需要通過open()開啟封包,接著呼叫dpkt.pcap.Reader(fp)將檔案內的位元組轉化為PCAP格式,最後呼叫自定義函數GetDpkt根據欄位進行解析即可。

import dpkt
import socket

def GetDpkt(pcap):
    for timestamp,packet in pcap:
        try:
            eth = dpkt.ethernet.Ethernet(packet)
            ip = eth.data
            tcp = ip.data

            src = socket.inet_ntoa(ip.src)
            dst = socket.inet_ntoa(ip.dst)
            sport = tcp.sport
            dport = tcp.dport
            print("[+] 源地址: {}:{} --> 目標地址:{}:{}".format(src,sport,dst,dport))
        except Exception:
            pass

# 檢測主機是否被DDOS攻擊了
def FindDDosAttack(pcap):
    pktCount = {}
    for timestamp,packet in pcap:
        try:
            eth = dpkt.ethernet.Ethernet(packet)
            ip = eth.data
            tcp = ip.data
            src = socket.inet_ntoa(ip.src)
            dst = socket.inet_ntoa(ip.dst)
            sport = tcp.sport
            # 累計判斷各個src地址對目標地址80埠存取次數
            if dport == 80:
                stream = src + ":" + dst
                if pktCount.has_key(stream):
                    pktCount[stream] = pktCount[stream] + 1
                else:
                    pktCount[stream] = 1
        except Exception:
            pass
    for stream in pktCount:
        pktSent = pktCount[stream]
        # 如果超過設定的檢測閾值500,則判斷為DDOS攻擊行為
        if pktSent > 500:
            src = stream.split(":")[0]
            dst = stream.split(":")[1]
            print("[+] 源地址: {} 攻擊: {} 流量: {} pkts.".format(src,dst,str(pktSent)))

# FindPcapURL 監控提取封包中的所有URL
def FindPcapURL(pcap):
    Url = []
    for timestamp,packet in pcap:
        try:
            eth = dpkt.ethernet.Ethernet(packet)
            ip = eth.data
            src = socket.inet_ntoa(ip.src)
            tcp = ip.data
            http = dpkt.http.Request(tcp.data)
            if(http.method == "GET"):
                UrlHead = http.headers
                for key,value in UrlHead.items():
                    url = re.findall('^https*://.*',str(value))
                    if url:
                        print("[+] 源地址: %10s --> 存取URL: %-80s"%(src, url[0]))
        except Exception:
            pass
    return set(Url)

# 動態儲存pcap檔案(每1024位元組儲存一次pcap檔案),並讀取出其中的網址解析出來
def write_cap(pkt):
    global pkts
    global count
    pkts.append(pkt)
    count += 1
    if count == 1024:
        wrpcap("data.pcap",pkts)
        fp = open("./data.pcap","rb")
        pcap = dpkt.pcap.Reader(fp)
        FindPcapURL(pcap)
        fp.close()
        pkts,count = [],0

if __name__ == "__main__":
    fp = open("d://lyshark.pcap","rb")
    pcap = dpkt.pcap.Reader(fp)
    GetDpkt(pcap)

執行上述程式碼,同樣可以輸出這些IP資訊,如下圖所示;

本文作者: 王瑞
本文連結: https://www.lyshark.com/post/29b6bdae.html
版權宣告: 本部落格所有文章除特別宣告外,均採用 BY-NC-SA 許可協定。轉載請註明出處!