• 21.4 Python 使用GeoIP2地图定位


    GeoIP2是一种IP地址定位库,它允许开发人员根据IP地址查找有关位置和地理位置的信息。它使用MaxMind公司的IP地址数据库,并提供一个方便的Python API。GeoIP2可以用于许多不同的应用程序,例如网站分析、广告定位和身份验证。GeoIP2提供了许多不同的信息,例如国家、城市、邮政编码、经纬度、时区等等。它还可以使用IPv6地址进行查询。

    • 安装第三方库:pip install geoip2

    读者可自行执行pip install geoip2命令安装这个第三方库,并自行下载对应免费版本的GeoLite2-City.mmdb主机数据库文件,当一切准备就绪以后我们就可以使用该数据库定位位置了,如下代码是一个演示案例,首先通过GetPcap将数据包解析并存储值ret变量内返回,当返回后通过geoip2.database加载数据库文件,并通过循环的方式以此查询reader.city数据,并将详细地址输出。

    import dpkt
    import socket
    import geoip2.database
    
    def GetPcap(pcap):
        ret = []
        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)
                ret.append(dst)
            except:
                pass
        return set(ret)
    
    if __name__ == '__main__':
        fp = open('d://lyshark.pcap','rb')
        pcap = dpkt.pcap.Reader(fp)
        addr = GetPcap(pcap)
        reader = geoip2.database.Reader("d://GeoLite2-City.mmdb")
        for item in addr:
            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"]),end="\n")
            except Exception:
                pass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    当读者运行上述代码后,则可输出当前抓到数据包的详细信息,其中包括了网段,经纬度,地区等敏感数据,如下图所示;

    当获取当经纬度详细信息后,则下一步就是要生成一个Google地图模板,一般Google底部模板采用KML文件格式,如下这段代码则是生成一个对应的地图模板,通过传入所需分析的pcap数据包以及数据库信息,则可以输出一个GoogleEarth.kml模板文件。

    import dpkt
    import socket
    import geoip2.database
    from optparse import OptionParser
    
    def GetPcap(pcap):
        ret = []
        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)
                ret.append(dst)
            except:
                pass
        return set(ret)
    
    def retKML(addr,longitude,latitude):
        kml = (
                  '\n'
                  '%s\n'
                  '\n'
                  '%6f,%6f\n'
                  '\n'
                  '\n'
              ) %(addr, longitude, latitude)
        return kml
    
    if __name__ == '__main__':
        parser = OptionParser()
        parser.add_option("-p", "--pcap", dest="pcap_file", help="set -p *.pcap")
        parser.add_option("-d", "--mmdb", dest="mmdb_file", help="set -d *.mmdb")
        (options, args) = parser.parse_args()
        if options.pcap_file and options.mmdb_file:
            fp = open(options.pcap_file,'rb')
            pcap = dpkt.pcap.Reader(fp)
            addr = GetPcap(pcap)
            reader = geoip2.database.Reader(options.mmdb_file)
    
            kmlheader = '<?xml version="1.0" encoding="UTF-8"?>\
            \n<kml xmlns="http://www.opengis.net/kml/2.2">\n<Document>\n'
            with open("GoogleEarth.kml", "w") as f:
                f.write(kmlheader)
                f.close()
    
            for item in addr:
                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"]),end="\n")
    
                    with open("GoogleEarth.kml","a+") as f:
                        f.write(retKML(item,response.location.latitude, response.location.longitude))
                        f.close()
                except Exception:
                    pass
    
            kmlfooter = '\n\n'
            with open("GoogleEarth.kml", "a+") as f:
                f.write(kmlfooter)
                f.close()
        else:
            parser.print_help()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    此时打开谷歌地图,并选择左侧的项目菜单,选择从计算机中导入KML文件,并自行将googleearth.kml文件导入到地图文件内,如下图所示;

    当导入成功后,此时在地图左侧将会出现一些坐标信息,此时读者可自行点击这些坐标以确定当前IP地址的详细位置,当然该地址仅供参考,因为某些主机的地址可能会使用隐藏IP的方式并不一定确保一定准确。

    当然了上述代码只是一个演示案例,在实际过滤中我们可以会进行多层解析,例如如下这段代码,其中AnalysisIP_To_Address函数就可用于接收一个过滤规则,代码中dport ==80 or dport == 443则用于只过滤出目标端口是80443的主机信息,读者也可自行增加一条符合规则的过滤条件进行自定义捕捉,此处仅仅只是一个演示案例。

    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
    
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
  • 相关阅读:
    CSRNET图像修复,DNN
    Vue热更新出现内存溢出
    JAVA中小型医院网站计算机毕业设计Mybatis+系统+数据库+调试部署
    ExpressLRS开源代码之工程结构
    Python-Numpy中的repmat
    vs2022生成失败怎么解决
    hadoop伪分布模式配置
    13 | k8s的部署策略
    Cython加密python代码防止反编译
    LNMP编译安装
  • 原文地址:https://blog.csdn.net/lyshark_csdn/article/details/134018338