Python 运用Dpkt库解析数据包

dpkt是一个用于解析和操作网络数据包的Python模块。它提供了对各种网络协议(如以太网、IP、TCP、UDP、ICMP等)的解析功能,并允许访问和操作数据包的各个字段和参数。可以用于解析从各种抓包工具捕获的数据包,并提取和分析包内的参数。

dpkt包的一些主要特点和用途:

  • 数据包解析:dpkt提供了解析网络数据包的功能,可以读取和解析从各种抓包工具(如Wireshark)导出的数据包文件(如pcap文件)。

  • 支持多种协议:dpkt支持解析和操作多种网络协议,包括以太网、IP、TCP、UDP、ICMP等。它可以识别和提取数据包中的各个协议头部,并提供了访问协议字段的方法。

  • 简单易用:dpkt的API设计简单易用,使得解析和操作数据包变得容易。您可以使用Python代码轻松地读取数据包文件,遍历数据包,并访问和处理数据包中的各个字段。

  • 数据包生成:除了解析数据包,dpkt还提供了创建和构造数据包的功能。您可以使用dpkt来生成特定协议的数据包,并设置各个字段的值。

  • 协议分析和网络流量分析:借助dpkt,您可以进行协议分析和网络流量分析。通过解析数据包并提取关键信息(如源IP地址、目标IP地址、端口号等),您可以进行网络流量统计、行为分析、异常检测等操作。

  • 兼容性:dpkt与Python的标准库兼容,并可以与其他Python库(如socket、struct等)结合使用。

总体而言,dpkt是一个功能强大且易于使用的Python模块,适用于网络数据包的解析、分析和操作。无论是进行网络安全研究、网络流量分析、网络协议分析还是开发网络应用程序,dpkt都可以为您提供便捷的工具和功能。

使用Dpkt分析数据包

代码使用了dpkt模块来读取和解析pcap文件(例如"D://aaa.pcap")中的数据包,并搜索其中的HTTP请求中是否包含指定的关键词(例如"wang.zip")。

#coding=utf-8
import dpkt
import socket

def FindPcapWord(pcap,WordKey):
    for ts,buf in pcap:
        try:
            eth = dpkt.ethernet.Ethernet(buf)
            ip = eth.data
            src = socket.inet_ntoa(ip.src)
            dst = socket.inet_ntoa(ip.dst)
            tcp = ip.data
            http = dpkt.http.Request(tcp.data)
            if(http.method == "GET"):
                uri = http.uri.lower()
                if WordKey in uri:
                    print("[+] 源地址: {} --> 目标地址: {} 检索到URL中存在 {}".format(src,dst,uri))
        except Exception:
            pass

fp = open("D://aaa.pcap","rb")
pcap = dpkt.pcap.Reader(fp)
FindPcapWord(pcap,"wang.zip")

也可以使用dpkt解析本机数据包中是否包含后门。

#coding=utf-8
import dpkt
import socket

def FindPcapWord(pcap,WordKey):
    for timestamp,packet in pcap:
        try:
            eth = dpkt.ethernet.Ethernet(packet)
            ip = eth.data
            src = socket.inet_ntoa(ip.src)
            dst = socket.inet_ntoa(ip.dst)
            tcp = ip.data
            http = dpkt.http.Request(tcp.data)
            if(http.method == "GET"):
                uri = http.uri.lower()
                if WordKey in uri:
                    print("[+] 源地址: {} --> 目标地址: {} 检索到URL中存在 {}".format(src,dst,uri))
        except Exception:
            pass

def Banner():
    print("  _          ____  _                _    ")
    print(" | |   _   _/ ___|| |__   __ _ _ __| | __")
    print(" | |  | | | \___ \| '_ \ / _` | '__| |/ /")
    print(" | |__| |_| |___) | | | | (_| | |  |   < ")
    print(" |_____\__, |____/|_| |_|\__,_|_|  |_|\_\\")
    print("       |___/                             \n")
    print("E-Mail: me@lyshark.com")

def FindHivemind(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))
            if dport == 80 and dst == "125.39.247.226":
                # 如果数据流中存在cmd等明文命令则说明可能存在后门
                if '[cmd]# ' in tcp.data.lower():
                    print("[+] {}:{}".format(dst,dport))
        except Exception:
            pass

Banner()
fp = open("D://aaa.pcap","rb")
pcap = dpkt.pcap.Reader(fp)
FindHivemind(pcap)

实时检测DDoS攻击

