This module contains a class that wraps the folium
package to plot geo-location data.
Read the Folium documentation
You must have msticpy installed to run this notebook:
!pip install --upgrade msticpy
# Imports
import sys
MIN_REQ_PYTHON = (3,6)
if sys.version_info < MIN_REQ_PYTHON:
print('Check the Kernel->Change Kernel menu and ensure that Python 3.6')
print('or later is selected as the active kernel.')
sys.exit("Python %s.%s or later is required.\n" % MIN_REQ_PYTHON)
from IPython.display import display
import pandas as pd
import msticpy.sectools as sectools
from msticpy.nbtools import *
from msticpy.nbtools.entityschema import IpAddress, GeoLocation
from msticpy.nbtools.foliummap import FoliumMap
FoliumMap(
title: str = 'layer1',
zoom_start: float = 2.5,
tiles=None,
width: str = '100%',
height: str = '100%',
location: list = None,
)
Wrapper class for Folium/Leaflet mapping.
Parameters
----------
title : str, optional
Name of the layer (the default is 'layer1')
zoom_start : int, optional
The zoom level of the map (the default is 7)
tiles : [type], optional
Custom set of tiles or tile URL (the default is None)
width : str, optional
Map display width (the default is '100%')
height : str, optional
Map display height (the default is '100%')
location : list, optional
Location to center map on
Attributes
----------
folium_map : folium.Map
folium_map = FoliumMap(width="50%", height="50%", location=(47.5982328,-122.331), zoom_start=14)
folium_map
The underlying folium map object is accessible as the folium_map
attribute
type(folium_map.folium_map)
folium.folium.Map
fol_map.add_ip_cluster(
ip_entities: Iterable[msticpy.nbtools.entityschema.IpAddress],
**kwargs,
)
Add a collection of IP Entities to the map.
Parameters
----------
ip_entities : Iterable[IpAddress]
a iterable of IpAddress Entities
Other Parameters
----------------
kwargs: icon properties to use for displaying this cluster
import pickle
with open(b"data/ip_entities.pkl", "rb") as fh:
ip_entities = pickle.load(fh)
ip_entities = [ip for ip in ip_entities if ip.Location and ip.Location.Latitude]
folium_map = FoliumMap(zoom_start=9)
folium_map.add_ip_cluster(ip_entities=ip_entities, color='orange')
folium_map.center_map()
folium_map
# Read in some data
geo_loc_df = pd.read_csv("data/ip_locs.csv", index_col=0)
geo_loc_df.head()
AllExtIPs | AdditionalData | Type | CountryCode | CountryName | State | City | Longitude | Latitude | IpAddress | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 65.55.44.109 | {} | geolocation | US | United States | Virginia | Boydton | -78.3750 | 36.6534 | 65.55.44.109 |
1 | 13.71.172.128 | {} | geolocation | CA | Canada | Ontario | Toronto | -79.4195 | 43.6644 | 13.71.172.128 |
2 | 13.71.172.130 | {} | geolocation | CA | Canada | Ontario | Toronto | -79.4195 | 43.6644 | 13.71.172.130 |
3 | 40.124.45.19 | {} | geolocation | US | United States | Texas | San Antonio | -98.4935 | 29.4247 | 40.124.45.19 |
4 | 104.43.212.12 | {} | geolocation | US | United States | Iowa | Des Moines | -93.6112 | 41.6006 | 104.43.212.12 |
# Create IP and GeoLocation Entities from the dataframe
def create_ip_entity(row):
ip_ent = IpAddress(Address=row["AllExtIPs"])
geo_loc = create_geo_entity(row)
ip_ent.Location = geo_loc
return ip_ent
def create_geo_entity(row):
# get subset of fields for GeoLocation
loc_props = row[["CountryCode", "CountryName","State", "City", "Longitude", "Latitude"]]
geo_loc = GeoLocation(**loc_props.to_dict())
return geo_loc
geo_locs = list(geo_loc_df.apply(create_geo_entity, axis=1).values)
ip_ents = list(geo_loc_df.apply(create_ip_entity, axis=1).values)
ip_ents[:5]
[IpAddress(Address=65.55.44.109, Location={ 'AdditionalData': {}, 'City': 'Boydton', 'C...), IpAddress(Address=13.71.172.128, Location={ 'AdditionalData': {}, 'City': 'Toronto', '...), IpAddress(Address=13.71.172.130, Location={ 'AdditionalData': {}, 'City': 'Toronto', '...), IpAddress(Address=40.124.45.19, Location={ 'AdditionalData': {}, 'City': 'San Antonio', ...), IpAddress(Address=104.43.212.12, Location={ 'AdditionalData': {}, 'City': 'Des Moines', ...)]
geo_loc_df.apply(lambda x: (x.Latitude, x.Longitude), axis=1).values
array([(36.6534, -78.375), (43.6644, -79.4195), (43.6644, -79.4195), (29.4247, -98.4935), (41.6006, -93.6112), (41.1399, -104.8193), (36.6534, -78.375), (43.6644, -79.4195), (38.7095, -78.1539), (38.7095, -78.1539), (36.6534, -78.375), (47.6742, -122.1243), (38.7095, -78.1539), (53.3338, -6.2488), (29.4247, -98.4935), (41.6006, -93.6112), (41.6006, -93.6112), (41.6006, -93.6112), (38.7095, -78.1539), (36.6534, -78.375), (36.6534, -78.375), (37.3388, -121.8914), (37.3388, -121.8914), (38.7095, -78.1539), (38.7095, -78.1539), (38.7095, -78.1539), (38.7095, -78.1539), (38.7095, -78.1539), (38.7095, -78.1539), (38.7095, -78.1539), (53.3338, -6.2488), (41.6006, -93.6112), (38.7095, -78.1539), (38.7095, -78.1539), (38.7095, -78.1539), (36.6534, -78.375), (38.7095, -78.1539), (41.6006, -93.6112), (41.6006, -93.6112), (41.6006, -93.6112), (38.7095, -78.1539), (37.3388, -121.8914), (37.3388, -121.8914), (38.7095, -78.1539), (41.6006, -93.6112), (40.4953, -111.9439), (41.6006, -93.6112), (41.6006, -93.6112), (36.6534, -78.375), (38.7095, -78.1539), (38.7095, -78.1539)], dtype=object)
fmap_ips = FoliumMap()
fmap_ips.add_ip_cluster(ip_entities=ip_ents[:20], color='blue')
fmap_ips.center_map()
fmap_ips
fmap_ips.add_ip_cluster(ip_entities=ip_ents[30:40], color='red', icon="flash")
fmap_ips.center_map()
fmap_ips
By default folium uses the information icon (i). Icons can be taken from the default Bootstrap set. See the default list here glyphicons
Alternatively you can use icons from the Font Awesome collection by adding prefx="fa" and icon="icon_name" to the call to add_ip_cluster or add_geo_cluster.
fmap_ips.add_geoloc_cluster(geo_locations=geo_locs[40:50], color='darkblue', icon="desktop", prefix="fa")
fmap_ips.center_map()
fmap_ips
from msticpy.nbtools.foliummap import get_map_center, get_center_ip_entities, get_center_geo_locs
print(get_center_geo_locs(geo_locs))
print(get_center_geo_locs(geo_locs, mode="mean"))
# get_map_center Will accept iterable of any entity type that is either
# an IpAddress entity or an entity that has properties of type IpAddress
print(get_map_center(ip_ents[30:40]))
print(get_map_center(ip_ents[:20]))
print(get_center_ip_entities(ip_ents[:20]))
(38.7095, -78.375) (39.70266078431372, -85.0484019607843) (40.15505, -78.26445) (39.9247, -79.4195) (39.9247, -79.4195)
from msticpy.sectools.geoip import entity_distance
print("Distance between")
print(ip_ents[0], ip_ents[1])
print("\n", entity_distance(ip_ents[0], ip_ents[1]), "km")
print("Distance between")
print(ip_ents[0], ip_ents[13])
print("\n", entity_distance(ip_ents[0], ip_ents[13]), "km")
Distance between { 'AdditionalData': {}, 'Address': '65.55.44.109', 'Location': { 'AdditionalData': {}, 'City': 'Boydton', 'CountryCode': 'US', 'CountryName': 'United States', 'Latitude': 36.6534, 'Longitude': -78.375, 'State': 'Virginia', 'Type': 'geolocation', 'edges': set()}, 'ThreatIntelligence': [], 'Type': 'ipaddress', 'edges': set()} { 'AdditionalData': {}, 'Address': '13.71.172.128', 'Location': { 'AdditionalData': {}, 'City': 'Toronto', 'CountryCode': 'CA', 'CountryName': 'Canada', 'Latitude': 43.6644, 'Longitude': -79.4195, 'State': 'Ontario', 'Type': 'geolocation', 'edges': set()}, 'ThreatIntelligence': [], 'Type': 'ipaddress', 'edges': set()} 784.604908273247 km Distance between { 'AdditionalData': {}, 'Address': '65.55.44.109', 'Location': { 'AdditionalData': {}, 'City': 'Boydton', 'CountryCode': 'US', 'CountryName': 'United States', 'Latitude': 36.6534, 'Longitude': -78.375, 'State': 'Virginia', 'Type': 'geolocation', 'edges': set()}, 'ThreatIntelligence': [], 'Type': 'ipaddress', 'edges': set()} { 'AdditionalData': {}, 'Address': '40.77.226.250', 'Location': { 'AdditionalData': {}, 'City': 'Dublin', 'CountryCode': 'IE', 'CountryName': 'Ireland', 'Latitude': 53.3338, 'Longitude': -6.2488, 'State': 'Leinster', 'Type': 'geolocation', 'edges': set()}, 'ThreatIntelligence': [], 'Type': 'ipaddress', 'edges': set()} 5699.044784950343 km