We recently released a new version of MSTICPy with a feature called Pivot functions. You must have msticpy installed to run this notebook:
!pip install --upgrade msticpy
MSTICpy versions >= 1.0.0
This feature has three main goals:
Here are a couple of examples showing calling different kinds of enrichment functions from the IpAddress entity:
>>> from msticpy.datamodel.entities import IpAddress, Host
>>> IpAddress.util.ip_type(ip_str="157.53.1.1"))
ip result
157.53.1.1 Public
>>> IpAddress.util.whois("157.53.1.1"))
asn asn_cidr asn_country_code asn_date asn_description asn_registry nets .....
NA NA US 2015-04-01 NA arin [{'cidr': '157.53.0.0/16'...
>>> IpAddress.util.geoloc_mm(value="157.53.1.1"))
CountryCode CountryName State City Longitude Latitude Asn...
US United States None None -97.822 37.751 None...
This second example shows a pivot function that does a data query for host logon events from a Host entity.
>>> Host.AzureSentinel.list_host_logons(host_name="VictimPc")
Account EventID TimeGenerated Computer SubjectUserName SubjectDomainName
NT AUTHORITY\SYSTEM 4624 2020-10-01 22:39:36.987000+00:00 VictimPc.Contoso.Azure VictimPc$ CONTOSO
NT AUTHORITY\SYSTEM 4624 2020-10-01 22:39:37.220000+00:00 VictimPc.Contoso.Azure VictimPc$ CONTOSO
NT AUTHORITY\SYSTEM 4624 2020-10-01 22:39:42.603000+00:00 VictimPc.Contoso.Azure VictimPc$ CONTOSO
The pivot functionality exposes operations relevant to a particular entity as methods (or functions) of that entity. These operations include:
You can also add other functions from 3rd party Python packages or ones you write yourself as pivot functions.
Before we get into things let's clear up a few terms.
These are Python classes that represent real-world objects commonly encountered in CyberSec investigations and hunting. E.g. Host, URL, IP Address, Account, etc.
This comes from the common practice in CyberSec investigations of navigating from one suspect entity to another. E.g. you might start with an alert identifying a potentially malicious IP Address, from there you 'pivot' to see which hosts or accounts were communicating with that address. From there you might pivot again to look at processes running on the host or Office activity for the account.
This article is available in Notebook form so that you can try out the examples. [TODO]
There is also full documenation of the Pivot functionality on our ReadtheDocs page
Before Pivot functions your ability to use the various bits of functionality in MSTICPy was always bounded by you knowledge of where a certain function was (or your enthusiasm for reading the docs).
For example, suppose you had an IP address that you wanted to do some simple enrichment on.
ip_addr = "20.72.193.242"
First you'd need to locate and import the functions. There might also be (as in the GeoIPLiteLookup class) some initialization step you'd need to do before using the functionality.
from msticpy.sectools.ip_utils import get_ip_type
from msticpy.sectools.ip_utils import get_whois_info
from msticpy.sectools.geoip import GeoLiteLookup
geoip = GeoLiteLookup()
Next you might have to check the help for each function to work it parameters.
help(get_ip_type)
Help on function get_ip_type in module msticpy.sectools.ip_utils: get_ip_type(ip: str = None, ip_str: str = None) -> str Validate value is an IP address and deteremine IPType category. (IPAddress category is e.g. Private/Public/Multicast). Parameters ---------- ip : str The string of the IP Address ip_str : str The string of the IP Address - alias for `ip` Returns ------- str Returns ip type string using ip address module
Then finally run the functions
get_ip_type(ip_addr)
'Public'
get_whois_info(ip_addr)
('MICROSOFT-CORP-MSN-AS-BLOCK, US', {'nir': None, 'asn_registry': 'arin', 'asn': '8075', 'asn_cidr': '20.64.0.0/10', 'asn_country_code': 'US', 'asn_date': '2017-10-18', 'asn_description': 'MICROSOFT-CORP-MSN-AS-BLOCK, US', 'query': '20.72.193.242', 'nets': [{'cidr': '20.40.0.0/13, 20.48.0.0/12, 20.128.0.0/16, 20.34.0.0/15, 20.36.0.0/14, 20.64.0.0/10, 20.33.0.0/16', 'name': 'MSFT', 'handle': 'NET-20-33-0-0-1', 'range': '20.33.0.0 - 20.128.255.255', 'description': 'Microsoft Corporation', 'country': 'US', 'state': 'WA', 'city': 'Redmond', 'address': 'One Microsoft Way', 'postal_code': '98052', 'emails': ['msndcc@microsoft.com', 'IOC@microsoft.com', 'abuse@microsoft.com'], 'created': '2017-10-18', 'updated': '2017-10-18'}], 'raw': None, 'referral': None, 'raw_referral': None})
geoip.lookup_ip(ip_addr)
([{'continent': {'code': 'NA', 'geoname_id': 6255149, 'names': {'de': 'Nordamerika', 'en': 'North America', 'es': 'Norteamérica', 'fr': 'Amérique du Nord', 'ja': '北アメリカ', 'pt-BR': 'América do Norte', 'ru': 'Северная Америка', 'zh-CN': '北美洲'}}, 'country': {'geoname_id': 6252001, 'iso_code': 'US', 'names': {'de': 'USA', 'en': 'United States', 'es': 'Estados Unidos', 'fr': 'États-Unis', 'ja': 'アメリカ合衆国', 'pt-BR': 'Estados Unidos', 'ru': 'США', 'zh-CN': '美国'}}, 'location': {'accuracy_radius': 1000, 'latitude': 47.6032, 'longitude': -122.3412, 'time_zone': 'America/Los_Angeles'}, 'registered_country': {'geoname_id': 6252001, 'iso_code': 'US', 'names': {'de': 'USA', 'en': 'United States', 'es': 'Estados Unidos', 'fr': 'États-Unis', 'ja': 'アメリカ合衆国', 'pt-BR': 'Estados Unidos', 'ru': 'США', 'zh-CN': '美国'}}, 'subdivisions': [{'geoname_id': 5815135, 'iso_code': 'WA', 'names': {'en': 'Washington', 'es': 'Washington', 'fr': 'Washington', 'ja': 'ワシントン州', 'ru': 'Вашингтон', 'zh-CN': '华盛顿州'}}], 'traits': {'ip_address': '20.72.193.242', 'prefix_len': 18}}], [IpAddress(Address=20.72.193.242, Location={ 'AdditionalData': {}, 'CountryCode': 'US', ...)])
At which point you'd discover that the output from each function was somewhat raw and it would take a bit more work if you wanted to combine it in any way (say in a single table).
We'll see how pivot functions address these problems in the remainder of the notebook.
Typically we use MSTICPy's init_notebook
function that handles
checking versions and importing some commonly-used packages and modules
(both MSTICPy and 3rd party packages like pandas
from msticpy.nbtools.nbinit import init_notebook
init_notebook(namespace=globals());
msticpy version installed: 0.9.3 latest published: 0.9.0 Latest version is installed. Processing imports.... Imported: pd (pandas.pandas); IPython.IPython; IPython.display.IPython.display; IPython.display.IPython.display; IPython.display.IPython.display; widgets (ipywidgets.ipywidgets); pathlib.pathlib; plt (matplotlib.pyplot.matplotlib.pyplot); matplotlib.matplotlib; sns (seaborn.seaborn); np (numpy.numpy); msticpy.data.msticpy.data; msticpy.nbtools.foliummap.msticpy.nbtools.foliummap; msticpy.common.utility.msticpy.common.utility; msticpy.common.utility.msticpy.common.utility; msticpy.common.wsconfig.msticpy.common.wsconfig Checking configuration.... No errors found. No warnings found. Setting notebook options....
There are some preliminary steps needed before you can use
pivot functions. The main one is loading the Pivot
class.
Pivot functions are added to the entities dynamically. The Pivot
class will try to discover relevant functions from queries,
Threat Intel providers and various utility functions.
In some cases, notably data queries, the data query functions are themselves created dynamically, so these need to be loaded before you create the Pivot class. (You can always create a new instance of this class, which forces re-discovery, so don't worry if mess up the order of things).
Note in most cases we don't need to connect/authenticate to a data provider prior to loading Pivot
Let's load our data query provider for AzureSentinel
az_provider = QueryProvider("AzureSentinel")
Please wait. Loading Kqlmagic extension...
Now we can load and instantiate the Pivot class.
Why do we need to pass namespace=globals()
?
Pivot searches through the current objects defined in the Python/notebook
namespace. This is most relevant for QueryProviders. In most other cases
(like GeoIP and ThreatIntel providers, it will create new ones if it
can't find existing ones).
from msticpy.datamodel.pivot import Pivot
pivot = Pivot(namespace=globals())
Using Open PageRank. See https://www.domcop.com/openpagerank/what-is-openpagerank
The simplest way to do this is simply enumerate (dir
) the
contents of the MSTPCPy entities sub-package. This should
have already been imported by the init_notebook
function that
we ran earlier.
The items at the beginning of the list with proper capitalization are the entities.
dir(entities)
['Account', 'Alert', 'Algorithm', 'AzureResource', 'CloudApplication', 'Dns', 'ElevationToken', 'Entity', 'File', 'FileHash', 'GeoLocation', 'Host', 'HostLogonSession', 'IpAddress', 'Malware', 'NetworkConnection', 'OSFamily', 'Process', 'RegistryHive', 'RegistryKey', 'RegistryValue', 'SecurityGroup', 'Threatintelligence', 'UnknownEntity', 'Url', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'account', 'alert', 'azure_resource', 'cloud_application', 'difflib', 'dns', 'entity', 'entity_enums', 'entity_graph', 'file', 'file_hash', 'find_entity', 'geo_location', 'host', 'host_logon_session', 'ip_address', 'malware', 'network_connection', 'process', 'registry_key', 'registry_value', 'security_group', 'threat_intelligence', 'unknown_entity', 'url']
We're going to make this a little easier in a forthcoming update with this helper function.
Warning: post-0.9.0 functionality
This will throw and error in v0.9.0 of MSTICPy
entities.find_entity("ip")
Match found 'IpAddress'
msticpy.datamodel.entities.ip_address.IpAddress
entities.find_entity("azure")
No exact match found for 'azure'. Closest matches are 'AzureResource', 'Url', 'Malware'
Note you can always address an entity using its qualified
path, e.g. entities.IpAddress
but if you are going
to use one or two entities a lot it will save a bit of typing
if you import them explicitly.
from msticpy.datamodel.entities import IpAddress, Host
Once you have the entity you can use the get_pivot_list()
function to see which pivot functions are available for it.
IpAddress.get_pivot_list()
['AzureSentinel.SecurityAlert_list_alerts_for_ip', 'AzureSentinel.SigninLogs_list_aad_signins_for_ip', 'AzureSentinel.AzureActivity_list_azure_activity_for_ip', 'AzureSentinel.AzureNetworkAnalytics_CL_list_azure_network_flows_by_ip', 'AzureSentinel.OfficeActivity_list_activity_for_ip', 'AzureSentinel.AzureNetworkAnalytics_CL_get_host_for_ip', 'AzureSentinel.Heartbeat_get_heartbeat_for_ip', 'AzureSentinel.Heartbeat_get_info_by_ipaddress', 'AzureSentinel.Syslog_list_logons_for_source_ip', 'AzureSentinel.ThreatIntelligenceIndicator_list_indicators', 'AzureSentinel.ThreatIntelligenceIndicator_list_indicators_by_ip', 'AzureSentinel.ThreatIntelligenceIndicator_list_indicators_by_hash', 'AzureSentinel.ThreatIntelligenceIndicator_list_indicators_by_filepath', 'AzureSentinel.ThreatIntelligenceIndicator_list_indicators_by_domain', 'AzureSentinel.ThreatIntelligenceIndicator_list_indicators_by_email', 'AzureSentinel.ThreatIntelligenceIndicator_list_indicators_by_url', 'ti.lookup_ip', 'ti.lookup_ipv4', 'ti.lookup_ipv4_OTX', 'ti.lookup_ipv4_Tor', 'ti.lookup_ipv4_VirusTotal', 'ti.lookup_ipv4_XForce', 'ti.lookup_ipv6', 'ti.lookup_ipv6_OTX', 'util.whois', 'util.ip_type', 'util.ip_rev_resolve', 'util.geoloc_mm', 'util.geoloc_ips']
Some of the function names are a little unweildy but, in many cases, this is necessary to avoid name collisions. You might notice from the list that the functions are grouped into containers "AzureSentinel", "ti" and "util" in the above example.
Although this makes the function name even longer we thought that this helped to keep related functionality together - so you don't get a TI lookup, when you thought you were running a query.
Fortunately Jupyter notebooks/IPython support tab completion so you should not normally have to remember these names.
The containers ("AzureSentinel", "util", etc.) are also callable functions - they just return the list of functions they contain.
IpAddress.util()
whois function ip_type function ip_rev_resolve function geoloc_mm function geoloc_ips function
Now we're ready to run any of the functions for this entity
IpAddress.util.ip_type(ip_addr)
ip | result | |
---|---|---|
0 | 20.72.193.242 | Public |
entities.IpAddress.util.whois(ip_addr)
asn | asn_cidr | asn_country_code | asn_date | asn_description | asn_registry | nets | nir | query | raw | raw_referral | referral | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 8075 | 20.64.0.0/10 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | arin | [{'cidr': '20.40.0.0/13, 20.48.0.0/12, 20.34.0.0/15, 20.64.0.0/10, 20.128.0.0/16, 20.36.0.0/14, ... | None | 20.72.193.242 | None | None | None |
entities.IpAddress.util.ip_rev_resolve(ip_addr)
qname | rdtype | response | ip_address | |
---|---|---|---|---|
0 | 20.72.193.242 | PTR | None of DNS query names exist: 20.72.193.242., 20.72.193.242.corp.microsoft.com. | 20.72.193.242 |
entities.IpAddress.util.geoloc_mm(ip_addr)
CountryCode | CountryName | State | City | Longitude | Latitude | Asn | edges | Type | AdditionalData | IpAddress | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | US | United States | Washington | None | -122.3412 | 47.6032 | None | {} | geolocation | {} | 20.72.193.242 |
entities.IpAddress.ti.lookup_ip(ip_addr)
Ioc | IocType | SafeIoc | QuerySubtype | Provider | Result | Severity | Details | RawResult | Reference | Status | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 20.72.193.242 | ipv4 | 20.72.193.242 | None | Tor | True | information | Not found. | None | https://check.torproject.org/exit-addresses | 0 |
0 | 20.72.193.242 | ipv4 | 20.72.193.242 | None | VirusTotal | True | unknown | {'verbose_msg': 'Missing IP address', 'response_code': 0} | {'response_code': 0, 'verbose_msg': 'Missing IP address'} | https://www.virustotal.com/vtapi/v2/ip-address/report | 0 |
0 | 20.72.193.242 | ipv4 | 20.72.193.242 | None | XForce | True | warning | {'score': 1, 'cats': {}, 'categoryDescriptions': {}, 'reason': 'Regional Internet Registry', 're... | {'ip': '20.72.193.242', 'history': [{'created': '2012-03-22T07:26:00.000Z', 'reason': 'Regional ... | https://api.xforce.ibmcloud.com/ipr/20.72.193.242 | 0 |
Notice that we didn't need to worry about either the parameter name or format (more on this in the next section). Also, whatever the function, the output is always returned as a pandas DataFrame.
Data query functions are a little more complex than most other functions and specifically often support many parameters. Rather than try to guess which parameter you meant, we require you to be explicit.
To use a data query, we need to authenticate to the provider.
az_provider.connect(WorkspaceConfig(workspace="CyberSecuritySoc").code_connect_str)
If you are not sure of the parameters required by the query you can use the built-in help
Host.AzureSentinel.SecurityAlert_list_related_alerts?
Signature: Host.AzureSentinel.SecurityAlert_list_related_alerts(*args, **kwargs) -> Union[pandas.core.frame.DataFrame, Any] Docstring: Retrieves list of alerts with a common host, account or process Parameters ---------- account_name: str (optional) The account name to find add_query_items: str (optional) Additional query clauses end: datetime (optional) Query end time host_name: str (optional) The hostname to find path_separator: str (optional) Path separator (default value is: \\) process_name: str (optional) The process name to find query_project: str (optional) Column project statement (default value is: | project-rename StartTimeUtc = StartTime, EndTim...) start: datetime (optional) Query start time (default value is: -30) subscription_filter: str (optional) Optional subscription/tenant filter expression (default value is: true) table: str (optional) Table name (default value is: SecurityAlert) File: c:\users\ian\anaconda3\envs\condadev\lib\functools.py Type: function
Host.AzureSentinel.SecurityAlert_list_related_alerts(host_name="victim00").head(5)
TenantId | TimeGenerated | AlertDisplayName | AlertName | Severity | Description | ProviderName | VendorName | VendorOriginalId | SystemAlertId | ResourceId | SourceComputerId | AlertType | ConfidenceLevel | ConfidenceScore | IsIncident | StartTimeUtc | EndTimeUtc | ProcessingEndTime | RemediationSteps | ExtendedProperties | Entities | SourceSystem | WorkspaceSubscriptionId | WorkspaceResourceGroup | ExtendedLinks | ProductName | ProductComponentName | AlertLink | Status | CompromisedEntity | Tactics | Type | Computer | src_hostname | src_accountname | src_procname | host_match | acct_match | proc_match | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2021-03-11 12:05:14.355000+00:00 | Suspected credential theft activity | Suspected credential theft activity | Medium | This program exhibits suspect characteristics potentially associated with credential theft. Onc... | MDATP | Microsoft | da637509097413415122_-841817867 | bf226b1b-8bda-31f7-c848-1f8bbb5f5922 | WindowsDefenderAtp | NaN | False | 2021-03-09 17:56:55.275000+00:00 | 2021-03-09 17:56:55.275000+00:00 | 2021-03-11 12:05:13.759000+00:00 | [\r\n "1. Make sure the machine is completely updated and all your software has the latest patc... | {\r\n "MicrosoftDefenderAtp.Category": "CredentialAccess",\r\n "MicrosoftDefenderAtp.Investiga... | [\r\n {\r\n "$id": "4",\r\n "DnsDomain": "na.contosohotels.com",\r\n "HostName": "vict... | Detection | Microsoft Defender Advanced Threat Protection | https://securitycenter.microsoft.com/alert/da637509097413415122_-841817867?tid=4b2462a4-bbee-495... | New | victim00.na.contosohotels.com | CredentialAccess | SecurityAlert | victim00 | victim00 | True | False | False | |||||||||
1 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2021-03-11 13:24:53.495000+00:00 | 'Mimikatz' hacktool was detected | 'Mimikatz' hacktool was detected | Low | Readily available tools, such as hacking programs, can be used by unauthorized individuals to sp... | MDATP | Microsoft | da637510393722104539_-1180405651 | ef04126b-2683-0a98-d01c-77ee6b1115ac | WindowsDefenderAv | NaN | False | 2021-03-11 06:00:14.083000+00:00 | 2021-03-11 06:00:14.083000+00:00 | 2021-03-11 13:24:53.379000+00:00 | [\r\n "1. Make sure the machine is completely updated and all your software has the latest patc... | {\r\n "MicrosoftDefenderAtp.Category": "Malware",\r\n "MicrosoftDefenderAtp.InvestigationId": ... | [\r\n {\r\n "$id": "4",\r\n "DnsDomain": "na.contosohotels.com",\r\n "HostName": "vict... | Detection | Microsoft Defender Advanced Threat Protection | https://securitycenter.microsoft.com/alert/da637510393722104539_-1180405651?tid=4b2462a4-bbee-49... | New | victim00.na.contosohotels.com | Unknown | SecurityAlert | victim00 | victim00 | True | False | False | |||||||||
2 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2021-03-11 13:24:53.490000+00:00 | Suspected credential theft activity | Suspected credential theft activity | Medium | This program exhibits suspect characteristics potentially associated with credential theft. Onc... | MDATP | Microsoft | da637509097413415122_-841817867 | bf226b1b-8bda-31f7-c848-1f8bbb5f5922 | WindowsDefenderAtp | NaN | False | 2021-03-09 17:56:55.275000+00:00 | 2021-03-09 17:56:55.275000+00:00 | 2021-03-11 13:24:53.363000+00:00 | [\r\n "1. Make sure the machine is completely updated and all your software has the latest patc... | {\r\n "MicrosoftDefenderAtp.Category": "CredentialAccess",\r\n "MicrosoftDefenderAtp.Investiga... | [\r\n {\r\n "$id": "4",\r\n "DnsDomain": "na.contosohotels.com",\r\n "HostName": "vict... | Detection | Microsoft Defender Advanced Threat Protection | https://securitycenter.microsoft.com/alert/da637509097413415122_-841817867?tid=4b2462a4-bbee-495... | New | victim00.na.contosohotels.com | CredentialAccess | SecurityAlert | victim00 | victim00 | True | False | False | |||||||||
3 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2021-03-11 13:19:42.521000+00:00 | Malicious credential theft tool execution detected | Malicious credential theft tool execution detected | High | A known credential theft tool execution command line was detected.\nEither the process itself or... | MDATP | Microsoft | da637508847019595161_-562481393 | 753680a5-4d20-2726-61b4-9c36e620ea26 | WindowsDefenderAtp | NaN | False | 2021-03-09 10:56:58.134000+00:00 | 2021-03-09 10:56:58.134000+00:00 | 2021-03-11 13:19:42.289000+00:00 | [\r\n "1. Make sure the machine is completely updated and all your software has the latest patc... | {\r\n "MicrosoftDefenderAtp.Category": "CredentialAccess",\r\n "MicrosoftDefenderAtp.Investiga... | [\r\n {\r\n "$id": "4",\r\n "DnsDomain": "na.contosohotels.com",\r\n "HostName": "vict... | Detection | Microsoft Defender Advanced Threat Protection | https://securitycenter.microsoft.com/alert/da637508847019595161_-562481393?tid=4b2462a4-bbee-495... | New | victim00.na.contosohotels.com | CredentialAccess | SecurityAlert | victim00 | victim00 | True | False | False | |||||||||
4 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2021-03-11 14:30:14.730000+00:00 | 'Mimikatz' hacktool was detected | 'Mimikatz' hacktool was detected | Low | Readily available tools, such as hacking programs, can be used by unauthorized individuals to sp... | MDATP | Microsoft | da637510393722104539_-1180405651 | ef04126b-2683-0a98-d01c-77ee6b1115ac | WindowsDefenderAv | NaN | False | 2021-03-11 06:00:14.083000+00:00 | 2021-03-11 06:00:14.083000+00:00 | 2021-03-11 14:30:14.450000+00:00 | [\r\n "1. Make sure the machine is completely updated and all your software has the latest patc... | {\r\n "MicrosoftDefenderAtp.Category": "Malware",\r\n "MicrosoftDefenderAtp.InvestigationId": ... | [\r\n {\r\n "$id": "4",\r\n "DnsDomain": "na.contosohotels.com",\r\n "HostName": "vict... | Detection | Microsoft Defender Advanced Threat Protection | https://securitycenter.microsoft.com/alert/da637510393722104539_-1180405651?tid=4b2462a4-bbee-49... | New | victim00.na.contosohotels.com | Unknown | SecurityAlert | victim00 | victim00 | True | False | False |
We also have a preview of a notebook tool that lets you browser around entities and their pivot functions, search for a function by keyword and view the help for that function. This is going to be released shortly.
Warning: post-0.9.0 functionality
This will throw and error in v0.9.0 of MSTICPy
Pivot.browse()
VBox(children=(HBox(children=(VBox(children=(HTML(value='<b>Entities</b>'), Select(description='entity', layou…
Due to various factors (historical, underlying data, developer laziness and forgetfullness, etc.) the functionality in MSTICPy can be inconsistent in the way it uses input parameters.
Also, many functions will only accept inputs as a single value, or a list or a DataFrame or some unpredictable combination of these.
Pivot functions allow you to largely forget about this - you can use the same function whether you have:
Let's take an example.
Suppose we have a set of IP addresses pasted from somewhere that we want to use as input.
We need to convert this into a Python data object of some sort.
To do this we can use another Pivot utility %%txt2df
. This is a
Jupyter/IPython magic function so you can just paste you data in
a cell.
Use %%txt2df --help
in an empty cell to see the full syntax.
The example below we specify a comma separator, that the data has a headers row and to save the converted data as a DataFrame named "ip_df".
Warning this will overwrite any existing variable of this
name
%%txt2df --sep , --headers --name ip_df
idx, ip, type
0, 172.217.15.99, Public
1, 40.85.232.64, Public
2, 20.38.98.100, Public
3, 23.96.64.84, Public
4, 65.55.44.108, Public
5, 131.107.147.209, Public
6, 10.0.3.4, Private
7, 10.0.3.5, Private
8, 13.82.152.48, Public
idx | ip | type | |
---|---|---|---|
0 | 0 | 172.217.15.99 | Public |
1 | 1 | 40.85.232.64 | Public |
2 | 2 | 20.38.98.100 | Public |
3 | 3 | 23.96.64.84 | Public |
4 | 4 | 65.55.44.108 | Public |
5 | 5 | 131.107.147.209 | Public |
6 | 6 | 10.0.3.4 | Private |
7 | 7 | 10.0.3.5 | Private |
8 | 8 | 13.82.152.48 | Public |
For our example we'll also create a standard Python list from the ip column.
ip_list = list(ip_df.ip)
print(ip_list)
['172.217.15.99', '40.85.232.64', '20.38.98.100', '23.96.64.84', '65.55.44.108', '131.107.147.209', '10.0.3.4', '10.0.3.5', '13.82.152.48']
If you recall the earlier example of get_ip_type
, passing it
a list or DataFrame doesn't result in anything useful.
get_ip_type(ip_list)
['172.217.15.99', '40.85.232.64', '20.38.98.100', '23.96.64.84', '65.55.44.108', '131.107.147.209', '10.0.3.4', '10.0.3.5', '13.82.152.48'] does not appear to be an IPv4 or IPv6 address
'Unspecified'
However, the pivotized version can accept and correctly process a list
IpAddress.util.ip_type(ip_list)
ip | result | |
---|---|---|
0 | 172.217.15.99 | Public |
1 | 40.85.232.64 | Public |
2 | 20.38.98.100 | Public |
3 | 23.96.64.84 | Public |
4 | 65.55.44.108 | Public |
5 | 131.107.147.209 | Public |
6 | 10.0.3.4 | Private |
7 | 10.0.3.5 | Private |
8 | 13.82.152.48 | Public |
In the case of a DataFrame, things are a little more complicated - we have to tell the function the name of the column that contains the input data.
IpAddress.util.whois(ip_df) # won't work!
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-29-786e8d7fe15b> in <module> ----> 1 IpAddress.util.whois(ip_df) # won't work! e:\src\microsoft\msticpy\msticpy\datamodel\pivot_register.py in pivot_lookup(*args, **kwargs) 172 # {"data": input_df, "src_column": input_column} 173 input_df, input_column, param_dict = _create_input_df( --> 174 input_value, pivot_reg, parent_kwargs=kwargs 175 ) 176 e:\src\microsoft\msticpy\msticpy\datamodel\pivot_register.py in _create_input_df(input_value, pivot_reg, parent_kwargs) 326 "Please specify the column when calling the function." 327 "You can use one of the parameter names for this:", --> 328 _DF_SRC_COL_PARAM_NAMES, 329 ) 330 # we want to get rid of data=xyz parameters from kwargs, since we're adding them KeyError: ("'ip_column' is not in the input dataframe", 'Please specify the column when calling the function.You can use one of the parameter names for this:', ['column', 'input_column', 'input_col', 'src_column', 'src_col'])
IpAddress.util.whois(ip_df, column="ip") # correct
nir | asn_registry | asn | asn_cidr | asn_country_code | asn_date | asn_description | query | nets | raw | referral | raw_referral | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | arin | 15169 | 172.217.15.0/24 | US | 2012-04-16 | GOOGLE, US | 172.217.15.99 | [{'cidr': '172.217.0.0/16', 'name': 'GOOGLE', 'handle': 'NET-172-217-0-0-1', 'range': '172.217.0... | NaN | NaN | NaN |
1 | NaN | arin | 8075 | 40.80.0.0/12 | US | 2015-02-23 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 40.85.232.64 | [{'cidr': '40.80.0.0/12, 40.124.0.0/16, 40.74.0.0/15, 40.76.0.0/14, 40.120.0.0/14, 40.125.0.0/17... | NaN | NaN | NaN |
2 | NaN | arin | 8075 | 20.36.0.0/14 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.38.98.100 | [{'cidr': '20.128.0.0/16, 20.33.0.0/16, 20.34.0.0/15, 20.36.0.0/14, 20.64.0.0/10, 20.40.0.0/13, ... | NaN | NaN | NaN |
3 | NaN | arin | 8075 | 23.96.0.0/14 | US | 2013-06-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 23.96.64.84 | [{'cidr': '23.96.0.0/13', 'name': 'MSFT', 'handle': 'NET-23-96-0-0-1', 'range': '23.96.0.0 - 23.... | NaN | NaN | NaN |
4 | NaN | arin | 8075 | 65.52.0.0/14 | US | 2001-02-14 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 65.55.44.108 | [{'cidr': '65.52.0.0/14', 'name': 'MICROSOFT-1BLK', 'handle': 'NET-65-52-0-0-1', 'range': '65.52... | NaN | NaN | NaN |
5 | NaN | arin | 3598 | 131.107.0.0/16 | US | 1988-11-11 | MICROSOFT-CORP-AS, US | 131.107.147.209 | [{'cidr': '131.107.0.0/16', 'name': 'MICROSOFT', 'handle': 'NET-131-107-0-0-1', 'range': '131.10... | NaN | NaN | NaN |
6 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
7 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
8 | NaN | arin | 8075 | 13.64.0.0/11 | US | 2015-03-26 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 13.82.152.48 | [{'cidr': '13.64.0.0/11, 13.96.0.0/13, 13.104.0.0/14', 'name': 'MSFT', 'handle': 'NET-13-64-0-0-... | NaN | NaN | NaN |
Note: for most functions you can ignore the parameter
name and just specify it as a positional parameter. You can also use the original parameter name of the underlying function or the placeholder name "value".
The following are all equivalent:
IpAddress.util.ip_type(ip_list)
IpAddress.util.ip_type(ip_str=ip_list)
IpAddress.util.ip_type(value=ip_list)
IpAddress.util.ip_type(data=ip_list)
When passing both a DataFrame and column name use:
IpAddress.util.ip_type(data=ip_df, column="col_name")
You can also pass an entity instance of an entity as a input parameter. The pivot code knows which attribute or attributes of an entity will provider the input value.
ip_entity = IpAddress(Address="40.85.232.64")
IpAddress.util.ip_type(ip_entity)
ip | result | |
---|---|---|
0 | 40.85.232.64 | Public |
Many of the underlying functions only accept single values as inputs. Examples of these are the data query functions - typically they expect a single host name, IP address, etc.
Pivot knows about the type of parameters that the function accepts. It will adjust the input to match the expectations of the underlying function. If a list or DataFrame is passed as input to a single-value function Pivot will split the input and call the function once for each value. It then combines the output into a single DataFrame before returning the results.
You can read a bit more about how this is done in the Appendix TODO
The Pivot class has a buit-in time range. This is used by default for all queries. Don't worry - you can change it easily
Pivot.current.timespan
TimeStamp(start=2021-03-10 18:33:43.314239, end=2021-03-11 18:33:43.314239, period=-1 day, 0:00:00)
You can edit the time range interactively
Pivot.current.edit_query_time()
VBox(children=(HTML(value='<h4>Set time range for pivot functions.</h4>'), HBox(children=(DatePicker(value=dat…
Or by setting the timespan property directly
from msticpy.common.timespan import TimeSpan
# TimeSpan accepts datetimes or datestrings
timespan = TimeSpan(start="02/01/2021", end="02/15/2021")
Pivot.current.timespan = timespan
In an upcoming release there is also a convenience function for setting the time directly with Python datetimes or date strings
Warning:
post-0.9.0 functionality This will throw and error in v0.9.0 of MSTICPy
Pivot.current.set_timespan(start="2020-02-06 03:00:00", end="2021-02-15 01:42:42")
You can also override the built-in time settings by specifying
start
and end
as parameters.
dt1 =
Host.AzureSentinel.SecurityAlert_list_related_alerts(host_name="victim00", start=dt1, end=dt2)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-36-a726e25f79ba> in <module> ----> 1 Host.AzureSentinel.SecurityAlert_list_related_alerts(host_name="victim00", start=dt1, end=dt2) NameError: name 'dt1' is not defined
The Pivot layer will pass any unused keyword parameters to the
underlying function. This does not usually apply to positional parameters -
if you want parameters to get to the function, you have to name them
explicitly.
In this example the add_query_items
parameter is passed to the underlying
query function
entities.Host.AzureSentinel.SecurityEvent_list_host_logons(
host_name="victimPc",
add_query_items="| summarize count() by LogonType"
)
LogonType | count_ | |
---|---|---|
0 | 5 | 21650 |
1 | 3 | 6808 |
2 | 4 | 9426 |
3 | 2 | 109 |
4 | 10 | 44 |
5 | 0 | 7 |
6 | 9 | 8 |
Because all pivot functions accept DataFrames as input and produce DataFrames as output, it means that it is possible to chain pivot functions into a pipeline.
You can join the input to the output. This usually only makes sense when the input is a DataFrame. It lets you keep the previously accumumated results and tag on the additional columns produced by the pivot function you are calling.
The join
parameter supports "inner", "left", "right" and "outer"
joins (be careful with the latter though!)
See pivot joins documentation
Although joining is useful in pipelines you can use it on any function whether in a pipeline or not.
entities.IpAddress.util.whois(ip_df, column="ip", join="inner")
idx | ip | type | nir | asn_registry | asn | asn_cidr | asn_country_code | asn_date | asn_description | query | nets | raw | referral | raw_referral | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 172.217.15.99 | Public | NaN | arin | 15169 | 172.217.15.0/24 | US | 2012-04-16 | GOOGLE, US | 172.217.15.99 | [{'cidr': '172.217.0.0/16', 'name': 'GOOGLE', 'handle': 'NET-172-217-0-0-1', 'range': '172.217.0... | NaN | NaN | NaN |
1 | 1 | 40.85.232.64 | Public | NaN | arin | 8075 | 40.80.0.0/12 | US | 2015-02-23 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 40.85.232.64 | [{'cidr': '40.80.0.0/12, 40.124.0.0/16, 40.74.0.0/15, 40.76.0.0/14, 40.120.0.0/14, 40.125.0.0/17... | NaN | NaN | NaN |
2 | 2 | 20.38.98.100 | Public | NaN | arin | 8075 | 20.36.0.0/14 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.38.98.100 | [{'cidr': '20.128.0.0/16, 20.33.0.0/16, 20.34.0.0/15, 20.36.0.0/14, 20.64.0.0/10, 20.40.0.0/13, ... | NaN | NaN | NaN |
3 | 3 | 23.96.64.84 | Public | NaN | arin | 8075 | 23.96.0.0/14 | US | 2013-06-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 23.96.64.84 | [{'cidr': '23.96.0.0/13', 'name': 'MSFT', 'handle': 'NET-23-96-0-0-1', 'range': '23.96.0.0 - 23.... | NaN | NaN | NaN |
4 | 4 | 65.55.44.108 | Public | NaN | arin | 8075 | 65.52.0.0/14 | US | 2001-02-14 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 65.55.44.108 | [{'cidr': '65.52.0.0/14', 'name': 'MICROSOFT-1BLK', 'handle': 'NET-65-52-0-0-1', 'range': '65.52... | NaN | NaN | NaN |
5 | 5 | 131.107.147.209 | Public | NaN | arin | 3598 | 131.107.0.0/16 | US | 1988-11-11 | MICROSOFT-CORP-AS, US | 131.107.147.209 | [{'cidr': '131.107.0.0/16', 'name': 'MICROSOFT', 'handle': 'NET-131-107-0-0-1', 'range': '131.10... | NaN | NaN | NaN |
6 | 8 | 13.82.152.48 | Public | NaN | arin | 8075 | 13.64.0.0/11 | US | 2015-03-26 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 13.82.152.48 | [{'cidr': '13.64.0.0/11, 13.96.0.0/13, 13.104.0.0/14', 'name': 'MSFT', 'handle': 'NET-13-64-0-0-... | NaN | NaN | NaN |
Pivot pipelines are implemented pandas customr accessors. Read more about Extending pandas here
When you load Pivot it adds the mp_pivot
accessor. This
appears as an attribute to DataFrames.
>>> ips_df.mp_pivot
<msticpy.datamodel.pivot_pd_accessor.PivotAccessor at 0x275754e2208>
The main pipelining function run
is a method of mp_pivot
.
run
requires two parameters - the pivot function to run and
the column to use as input. See mp_pivot.run documentation
Here is an example of using it to call 4 pivot functions, each
using the output of the previous function as input and using
the join
parameter to accumulate the results from each
stage.
Let's step through it line by line.
ips_df
- this is just the starting DataFrame, our input data.mp_pivot.run()
accessor method on this dataframe.
We pass it the pivot function that we want to run and the input column name.
This column name is the column in ips_df where our input IP addresses are.
We've also specified an join
type of inner. In this case the join type doesn't
really matter since we know we get exactly one output row for every input row.query
function to filter out unwanted entries
from the previous stage. In this case we only want Public IP addresses.
This illustrates that you can intersperse standard pandas functions
in the same pipeline. We could have also added a column selector expression
([["col1", "col2"...]]) if we wanted to filter the columns passed to the
next stagewhois
. Remember the "column" parameter
always refers to the input column, i.e. the column from previous stage
that we want to use in this stage.geoloc_mm
to get geo location details joining with a left
join - this preserves the input data rows and adds null columns in any cases
where the pivot function returned no result..head(5)
shown here).ip_list = [
"192.168.40.32",
"192.168.1.216",
"192.168.153.17",
"3.88.48.125",
"10.200.104.20",
"192.168.90.101",
"192.168.150.50",
"172.16.100.31",
"192.168.30.189",
"10.100.199.10",
]
ips_df = pd.DataFrame(ip_list, columns=["IP"])
(
ips_df
.mp_pivot.run(entities.IpAddress.util.ip_type, column="IP", join="inner")
.query("result == 'Public'").head(10)
.mp_pivot.run(entities.IpAddress.util.whois, column="ip", join="left")
.mp_pivot.run(entities.IpAddress.util.geoloc_mm, column="ip", join="left")
.mp_pivot.run(entities.IpAddress.AzureSentinel.SecurityAlert_list_alerts_for_ip, source_ip_list="ip", join="left")
).head(5)
IP | ip | result | asn | asn_cidr | asn_country_code | asn_date | asn_description | asn_registry | nets | nir | query | raw | raw_referral | referral | CountryCode | CountryName | State | City | Longitude | Latitude | Asn | edges | Type_x | AdditionalData | ... | AlertType | ConfidenceLevel | ConfidenceScore | IsIncident | StartTimeUtc | EndTimeUtc | ProcessingEndTime | RemediationSteps | ExtendedProperties | Entities | SourceSystem | WorkspaceSubscriptionId | WorkspaceResourceGroup | ExtendedLinks | ProductName | ProductComponentName | AlertLink | Status | CompromisedEntity | Tactics | Type_y | SystemAlertId1 | ExtendedProperties1 | Entities1 | MatchingIps | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3.88.48.125 | 3.88.48.125 | Public | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | arin | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | 3.88.48.125 | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 8ecf8077-cf51-4820-aadd-14040956f35d_8a369bd2-97b6-4fe2-922a-cd170faf25bc | NaN | False | 2020-12-19 13:04:59+00:00 | 2020-12-19 19:04:59+00:00 | 2020-12-19 19:10:17+00:00 | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n }\r\n] | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Scheduled Alerts | New | CommandAndControl | SecurityAlert | fdc54c12-efba-38b0-8379-f06d7fbfd34a | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n }\r\n] | [3.88.48.125] | |||||
1 | 3.88.48.125 | 3.88.48.125 | Public | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | arin | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | 3.88.48.125 | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:15+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 625ff9af-dddc-0cf8-9d4b-e79067fa2e71 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | |||
2 | 3.88.48.125 | 3.88.48.125 | Public | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | arin | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | 3.88.48.125 | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:15+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | c977f904-ab30-d57e-986f-9d6ebf72771b | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | |||
3 | 3.88.48.125 | 3.88.48.125 | Public | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | arin | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | 3.88.48.125 | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:15+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 9ee547e4-cba1-47d1-e1f9-87247b693a52 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | |||
4 | 3.88.48.125 | 3.88.48.125 | Public | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | arin | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | 3.88.48.125 | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:16+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 83a0e08a-1adb-ef75-1c56-f6c9ce25ca69 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] |
5 rows × 63 columns
In addition to run
, the mp_pivot
accessor also
has the following functions:
display
- this simply displays the data at the point called in
the pipeline. You can add an optional title, filtering and the number
or rows to displaytee
- this forks a copy of the dataframe at the point it is
called in the pipeline. It will assign the forked copy to the name
given in the var_name
parameter. If there is an existing variable of
the same name it will not overwrite it unless you add the clobber=True
parameter.In both cases the pipelined data is passed through unchanged. See Pivot functions help for more details.
Use of these is shown below
...
.mp_pivot.run(entities.IpAddress.util.geoloc_mm, column="ip", join="left")
.mp_pivot.display(title="Geo Lookup", cols=["IP", "City"]) # << display an intermediate result
.mp_pivot.tee(var_name="geoip_df", clobber=True) # << save a copy called 'geoip_df'
.mp_pivot.run(entities.IpAddress.AzureSentinel.SecurityAlert_list_alerts_for_ip, source_ip_list="ip", join="left")
In the next release we've also implemented:
tee_exec
- this executes a function on a forked copy of the DataFrame
The function must be a pandas function or custom accessor. A
good example of the use of this might be creating a plot or summary
table to display partway through the pipeline.You can add pivot functions of your own. You need to supply:
Full details of this are described here.
The published version of Pivot doesn't let you add functions defined inline (i.e. in the notebook itself) but this will be possible in the next release.
Assume that we've created this function in a Python module my_module.py
%%writefile my_module.py
"""U-case and hash"""
from hashlib import md5
def my_func(input: str):
md5_hash = "-".join(hex(b)[2:] for b in md5("hello".encode("utf-8")).digest())
return {
"Title": input.upper(),
"Hash": md5_hash
}
Writing my_module.py
Create a definition file
%%writefile my_func.yml
pivot_providers:
my_func_defn:
src_func_name: my_func
src_module: my_module
entity_container_name: cyber
input_type: value
entity_map:
Host: HostName
func_input_value_arg: input
func_new_name: upper_hash_name
Writing my_func.yml
from msticpy.datamodel.pivot_register_reader import register_pivots
register_pivots("my_func.yml")
Host.cyber.upper_hash_name("host_name")
Title | Hash | input | |
---|---|---|---|
0 | HOST_NAME | 5d-41-40-2a-bc-4b-2a-76-b9-71-9d-91-10-17-c5-92 | host_name |
In the next release, this will be available as a simple function that can be used to add a function defined in the notebook.
Warning: post-0.9.0 functionality
This will throw and error in v0.9.0 of MSTICPy
from hashlib import md5
def my_func2(input: str):
md5_hash = "-".join(hex(b)[2:] for b in md5("hello".encode("utf-8")).digest())
return {
"Title": input.upper(),
"Hash": md5_hash
}
Pivot.add_pivot_function(
func=my_func2,
container="cyber", # which container it will appear in on the entity
input_type="value",
entity_map={"Host": "HostName"},
func_input_value_arg="input",
func_new_name="il_upper_hash_name",
)
Host.cyber.il_upper_hash_name("host_name")
Title | Hash | input | |
---|---|---|---|
0 | HOST_NAME | 5d-41-40-2a-bc-4b-2a-76-b9-71-9d-91-10-17-c5-92 | host_name |
We've taken a short tour through the MSTICPy looking at how they make the functionality in the package easier to discover and use. I'm particularly excited about the pipeline functionality. In the next release we're going to make it possible to define reusable pipelines in configuration files and execute them with a single function call. This should help streamline some common patterns in notebooks for Cyber hunting and investigation.
Please send any feedback or suggestions for improvements to msticpy@microsoft.com or create an issue on https://github.com/microsoft/msticpy.
Happy hunting!
query = """
SecurityAlert
| where AlertName == "Time series anomaly detection for total volume of traffic"
| project AlertName, Description, Entities
| extend Entities = todynamic(Entities)
| mvexpand with_itemindex=Index Entities
| extend IP = Entities["Address"]
"""
ips = az_provider.exec_query(query)
ips_df = ips[["IP"]].drop_duplicates()
entities.IpAddress.util.ip_type(data=ips_df, column="IP", join="inner")
IP | ip | result | |
---|---|---|---|
0 | 192.168.40.32 | 192.168.40.32 | Private |
1 | 192.168.1.216 | 192.168.1.216 | Private |
2 | 192.168.153.17 | 192.168.153.17 | Private |
3 | 3.88.48.125 | 3.88.48.125 | Public |
4 | 10.200.104.20 | 10.200.104.20 | Private |
5 | 192.168.90.101 | 192.168.90.101 | Private |
6 | 192.168.150.50 | 192.168.150.50 | Private |
7 | 172.16.100.31 | 172.16.100.31 | Private |
8 | 192.168.30.189 | 192.168.30.189 | Private |
9 | 10.100.199.10 | 10.100.199.10 | Private |
10 | 52.171.57.74 | 52.171.57.74 | Public |
11 | 52.171.36.115 | 52.171.36.115 | Public |
12 | 20.84.105.0 | 20.84.105.0 | Public |
13 | 20.55.97.123 | 20.55.97.123 | Public |
14 | 20.84.112.117 | 20.84.112.117 | Public |
15 | 192.168.99.137 | 192.168.99.137 | Private |
16 | 192.168.55.10 | 192.168.55.10 | Private |
17 | 192.168.51.6 | 192.168.51.6 | Private |
18 | 104.214.50.229 | 104.214.50.229 | Public |
19 | 20.51.104.164 | 20.51.104.164 | Public |
20 | 20.81.40.144 | 20.81.40.144 | Public |
21 | 20.80.162.44 | 20.80.162.44 | Public |
22 | 172.31.0.0 | 172.31.0.0 | Private |
23 | 104.215.76.44 | 104.215.76.44 | Public |
24 | 172.31.0.1 | 172.31.0.1 | Private |
25 | 20.81.42.55 | 20.81.42.55 | Public |
26 | 20.55.80.232 | 20.55.80.232 | Public |
27 | 172.16.199.104 | 172.16.199.104 | Private |
28 | 79.124.62.82 | 79.124.62.82 | Public |
entities.IpAddress.util.ip_type
entities.IpAddress.util.whois
entities.IpAddress.util.geoloc_mm
entities.IpAddress.AzureSentinel.SecurityAlert_list_related_alerts
df = entities.IpAddress.util.ip_type(data=ips, column="IP", join="inner")
df2 = entities.IpAddress.util.whois(data=df, column="IP", join="inner")
df3 = entities.IpAddress.util.geoloc_mm(data=df2, column="IP", join="inner")
df3 = entities.IpAddress.AzureSentinel.SecurityAlert_list_related_alerts(data=df3, column="IP", join="inner")
ips_df.mp_pivot
<msticpy.datamodel.pivot_pd_accessor.PivotAccessor at 0x275754e2208>
(
ips_df
.mp_pivot.run(entities.IpAddress.util.ip_type, column="IP", join="inner")
.query("result == 'Public'").head(10)
.mp_pivot.run(entities.IpAddress.util.whois, column="ip", join="left")
.mp_pivot.run(entities.IpAddress.util.geoloc_mm, column="ip", join="left")
.mp_pivot.run(entities.IpAddress.AzureSentinel.SecurityAlert_list_alerts_for_ip, source_ip_list="ip")
).head(5)
TenantId | TimeGenerated | AlertDisplayName | AlertName | Severity | Description | ProviderName | VendorName | VendorOriginalId | SystemAlertId | ResourceId | SourceComputerId | AlertType | ConfidenceLevel | ConfidenceScore | IsIncident | StartTimeUtc | EndTimeUtc | ProcessingEndTime | RemediationSteps | ExtendedProperties | Entities | SourceSystem | WorkspaceSubscriptionId | WorkspaceResourceGroup | ExtendedLinks | ProductName | ProductComponentName | AlertLink | Status | CompromisedEntity | Tactics | Type | SystemAlertId1 | ExtendedProperties1 | Entities1 | MatchingIps | src_row_index | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-23 14:08:12+00:00 | Microsoft Threat Intelligence Analytics | Microsoft Threat Intelligence Analytics | Medium | Microsoft threat intelligence analytic has detected Blocked communication to a known WatchList d... | Threat Intelligence Alerts | Microsoft | 91d806d3-6b6f-4e5c-a78f-e674d602be51 | 625ff9af-dddc-0cf8-9d4b-e79067fa2e71 | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:15+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 625ff9af-dddc-0cf8-9d4b-e79067fa2e71 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | 0 | |||||
1 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-23 14:08:12+00:00 | Microsoft Threat Intelligence Analytics | Microsoft Threat Intelligence Analytics | Medium | Microsoft threat intelligence analytic has detected Blocked communication to a known WatchList d... | Threat Intelligence Alerts | Microsoft | 173063c4-10dd-4dd2-9e4f-ec5ed596ec54 | c977f904-ab30-d57e-986f-9d6ebf72771b | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:15+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | c977f904-ab30-d57e-986f-9d6ebf72771b | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | 0 | |||||
2 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-23 14:08:12+00:00 | Microsoft Threat Intelligence Analytics | Microsoft Threat Intelligence Analytics | Medium | Microsoft threat intelligence analytic has detected Blocked communication to a known WatchList d... | Threat Intelligence Alerts | Microsoft | 58b2cda2-11c6-42b8-b6f1-72751cad8f38 | 9ee547e4-cba1-47d1-e1f9-87247b693a52 | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:15+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 9ee547e4-cba1-47d1-e1f9-87247b693a52 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | 0 | |||||
3 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-23 14:08:12+00:00 | Microsoft Threat Intelligence Analytics | Microsoft Threat Intelligence Analytics | Medium | Microsoft threat intelligence analytic has detected Blocked communication to a known WatchList d... | Threat Intelligence Alerts | Microsoft | e945f91e-5726-4581-8564-4c04e5414a58 | 83a0e08a-1adb-ef75-1c56-f6c9ce25ca69 | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:16+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 83a0e08a-1adb-ef75-1c56-f6c9ce25ca69 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | 0 | |||||
4 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-23 13:53:46+00:00 | Microsoft Threat Intelligence Analytics | Microsoft Threat Intelligence Analytics | Medium | Microsoft threat intelligence analytic has detected Blocked communication to a known WatchList d... | Threat Intelligence Alerts | Microsoft | a95aaf62-9628-418b-8f5f-0f1f26dcdc13 | fde729f6-674b-997a-17eb-e4e7d2b3690d | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:53:47+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | fde729f6-674b-997a-17eb-e4e7d2b3690d | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | 0 |
ips_df
IP | |
---|---|
0 | 192.168.40.32 |
1 | 192.168.1.216 |
2 | 192.168.153.17 |
3 | 3.88.48.125 |
4 | 10.200.104.20 |
17 | 192.168.90.101 |
68 | 192.168.150.50 |
69 | 172.16.100.31 |
70 | 192.168.30.189 |
105 | 10.100.199.10 |
272 | 52.171.57.74 |
273 | 52.171.36.115 |
275 | 20.84.105.0 |
276 | 20.55.97.123 |
392 | 20.84.112.117 |
397 | 192.168.99.137 |
410 | 192.168.55.10 |
720 | 192.168.51.6 |
923 | 104.214.50.229 |
924 | 20.51.104.164 |
925 | 20.81.40.144 |
926 | 20.80.162.44 |
927 | 172.31.0.0 |
928 | 104.215.76.44 |
1017 | 172.31.0.1 |
1923 | 20.81.42.55 |
3290 | 20.55.80.232 |
4381 | 172.16.199.104 |
5542 | 79.124.62.82 |
entities.IpAddress.util.whois(data=ips_df, column="IP")
nir | asn_registry | asn | asn_cidr | asn_country_code | asn_date | asn_description | query | nets | raw | referral | raw_referral | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
3 | NaN | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | NaN | NaN | NaN |
4 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
17 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
68 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
69 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
70 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
105 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
272 | NaN | arin | 8075 | 52.160.0.0/11 | US | 2015-11-24 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 52.171.57.74 | [{'cidr': '52.160.0.0/11, 52.148.0.0/14, 52.152.0.0/13, 52.145.0.0/16, 52.146.0.0/15', 'name': '... | NaN | NaN | NaN |
273 | NaN | arin | 8075 | 52.160.0.0/11 | US | 2015-11-24 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 52.171.36.115 | [{'cidr': '52.145.0.0/16, 52.146.0.0/15, 52.152.0.0/13, 52.160.0.0/11, 52.148.0.0/14', 'name': '... | NaN | NaN | NaN |
275 | NaN | arin | 8075 | 20.64.0.0/10 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.84.105.0 | [{'cidr': '20.128.0.0/16, 20.64.0.0/10, 20.40.0.0/13, 20.36.0.0/14, 20.48.0.0/12, 20.34.0.0/15, ... | NaN | NaN | NaN |
276 | NaN | arin | 8075 | 20.48.0.0/12 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.55.97.123 | [{'cidr': '20.128.0.0/16, 20.64.0.0/10, 20.40.0.0/13, 20.36.0.0/14, 20.48.0.0/12, 20.34.0.0/15, ... | NaN | NaN | NaN |
392 | NaN | arin | 8075 | 20.64.0.0/10 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.84.112.117 | [{'cidr': '20.128.0.0/16, 20.64.0.0/10, 20.40.0.0/13, 20.36.0.0/14, 20.48.0.0/12, 20.34.0.0/15, ... | NaN | NaN | NaN |
397 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
410 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
720 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
923 | NaN | arin | 8075 | 104.208.0.0/13 | US | 2014-10-01 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 104.214.50.229 | [{'cidr': '104.208.0.0/13', 'name': 'MSFT', 'handle': 'NET-104-208-0-0-1', 'range': '104.208.0.0... | NaN | NaN | NaN |
924 | NaN | arin | 8075 | 20.48.0.0/12 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.51.104.164 | [{'cidr': '20.34.0.0/15, 20.48.0.0/12, 20.64.0.0/10, 20.33.0.0/16, 20.40.0.0/13, 20.36.0.0/14, 2... | NaN | NaN | NaN |
925 | NaN | arin | 8075 | 20.64.0.0/10 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.81.40.144 | [{'cidr': '20.128.0.0/16, 20.33.0.0/16, 20.48.0.0/12, 20.34.0.0/15, 20.64.0.0/10, 20.36.0.0/14, ... | NaN | NaN | NaN |
926 | NaN | arin | 8075 | 20.64.0.0/10 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.80.162.44 | [{'cidr': '20.128.0.0/16, 20.33.0.0/16, 20.48.0.0/12, 20.34.0.0/15, 20.64.0.0/10, 20.36.0.0/14, ... | NaN | NaN | NaN |
927 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
928 | NaN | arin | 8075 | 104.208.0.0/13 | US | 2014-10-01 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 104.215.76.44 | [{'cidr': '104.208.0.0/13', 'name': 'MSFT', 'handle': 'NET-104-208-0-0-1', 'range': '104.208.0.0... | NaN | NaN | NaN |
1017 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1923 | NaN | arin | 8075 | 20.64.0.0/10 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.81.42.55 | [{'cidr': '20.34.0.0/15, 20.36.0.0/14, 20.48.0.0/12, 20.64.0.0/10, 20.128.0.0/16, 20.33.0.0/16, ... | NaN | NaN | NaN |
3290 | NaN | arin | 8075 | 20.48.0.0/12 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.55.80.232 | [{'cidr': '20.34.0.0/15, 20.36.0.0/14, 20.48.0.0/12, 20.64.0.0/10, 20.128.0.0/16, 20.33.0.0/16, ... | NaN | NaN | NaN |
4381 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
5542 | NaN | ripencc | 207812 | 79.124.62.0/24 | BG | 2007-07-31 | DM_AUTO, BG | 79.124.62.82 | [{'cidr': '79.124.62.0/24', 'name': 'CLOUDVPS-NET', 'handle': 'NOC299-RIPE', 'range': '79.124.62... | NaN | NaN | NaN |
Note:
mp_pivot.display
function to display intermediate results(
ips_df
.mp_pivot.run(entities.IpAddress.util.ip_type, column="IP", join="inner")
.query("result == 'Public'").head(10)
.mp_pivot.run(entities.IpAddress.util.whois, column="ip", join="left")
.mp_pivot.run(entities.IpAddress.util.geoloc_mm, column="ip", join="left")
.mp_pivot.display(title="Geo Lookup", cols=["IP", "City"]) # << display an intermediate result
.mp_pivot.run(entities.IpAddress.AzureSentinel.SecurityAlert_list_alerts_for_ip, source_ip_list="ip", join="left")
).head(5)
IP | City | |
---|---|---|
0 | 3.88.48.125 | Ashburn |
1 | 52.171.57.74 | San Antonio |
2 | 52.171.36.115 | San Antonio |
3 | 20.84.105.0 | None |
4 | 20.55.97.123 | Washington |
5 | 20.84.112.117 | None |
6 | 104.214.50.229 | San Antonio |
7 | 20.51.104.164 | None |
8 | 20.81.40.144 | Washington |
9 | 20.80.162.44 | None |
IP | ip | result | nir | asn_registry | asn | asn_cidr | asn_country_code | asn_date | asn_description | query | nets | raw | referral | raw_referral | CountryCode | CountryName | State | City | Longitude | Latitude | Asn | edges | Type_x | AdditionalData | ... | ConfidenceLevel | ConfidenceScore | IsIncident | StartTimeUtc | EndTimeUtc | ProcessingEndTime | RemediationSteps | ExtendedProperties | Entities | SourceSystem | WorkspaceSubscriptionId | WorkspaceResourceGroup | ExtendedLinks | ProductName | ProductComponentName | AlertLink | Status | CompromisedEntity | Tactics | Type_y | SystemAlertId1 | ExtendedProperties1 | Entities1 | MatchingIps | src_row_index | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3.88.48.125 | 3.88.48.125 | Public | None | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 83 | NaN | False | 2020-11-20 14:57:45+00:00 | 2020-11-20 14:57:45+00:00 | 2020-11-20 15:08:56+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"bigbonsai-music.de\") | where T... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "bigbonsai-music.de",\r\n "HostName": "bigbon... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | a9954983-cc15-8b65-8e2d-ae268e8c6cb5 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"bigbonsai-music.de\") | where T... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "bigbonsai-music.de",\r\n "HostName": "bigbon... | [3.88.48.125] | 0 | |||
1 | 3.88.48.125 | 3.88.48.125 | Public | None | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 83 | NaN | False | 2020-11-20 14:57:45+00:00 | 2020-11-20 14:57:45+00:00 | 2020-11-20 15:08:57+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"bigbonsai-music.de\") | where T... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "bigbonsai-music.de",\r\n "HostName": "bigbon... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | b241e024-ca33-c706-7475-c7dbecbc41c3 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"bigbonsai-music.de\") | where T... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "bigbonsai-music.de",\r\n "HostName": "bigbon... | [3.88.48.125] | 0 | |||
2 | 3.88.48.125 | 3.88.48.125 | Public | None | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 83 | NaN | False | 2020-11-20 14:57:46+00:00 | 2020-11-20 14:57:46+00:00 | 2020-11-20 15:08:57+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"bigbonsai-music.de\") | where T... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "bigbonsai-music.de",\r\n "HostName": "bigbon... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | f9bf5915-4560-664c-486d-4e60c8cf6641 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"bigbonsai-music.de\") | where T... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "bigbonsai-music.de",\r\n "HostName": "bigbon... | [3.88.48.125] | 0 | |||
3 | 3.88.48.125 | 3.88.48.125 | Public | None | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 83 | NaN | False | 2020-11-20 14:57:45+00:00 | 2020-11-20 14:57:45+00:00 | 2020-11-20 15:08:57+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"bigbonsai-music.de\") | where T... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "bigbonsai-music.de",\r\n "HostName": "bigbon... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 63fb83f4-54a0-ad9a-84cc-4d4403dcf8ec | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"bigbonsai-music.de\") | where T... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "bigbonsai-music.de",\r\n "HostName": "bigbon... | [3.88.48.125] | 0 | |||
4 | 3.88.48.125 | 3.88.48.125 | Public | None | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 83 | NaN | False | 2020-11-20 14:57:45+00:00 | 2020-11-20 14:57:45+00:00 | 2020-11-20 15:08:56+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"bigbonsai-music.de\") | where T... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "bigbonsai-music.de",\r\n "HostName": "bigbon... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | dd08cd9d-2d76-83b6-daae-335dfd1466eb | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"bigbonsai-music.de\") | where T... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "bigbonsai-music.de",\r\n "HostName": "bigbon... | [3.88.48.125] | 0 |
5 rows × 64 columns
ip_test_df = (
ips_df
.mp_pivot.run(entities.IpAddress.util.ip_type, column="IP", join="inner")
.query("result == 'Public'").head(10)
.mp_pivot.run(entities.IpAddress.util.whois, column="ip", join="left")
.mp_pivot.run(entities.IpAddress.util.geoloc_mm, column="ip", join="left")
).head(5)
# %%debug
ip_test_df.mp_pivot.run(entities.IpAddress.AzureSentinel.SecurityAlert_list_alerts_for_ip, source_ip_list="ip", join="left")
IP | ip | result | nir | asn_registry | asn | asn_cidr | asn_country_code | asn_date | asn_description | query | nets | raw | referral | raw_referral | CountryCode | CountryName | State | City | Longitude | Latitude | Asn | edges | Type_x | AdditionalData | ... | ConfidenceLevel | ConfidenceScore | IsIncident | StartTimeUtc | EndTimeUtc | ProcessingEndTime | RemediationSteps | ExtendedProperties | Entities | SourceSystem | WorkspaceSubscriptionId | WorkspaceResourceGroup | ExtendedLinks | ProductName | ProductComponentName | AlertLink | Status | CompromisedEntity | Tactics | Type_y | SystemAlertId1 | ExtendedProperties1 | Entities1 | MatchingIps | src_row_index | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3.88.48.125 | 3.88.48.125 | Public | None | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 83 | NaN | False | 2020-11-20 03:52:17+00:00 | 2020-11-20 03:52:17+00:00 | 2020-11-20 04:06:42+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"chambresdhotesbruges.fr\") | wh... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "chambresdhotesbruges.fr",\r\n "HostName": "c... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 45614988-e680-cbc0-4673-babf03147290 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"chambresdhotesbruges.fr\") | wh... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "chambresdhotesbruges.fr",\r\n "HostName": "c... | [3.88.48.125] | 0 | |||
1 | 3.88.48.125 | 3.88.48.125 | Public | None | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 83 | NaN | False | 2020-11-20 03:52:17+00:00 | 2020-11-20 03:52:17+00:00 | 2020-11-20 04:06:42+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"chambresdhotesbruges.fr\") | wh... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "chambresdhotesbruges.fr",\r\n "HostName": "c... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 2cc59e4f-1cd3-b583-fdc2-96f1837bb0e1 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"chambresdhotesbruges.fr\") | wh... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "chambresdhotesbruges.fr",\r\n "HostName": "c... | [3.88.48.125] | 0 | |||
2 | 3.88.48.125 | 3.88.48.125 | Public | None | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 83 | NaN | False | 2020-11-20 03:52:20+00:00 | 2020-11-20 03:52:20+00:00 | 2020-11-20 04:06:42+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"chambresdhotesbruges.fr\") | wh... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "chambresdhotesbruges.fr",\r\n "HostName": "c... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | ebfe31f1-bc4b-69a1-521a-84b35a681cd1 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"chambresdhotesbruges.fr\") | wh... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "chambresdhotesbruges.fr",\r\n "HostName": "c... | [3.88.48.125] | 0 | |||
3 | 3.88.48.125 | 3.88.48.125 | Public | None | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 83 | NaN | False | 2020-11-20 03:52:17+00:00 | 2020-11-20 03:52:17+00:00 | 2020-11-20 04:06:43+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"chambresdhotesbruges.fr\") | wh... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "chambresdhotesbruges.fr",\r\n "HostName": "c... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 1eb1fd38-431d-a69a-bc81-955b7e675ddf | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"chambresdhotesbruges.fr\") | wh... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "chambresdhotesbruges.fr",\r\n "HostName": "c... | [3.88.48.125] | 0 | |||
4 | 3.88.48.125 | 3.88.48.125 | Public | None | arin | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | 3.88.48.125 | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | None | None | US | United States | Virginia | Ashburn | -77.4728 | 39.0481 | None | {} | geolocation | {} | ... | 83 | NaN | False | 2020-11-20 03:52:17+00:00 | 2020-11-20 03:52:17+00:00 | 2020-11-20 04:06:45+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"chambresdhotesbruges.fr\") | wh... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "chambresdhotesbruges.fr",\r\n "HostName": "c... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | a79e3d8f-ce76-cba5-ea9a-00a89fc4b2a9 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"chambresdhotesbruges.fr\") | wh... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "chambresdhotesbruges.fr",\r\n "HostName": "c... | [3.88.48.125] | 0 | |||
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
1592 | 20.55.97.123 | 20.55.97.123 | Public | None | arin | 8075 | 20.48.0.0/12 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.55.97.123 | [{'cidr': '20.128.0.0/16, 20.64.0.0/10, 20.40.0.0/13, 20.36.0.0/14, 20.48.0.0/12, 20.34.0.0/15, ... | None | None | None | US | United States | Virginia | Washington | -78.1539 | 38.7095 | None | {} | geolocation | {} | ... | NaN | False | 2021-01-30 21:04:21.558000+00:00 | 2021-02-13 21:04:21.558000+00:00 | 2021-02-13 21:09:29.084000+00:00 | {\r\n "Query": "// The query_now parameter represents the time (in UTC) at which the scheduled ... | [\r\n {\r\n "$id": "3",\r\n "Address": "192.168.1.216",\r\n "Type": "ip"\r\n },\r\n ... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Scheduled Alerts | New | Exfiltration | SecurityAlert | b03ba910-9e74-49d3-4454-6338d853400b | {\r\n "Query": "// The query_now parameter represents the time (in UTC) at which the scheduled ... | [\r\n {\r\n "$id": "3",\r\n "Address": "192.168.1.216",\r\n "Type": "ip"\r\n },\r\n ... | [20.55.97.123] | 4 | |||||
1593 | 20.55.97.123 | 20.55.97.123 | Public | None | arin | 8075 | 20.48.0.0/12 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.55.97.123 | [{'cidr': '20.128.0.0/16, 20.64.0.0/10, 20.40.0.0/13, 20.36.0.0/14, 20.48.0.0/12, 20.34.0.0/15, ... | None | None | None | US | United States | Virginia | Washington | -78.1539 | 38.7095 | None | {} | geolocation | {} | ... | NaN | False | 2021-01-30 22:04:21.558000+00:00 | 2021-02-13 22:04:21.558000+00:00 | 2021-02-13 22:09:28.540000+00:00 | {\r\n "Query": "// The query_now parameter represents the time (in UTC) at which the scheduled ... | [\r\n {\r\n "$id": "3",\r\n "Address": "192.168.1.216",\r\n "Type": "ip"\r\n },\r\n ... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Scheduled Alerts | New | Exfiltration | SecurityAlert | 5da44cf1-5f00-b9b0-61eb-d3e5e4051478 | {\r\n "Query": "// The query_now parameter represents the time (in UTC) at which the scheduled ... | [\r\n {\r\n "$id": "3",\r\n "Address": "192.168.1.216",\r\n "Type": "ip"\r\n },\r\n ... | [20.55.97.123] | 4 | |||||
1594 | 20.55.97.123 | 20.55.97.123 | Public | None | arin | 8075 | 20.48.0.0/12 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.55.97.123 | [{'cidr': '20.128.0.0/16, 20.64.0.0/10, 20.40.0.0/13, 20.36.0.0/14, 20.48.0.0/12, 20.34.0.0/15, ... | None | None | None | US | United States | Virginia | Washington | -78.1539 | 38.7095 | None | {} | geolocation | {} | ... | NaN | False | 2021-01-31 02:04:21.558000+00:00 | 2021-02-14 02:04:21.558000+00:00 | 2021-02-14 02:09:28.799000+00:00 | {\r\n "Query": "// The query_now parameter represents the time (in UTC) at which the scheduled ... | [\r\n {\r\n "$id": "3",\r\n "Address": "192.168.1.216",\r\n "Type": "ip"\r\n },\r\n ... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Scheduled Alerts | New | Exfiltration | SecurityAlert | 0f0aa0e7-f56a-7f90-c042-a082e33c7bc6 | {\r\n "Query": "// The query_now parameter represents the time (in UTC) at which the scheduled ... | [\r\n {\r\n "$id": "3",\r\n "Address": "192.168.1.216",\r\n "Type": "ip"\r\n },\r\n ... | [20.55.97.123] | 4 | |||||
1595 | 20.55.97.123 | 20.55.97.123 | Public | None | arin | 8075 | 20.48.0.0/12 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.55.97.123 | [{'cidr': '20.128.0.0/16, 20.64.0.0/10, 20.40.0.0/13, 20.36.0.0/14, 20.48.0.0/12, 20.34.0.0/15, ... | None | None | None | US | United States | Virginia | Washington | -78.1539 | 38.7095 | None | {} | geolocation | {} | ... | NaN | False | 2021-01-31 04:04:21.558000+00:00 | 2021-02-14 04:04:21.558000+00:00 | 2021-02-14 04:09:28.953000+00:00 | {\r\n "Query": "// The query_now parameter represents the time (in UTC) at which the scheduled ... | [\r\n {\r\n "$id": "3",\r\n "Address": "192.168.1.216",\r\n "Type": "ip"\r\n },\r\n ... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Scheduled Alerts | New | Exfiltration | SecurityAlert | 44df015d-0414-88db-e149-18c9c6f37764 | {\r\n "Query": "// The query_now parameter represents the time (in UTC) at which the scheduled ... | [\r\n {\r\n "$id": "3",\r\n "Address": "192.168.1.216",\r\n "Type": "ip"\r\n },\r\n ... | [20.55.97.123] | 4 | |||||
1596 | 20.55.97.123 | 20.55.97.123 | Public | None | arin | 8075 | 20.48.0.0/12 | US | 2017-10-18 | MICROSOFT-CORP-MSN-AS-BLOCK, US | 20.55.97.123 | [{'cidr': '20.128.0.0/16, 20.64.0.0/10, 20.40.0.0/13, 20.36.0.0/14, 20.48.0.0/12, 20.34.0.0/15, ... | None | None | None | US | United States | Virginia | Washington | -78.1539 | 38.7095 | None | {} | geolocation | {} | ... | NaN | False | 2021-02-09 17:25:20+00:00 | 2021-02-10 01:04:24+00:00 | 2021-02-10 01:09:28+00:00 | {\r\n "Query": "// The query_now parameter represents the time (in UTC) at which the scheduled ... | [\r\n {\r\n "$id": "3",\r\n "Url": "https://bit.ly/3htG84T",\r\n "Type": "url"\r\n },... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Scheduled Alerts | New | Unknown | SecurityAlert | 9efcecb6-1a26-eb48-81ed-f6268080ac60 | {\r\n "Query": "// The query_now parameter represents the time (in UTC) at which the scheduled ... | [\r\n {\r\n "$id": "3",\r\n "Url": "https://bit.ly/3htG84T",\r\n "Type": "url"\r\n },... | [20.55.97.123] | 4 |
1597 rows × 64 columns
tee
function¶Save intermediate results to a DataFrame
(
ips_df
.mp_pivot.run(entities.IpAddress.util.ip_type, column="IP", join="inner")
.query("result == 'Public'").head(10)
.mp_pivot.run(entities.IpAddress.util.whois, column="ip", join="left")
.mp_pivot.tee(var_name="whois_df", clobber=True)
.mp_pivot.run(entities.IpAddress.util.geoloc_mm, column="ip", join="left")
.mp_pivot.display(title="Geo Lookup", cols=["IP", "City"]) # << display an intermediate result
.mp_pivot.run(entities.IpAddress.AzureSentinel.SecurityAlert_list_alerts_for_ip, source_ip_list="ip")
).head(5)
IP | City | |
---|---|---|
0 | 3.88.48.125 | Ashburn |
TenantId | TimeGenerated | AlertDisplayName | AlertName | Severity | Description | ProviderName | VendorName | VendorOriginalId | SystemAlertId | ResourceId | SourceComputerId | AlertType | ConfidenceLevel | ConfidenceScore | IsIncident | StartTimeUtc | EndTimeUtc | ProcessingEndTime | RemediationSteps | ExtendedProperties | Entities | SourceSystem | WorkspaceSubscriptionId | WorkspaceResourceGroup | ExtendedLinks | ProductName | ProductComponentName | AlertLink | Status | CompromisedEntity | Tactics | Type | SystemAlertId1 | ExtendedProperties1 | Entities1 | MatchingIps | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-23 14:08:12+00:00 | Microsoft Threat Intelligence Analytics | Microsoft Threat Intelligence Analytics | Medium | Microsoft threat intelligence analytic has detected Blocked communication to a known WatchList d... | Threat Intelligence Alerts | Microsoft | 91d806d3-6b6f-4e5c-a78f-e674d602be51 | 625ff9af-dddc-0cf8-9d4b-e79067fa2e71 | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:15+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 625ff9af-dddc-0cf8-9d4b-e79067fa2e71 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | |||||
1 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-23 14:08:12+00:00 | Microsoft Threat Intelligence Analytics | Microsoft Threat Intelligence Analytics | Medium | Microsoft threat intelligence analytic has detected Blocked communication to a known WatchList d... | Threat Intelligence Alerts | Microsoft | 173063c4-10dd-4dd2-9e4f-ec5ed596ec54 | c977f904-ab30-d57e-986f-9d6ebf72771b | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:15+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | c977f904-ab30-d57e-986f-9d6ebf72771b | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | |||||
2 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-23 14:08:12+00:00 | Microsoft Threat Intelligence Analytics | Microsoft Threat Intelligence Analytics | Medium | Microsoft threat intelligence analytic has detected Blocked communication to a known WatchList d... | Threat Intelligence Alerts | Microsoft | 58b2cda2-11c6-42b8-b6f1-72751cad8f38 | 9ee547e4-cba1-47d1-e1f9-87247b693a52 | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:15+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 9ee547e4-cba1-47d1-e1f9-87247b693a52 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | |||||
3 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-23 14:08:12+00:00 | Microsoft Threat Intelligence Analytics | Microsoft Threat Intelligence Analytics | Medium | Microsoft threat intelligence analytic has detected Blocked communication to a known WatchList d... | Threat Intelligence Alerts | Microsoft | e945f91e-5726-4581-8564-4c04e5414a58 | 83a0e08a-1adb-ef75-1c56-f6c9ce25ca69 | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 14:08:16+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | 83a0e08a-1adb-ef75-1c56-f6c9ce25ca69 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] | |||||
4 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-23 13:53:46+00:00 | Microsoft Threat Intelligence Analytics | Microsoft Threat Intelligence Analytics | Medium | Microsoft threat intelligence analytic has detected Blocked communication to a known WatchList d... | Threat Intelligence Alerts | Microsoft | a95aaf62-9628-418b-8f5f-0f1f26dcdc13 | fde729f6-674b-997a-17eb-e4e7d2b3690d | ThreatIntelligence | 83 | NaN | False | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:48:23+00:00 | 2020-12-23 13:53:47+00:00 | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Microsoft Threat Intelligence Analytics | New | 3.88.48.125 | Unknown | SecurityAlert | fde729f6-674b-997a-17eb-e4e7d2b3690d | {\r\n "Query": "CommonSecurityLog| where RequestURL hasprefix(\"www.arboretum.hu\") | where Tim... | [\r\n {\r\n "$id": "3",\r\n "DnsDomain": "www.arboretum.hu",\r\n "HostName": "www.arbo... | [3.88.48.125] |
(
ips_df
.mp_pivot.run(entities.IpAddress.util.ip_type, column="IP", join="inner")
.query("result == 'Public'").head(5)
.mp_pivot.run(entities.IpAddress.util.whois, column="ip", join="left")
.mp_pivot.run(entities.IpAddress.util.geoloc_mm, column="ip", join="left")
.mp_pivot.display(title="Geo Lookup", cols=["IP", "City"]) # << display an intermediate result
.mp_pivot.run(entities.IpAddress.AzureSentinel.SecurityAlert_list_alerts_for_ip, source_ip_list="ip")
.mp_pivot.display(title="Alerts Sample", head=5)
.mp_timeline.plot(
title="IPs with alerts",
source_columns=["AlertName", "MatchingIps"],
)
);
IP | City | |
---|---|---|
0 | 3.88.48.125 | Ashburn |
TenantId | TimeGenerated | AlertDisplayName | AlertName | Severity | Description | ProviderName | VendorName | VendorOriginalId | SystemAlertId | ResourceId | SourceComputerId | AlertType | ConfidenceLevel | ConfidenceScore | IsIncident | StartTimeUtc | EndTimeUtc | ProcessingEndTime | RemediationSteps | ExtendedProperties | Entities | SourceSystem | WorkspaceSubscriptionId | WorkspaceResourceGroup | ExtendedLinks | ProductName | ProductComponentName | AlertLink | Status | CompromisedEntity | Tactics | Type | SystemAlertId1 | ExtendedProperties1 | Entities1 | MatchingIps | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2020-12-19 19:10:17+00:00 | Possible contact with a domain generated by a DGA | Possible contact with a domain generated by a DGA | Medium | Identifies contacts with domains names in CommonSecurityLog that might have been generated by a ... | ASI Scheduled Alerts | Microsoft | 2e06b22f-2022-4cc5-8db4-da726aaca8c7 | fdc54c12-efba-38b0-8379-f06d7fbfd34a | 8ecf8077-cf51-4820-aadd-14040956f35d_8a369bd2-97b6-4fe2-922a-cd170faf25bc | NaN | False | 2020-12-19 13:04:59+00:00 | 2020-12-19 19:04:59+00:00 | 2020-12-19 19:10:17+00:00 | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n }\r\n] | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Scheduled Alerts | New | CommandAndControl | SecurityAlert | fdc54c12-efba-38b0-8379-f06d7fbfd34a | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n }\r\n] | [3.88.48.125] | |||||||
1 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2021-01-15 09:32:56+00:00 | Time series anomaly detection for total volume of traffic | Time series anomaly detection for total volume of traffic | Medium | Identifies anamalous spikes in network traffic logs as compared to baseline or normal historical... | ASI Scheduled Alerts | Microsoft | 61c7e4cb-8a09-4b14-8876-ed01ba79cf97 | 06c1a670-447a-5032-87d9-dadcc38c7f54 | 8ecf8077-cf51-4820-aadd-14040956f35d_ab8f7be2-4ada-4f9f-b8b7-5596cc80068d | NaN | False | 2021-01-01 09:27:50+00:00 | 2021-01-15 09:27:50+00:00 | 2021-01-15 09:32:56+00:00 | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n },\r\n {\... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | SOC | Azure Sentinel | Scheduled Alerts | New | Exfiltration | SecurityAlert | 06c1a670-447a-5032-87d9-dadcc38c7f54 | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n },\r\n {\... | [3.88.48.125] | |||||||
2 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2021-01-15 10:32:56+00:00 | Time series anomaly detection for total volume of traffic | Time series anomaly detection for total volume of traffic | Medium | Identifies anamalous spikes in network traffic logs as compared to baseline or normal historical... | ASI Scheduled Alerts | Microsoft | b3f1d5f8-a6b2-46e3-a479-3748d1dfb3f9 | 8855a515-5f75-1917-e001-ab7c56fbe7b1 | 8ecf8077-cf51-4820-aadd-14040956f35d_ab8f7be2-4ada-4f9f-b8b7-5596cc80068d | NaN | False | 2021-01-01 10:27:50+00:00 | 2021-01-15 10:27:50+00:00 | 2021-01-15 10:32:56+00:00 | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n },\r\n {\... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | SOC | Azure Sentinel | Scheduled Alerts | New | Exfiltration | SecurityAlert | 8855a515-5f75-1917-e001-ab7c56fbe7b1 | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n },\r\n {\... | [3.88.48.125] | |||||||
3 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2021-01-15 11:09:27+00:00 | Time series anomaly detection for total volume of traffic | Time series anomaly detection for total volume of traffic | Medium | Identifies anamalous spikes in network traffic logs as compared to baseline or normal historical... | ASI Scheduled Alerts | Microsoft | 60c18b16-17e4-48a2-b79f-6146c0412eb4 | 4acbd9b6-77b9-6918-bae4-52dcc703e646 | 8ecf8077-cf51-4820-aadd-14040956f35d_cfb8a41c-dfb8-43e8-978e-3bec44cb62d2 | NaN | False | 2021-01-01 11:04:21+00:00 | 2021-01-15 11:04:21+00:00 | 2021-01-15 11:09:27+00:00 | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n },\r\n {\... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Scheduled Alerts | New | Exfiltration | SecurityAlert | 4acbd9b6-77b9-6918-bae4-52dcc703e646 | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n },\r\n {\... | [3.88.48.125] | |||||||
4 | 8ecf8077-cf51-4820-aadd-14040956f35d | 2021-01-15 09:09:27+00:00 | Time series anomaly detection for total volume of traffic | Time series anomaly detection for total volume of traffic | Medium | Identifies anamalous spikes in network traffic logs as compared to baseline or normal historical... | ASI Scheduled Alerts | Microsoft | 9f91a845-194f-4baf-a479-6d806dd314a8 | 63d01128-c146-3470-c8d3-dc2e1258c6ab | 8ecf8077-cf51-4820-aadd-14040956f35d_cfb8a41c-dfb8-43e8-978e-3bec44cb62d2 | NaN | False | 2021-01-01 09:04:21+00:00 | 2021-01-15 09:04:21+00:00 | 2021-01-15 09:09:27+00:00 | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n },\r\n {\... | Detection | d1d8779d-38d7-4f06-91db-9cbc8de0176f | soc | Azure Sentinel | Scheduled Alerts | New | Exfiltration | SecurityAlert | 63d01128-c146-3470-c8d3-dc2e1258c6ab | {\r\n "Query": "// The query_now parameter (in UTC format) was prepended to the query to reflec... | [\r\n {\r\n "$id": "3",\r\n "Address": "3.88.48.125",\r\n "Type": "ip"\r\n },\r\n {\... | [3.88.48.125] |
You can specify a pipeline using YAML syntax and execute directly with a DataFrame input.
Here is an example pipeline file with two pipelines, each with multiple steps.
pipelines:
pipeline1:
description: Pipeline 1 description
steps:
- name: get_logons
step_type: pivot
function: util.whois
entity: IpAddress
comment: Standard pivot function
params:
column: IpAddress
join: inner
- name: disp_logons
step_type: pivot_display
comment: Pivot display
params:
title: "The title"
cols:
- Computer
- Account
query: Computer.str.startswith('MSTICAlerts')
head: 10
- name: tee_logons
step_type: pivot_tee
comment: Pivot tee
params:
var_name: var_df
clobber: True
- name: tee_logons_disp
step_type: pivot_tee_exec
comment: Pivot tee_exec with mp_timeline.plot
function: mp_timeline.plot
params:
source_columns:
- Computer
- Account
- name: logons_timeline
step_type: pd_accessor
comment: Standard accessor with mp_timeline.plot
function: mp_timeline.plot
params:
source_columns:
- Computer
- Account
pipeline2:
description: Pipeline 2 description
steps:
- name: get_logons
step_type: pivot
function: util.whois
entity: IpAddress
comment: Standard pivot function
params:
column: IpAddress
join: inner
- name: disp_logons
step_type: pivot_display
comment: Pivot display
params:
title: "The title"
cols:
- Computer
- Account
query: Computer.str.startswith('MSTICAlerts')
head: 10
- name: tee_logons
step_type: pivot_tee
comment: Pivot tee
params:
var_name: var_df
clobber: True
from msticpy.datamodel.pivot_pipeline import Pipeline
pipelines_yml = """
pipelines:
pipeline1:
description: Pipeline 1 description
steps:
- name: get_ip_type
step_type: pivot
function: util.ip_type
entity: IpAddress
comment: Get IP Type
params:
column: IP
join: inner
- name: filter_public
step_type: pd_accessor
comment: Filter to only public IPs
function: query
pos_params:
- result == "Public"
- name: whois
step_type: pivot
function: util.whois
entity: IpAddress
comment: Get Whois info
params:
column: IP
join: inner
"""
Qe can store this in a file:
with open("pipelines.yml", "w") as fh:
fh.write(pipelines_yml)
pipelines = list(Pipeline.from_yaml(pipelines_yml))
print(pipelines[0].print_pipeline())
# Pipeline 1 description ( input_df # Get IP Type .mp_pivot.run(IpAddress.util.ip_type, column='IP', join='inner') # Filter to only public IPs .query('result == "Public"') # Get Whois info .mp_pivot.run(IpAddress.util.whois, column='IP', join='inner') )
pipeline1 = pipelines[0]
result_df = pipeline1.run(data=ips_df, verbose=True)
result_df.head(3)
Steps: 0%| | 0/3 [00:00<?, ?it/s]
step = get_ip_type PipelineExecStep(accessor='mp_pivot.run', pos_params=[], params={'func': <function get_ip_type at 0x0000028BAFA17048>, 'column': 'IP', 'join': 'inner'}, text=".mp_pivot.run(IpAddress.util.ip_type, column='IP', join='inner')", comment='Get IP Type') step = filter_public PipelineExecStep(accessor='query', pos_params=['result == "Public"'], params={}, text='.query(\'result == "Public"\')', comment='Filter to only public IPs') step = whois PipelineExecStep(accessor='mp_pivot.run', pos_params=[], params={'func': <function get_whois_df at 0x0000028BAFA89F78>, 'column': 'IP', 'join': 'inner'}, text=".mp_pivot.run(IpAddress.util.whois, column='IP', join='inner')", comment='Get Whois info')
IP | ip | result | asn | asn_cidr | asn_country_code | asn_date | asn_description | asn_registry | nets | nir | query | raw | raw_referral | referral | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3.88.48.125 | 3.88.48.125 | Public | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | arin | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | 3.88.48.125 | None | None | None |
def my_func(input: str):
return {
"title": input.upper(),
"text": "something"
}
Pivot.add_pivot_function(
func=my_func,
container="cyber",
input_type="value",
entity_map={"Host": "HostName"},
func_input_value_arg="input",
func_new_name="upper_name",
)
entities.Host.cyber.upper_name("host_name")
title | text | input | |
---|---|---|---|
0 | HOST_NAME | something | host_name |
(
ips_df
.mp_pivot.run(entities.IpAddress.util.ip_type, column="IP", join="inner")
.query("result == 'Public'").head(2)
.mp_pivot.run(entities.IpAddress.util.whois, column="ip", join="left")
.mp_pivot.run(entities.IpAddress.util.geoloc_mm, column="ip", join="left")
.mp_pivot.display(title="Geo Lookup", cols=["IP", "City"]) # << display an intermediate result
.mp_pivot.run(entities.IpAddress.AzureSentinel.SecurityAlert_list_alerts_for_ip, source_ip_list="ip")
.mp_pivot.display(title="Alerts Sample", head=2)
.mp_pivot.run(entities.Host.cyber.upper_name, column="Severity")
).head(3)
This function extracts individual elements from a list column into separate rows.
In this case the nets
column.
(
ips_df
# Get IP Type
.mp_pivot.run(IpAddress.util.ip_type, column='IP', join='inner')
# Filter to only public IPs
.query(expr='result == "Public"')
# Get Whois info
.mp_pivot.run(IpAddress.util.whois, column='IP', join='inner')
).head(1)
IP | ip | result | asn | asn_cidr | asn_country_code | asn_date | asn_description | asn_registry | nets | nir | query | raw | raw_referral | referral | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3.88.48.125 | 3.88.48.125 | Public | 14618 | 3.80.0.0/12 | US | 2017-12-20 | AMAZON-AES, US | arin | [{'cidr': '3.0.0.0/9', 'name': 'AT-88-Z', 'handle': 'NET-3-0-0-0-1', 'range': '3.0.0.0 - 3.127.2... | None | 3.88.48.125 | None | None | None |
def extract_nets(data, col):
out_series = []
for net in result_df.nets:
for entry in net:
out_series.append(pd.Series(entry))
return pd.DataFrame(out_series)
Pivot.add_pivot_function(
func=extract_nets,
container="whois",
input_type="dataframe",
entity_map={"IpAddress": "Address"},
func_df_param_name="data",
func_df_col_param_name="col",
func_new_name="extract_nets",
)
from msticpy.datamodel.entities import IpAddress
(
ips_df
# Get IP Type
.mp_pivot.run(IpAddress.util.ip_type, column='IP', join='inner')
# Filter to only public IPs
.query(expr='result == "Public"')
# Get Whois info
.mp_pivot.run(IpAddress.util.whois, column='IP', join='inner')
.mp_pivot.run(IpAddress.whois.extract_nets, column='nets')
)
cidr | name | handle | range | description | country | state | city | address | postal_code | emails | created | updated | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3.0.0.0/9 | AT-88-Z | NET-3-0-0-0-1 | 3.0.0.0 - 3.127.255.255 | Amazon Technologies Inc. | US | WA | Seattle | 410 Terry Ave N. | 98109 | [aws-routing-poc@amazon.com, abuse@amazonaws.com, amzn-noc-contact@amazon.com, aws-dogfish-routi... | 2017-12-20 | 2018-03-30 |
1 | 3.80.0.0/12 | AMAZON-IAD | NET-3-80-0-0-1 | None | Amazon Data Services NoVa | US | VA | Herndon | 13200 Woodland Park Road | 20171 | [amzn-noc-contact@amazon.com, abuse@amazonaws.com] | 2018-08-22 | 2018-08-22 |
In Python you can create functions that return other functions. On the way they can change how the arguments and output are processed.
Take this simple function that just applies proper capitalization to an input string.
def print_me(arg):
print(arg.capitalize())
print_me("hello")
Hello
If we try to pass a list to this function we get an
expected exception about lists not supporting capitalize
print_me(["hello", "world"])
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-66-94b3e61eb86f> in <module> ----> 1 print_me(["hello", "world"]) NameError: name 'print_me' is not defined
We could create a wrapper function that checked the input and iterated over the individual items if arg is a list. The works but we don't want to have to do this for every function that we want to have flexible input!
def print_me_list(arg):
if isinstance(arg, list):
for item in arg:
print_me(item)
else:
print_me(arg)
print_me_list("hello")
print_me_list(["how", "are", "you", "?"])
Hello How Are You ?
Instead we can create a function wrapper. The outer function
dont_care_func
defines an inner function, list_or_str
and then
returns this function. The inner function list_or_str
is what
implements the same "is-this-a-string-or-list" logic that we
saw in the previous example.
Crucially though, it isn't hard-coded to call print_me
but
calls whatever function passed to it from the outer function
dont_care_func
.
# Our magic wrapper
def dont_care_func(func):
def list_or_str(arg):
if isinstance(arg, list):
for item in arg:
func(item)
else:
func(arg)
return list_or_str
How do we use this?
We simply pass the function that we want to wrap to
dont_care_func
. Recall, that this function just returns
an instance of the inner function. In this particular instance
the value func
will have been replaced by the actual function
print_me
.
print_stuff = dont_care_func(print_me)
Now we have a wrapped version of print_me
that can
handle different types of input. Magic!
print_stuff("hello")
print_stuff(["how", "are", "you", "?"])
Hello How Are You ?
We can also define further functions and create wrapped
versions of those by passing them to dont_care_func
.
def shout_me(arg):
print(arg.upper(), "\U0001F92C!", end=" ")
shout_stuff = dont_care_func(shout_me)
shout_stuff("hello")
shout_stuff(["how", "are", "you", "?"])
HELLO 🤬! HOW 🤬! ARE 🤬! YOU 🤬! ? 🤬!
The wrapper functionality in Pivot is a bit more complex than this but essentially operates this way.