主要通过设置检测不正常数据包数量的阈值来判断是否存在DDoS攻击。

#coding=utf-8
import dpkt
import socket

def FindPcapWord(pcap,WordKey):
    for timestamp,packet in pcap:
        try:
            eth = dpkt.ethernet.Ethernet(packet)
            ip = eth.data
            src = socket.inet_ntoa(ip.src)
            dst = socket.inet_ntoa(ip.dst)
            tcp = ip.data
            http = dpkt.http.Request(tcp.data)
            if(http.method == "GET"):
                uri = http.uri.lower()
                if WordKey in uri:
                    print("[+] 源地址: {} --> 目标地址: {} 检索到URL中存在 {}".format(src,dst,uri))
        except Exception:
            pass

def FindHivemind(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))
            if dport == 80 and dst == "125.39.247.226":
                # 如果数据流中存在cmd等明文命令则说明可能存在后门
                if '[cmd]# ' in tcp.data.lower():
                    print("[+] {}:{}".format(dst,dport))
        except Exception:
            pass

def Banner():
    print("  _          ____  _                _    ")
    print(" | |   _   _/ ___|| |__   __ _ _ __| | __")
    print(" | |  | | | \___ \| '_ \ / _` | '__| |/ /")
    print(" | |__| |_| |___) | | | | (_| | |  |   < ")
    print(" |_____\__, |____/|_| |_|\__,_|_|  |_|\_\\")
    print("       |___/                             \n")
    print("E-Mail: me@lyshark.com")

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)))

if __name__ == "__main__":
    Banner()
    fp = open("D://data.pcap","rb")
    pcap = dpkt.pcap.Reader(fp)
    FindPcapWord(pcap,"wang.zip")

DPKT动态抓包解析

首先使用scapy动态抓包,然后调用不同的函数对抓到的数据包进行处理提取出想要的数据.

import os,argparse,dpkt
from scapy.all import *
pkts=[]
count=0

# 检查数据包的IP层,提取出IP和TTL字段的值
def Get_TTL(pkt):
    try:
        if pkt.haslayer(IP):
            ip_src = pkt.getlayer(IP).src
            ip_sport = pkt.getlayer(IP).sport
            ip_dst = pkt.getlayer(IP).dst
            ip_dport = pkt.getlayer(IP).dport
            ip_ttl = str(pkt.ttl)
            print("[+] 源地址: %-15s:%-5s --> 目标地址: %-15s:%-5s --> TTL: %-5s"%(ip_src,ip_sport,ip_dst,ip_dport,ip_ttl))
    except Exception:
        pass

# 获取本机发送出去的DNS请求所对应的网站地址
def Get_DNSRR(pkt):
    if pkt.haslayer(DNSRR):
        rrname = pkt.getlayer(DNSRR).rrname
        rdata = pkt.getlayer(DNSRR).rdata
        ttl = pkt.getlayer(DNSRR).ttl
        print("[+] 域名: {} --> 别名: {} --> TTL: {}".format(rrname,rdata,ttl))

# 解析网页的DNS查询记录
def Get_DNSQR(pkt):
    # 判断是否含有DNSRR且存在UDP端口53
    if pkt.haslayer(DNSRR) and pkt.getlayer(UDP).sport == 53:
        rcode = pkt.getlayer(DNS).rcode
        qname = pkt.getlayer(DNSQR).qname
        # 若rcode为3,则表示该域名不存在
        if rcode == 3:
            print("[-] 域名解析不存在")
        else:
            print("[+] 解析DNSQR存在:" + str(qname))

# 检测主机是否被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

def Banner():
    print("  _          ____  _                _    ")
    print(" | |   _   _/ ___|| |__   __ _ _ __| | __")
    print(" | |  | | | \___ \| '_ \ / _` | '__| |/ /")
    print(" | |__| |_| |___) | | | | (_| | |  |   < ")
    print(" |_____\__, |____/|_| |_|\__,_|_|  |_|\_\\")
    print("       |___/                             \n")
    print("E-Mail: me@lyshark.com")

if __name__ == "__main__":
    Banner()
    parser = argparse.ArgumentParser()
    parser.add_argument("--mode",dest="mode",help="模式选择<TTL/DNSRR/DNSQR/URL>")
    args = parser.parse_args()
    if args.mode == "TTL":
        print("[*] 开始抓取本机TTL流量")
        sniff(prn=Get_TTL,store=0)
    elif args.mode == "DNSRR":
        print("[*] 开始抓取本机发送出去的DNS查询请求所对应的网站URL")
        sniff(prn=Get_DNSRR,store=0)
    elif args.mode == "DNSQR":
        print("[*] 解析网页的DNS查询记录")
        sniff(prn=Get_DNSQR,store=0)
    elif args.mode == "URL":
        print("[+] 开始抓包,pcap文件并读取出其中的网址")
        sniff(prn=write_cap,store=0)
    else:
        parser.print_help()

Geoip2定位IP来源

首先提取出Pcpa格式的数据包文件,然后通过使用离线数据库查询出指定IP地址的地理位置.

# pip install geoip2
# github地址下载:https://github.com/maxmind/GeoIP2-python
# 离线数据库:https://www.maxmind.com/en/accounts/current/geoip/downloads
import argparse
import socket,dpkt
import geoip2.database

def AnalysisPace(DpktPack,Filter):
    respon = []
    with open(DpktPack,"rb") as fp:
        pcap = dpkt.pcap.Reader(fp)
        for timestamp, packet in pcap:
            try:
                eth = dpkt.ethernet.Ethernet(packet)
                # 解析过滤出网络层(三层)中的IP数据包
                if eth.data.__class__.__name__ == "IP":
                    ip = eth.data
                    src = socket.inet_ntoa(ip.src)
                    dst = socket.inet_ntoa(ip.dst)
                    # 解析过滤出传输层(四层)中的TCP数据包
                    if eth.data.data.__class__.__name__ == "TCP":
                        sport = eth.data.data.sport
                        dport = eth.data.data.dport
                        # 过滤出源地址是192.168.1.2且目的端口是80或者443的流量
                        # if src == "192.168.1.2" and dport == 80 or dport == 443:
                        if eval(Filter):
                            dic = { "src":"None","sport":0 , "dst":"None","dport":0 }
                            #print("[+] 时间戳: %-17s 源地址: %-14s:%-2s ---> 目标地址: %-16s:%-2s" %(timestamp,src, sport, dst, dport))
                            RecvData = eth.data.data.data
                            if len(RecvData) and b"GET" in RecvData:
                                #print("[*] 时间戳: {} 源地址: {} <--- 访问网页: {}".format(timestamp,src,bytes.decode(RecvData).split("\n")[1]))
                                pass
                            dic['src'] = src
                            dic['dst'] = dst
                            dic['sport'] = sport
                            dic['dport'] = dport
                            respon.append(dic)
            except Exception:
                pass
    return respon

def AnalysisIP_To_Address(PcapFile,MmdbFile):
    IPDict = AnalysisPace(PcapFile,"dport ==80 or dport == 443")
    NoRepeat = []

    for item in range(len(IPDict)):
        NoRepeat.append(IPDict[item].get("dst"))
    NoRepeat = set(NoRepeat)

    reader = geoip2.database.Reader(MmdbFile)
    for item in NoRepeat:
        try:
            response = reader.city(item)
            print("[+] IP地址: %-16s --> " %item,end="")
            print("网段: %-16s --> " %response.traits.network,end="")
            print("经度: %-10s 纬度: %-10s --> " %(response.location.latitude, response.location.longitude),end="")
            print("定位: {} {} {}".format(response.country.names["zh-CN"],response.subdivisions.most_specific.name,response.city.name),end="\n")
        except Exception:
            print("定位: None None None")
            pass

def Banner():
    print("  _          ____  _                _    ")
    print(" | |   _   _/ ___|| |__   __ _ _ __| | __")
    print(" | |  | | | \___ \| '_ \ / _` | '__| |/ /")
    print(" | |__| |_| |___) | | | | (_| | |  |   < ")
    print(" |_____\__, |____/|_| |_|\__,_|_|  |_|\_\\")
    print("       |___/                             \n")
    print("E-Mail: me@lyshark.com\n")

if __name__ == '__main__':
    Banner()
    parser = argparse.ArgumentParser()
    parser.add_argument("-p", "--pcap", dest="pcap", help="设置抓到的数据包 *.pcap")
    parser.add_argument("-d", "--mmdb", dest="mmdb", help="设置城市数据库 GeoLite2-City.mmdb")
    
    args = parser.parse_args()
    # 使用方式: main.py -p data.pcap -d GeoLite2-City.mmdb (分析数据包中IP)
    if args.pcap and args.mmdb:
        AnalysisIP_To_Address(args.pcap,args.mmdb)
    else:
        parser.print_help()
  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值