{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Guided Triage - Incidents\n", "
\n", "  Details...\n", "Notebook Version: 1.0
\n", "\n", "**Data Sources Used**:
\n", "- Microsoft Sentinel\n", " - Incidents\n", "
\n", "- Threat Intelligence Providers\n", " - OTX (https://otx.alienvault.com/)\n", " - VirusTotal (https://www.virustotal.com/)\n", " - XForce (https://www.ibm.com/security/xforce)\n", " - GreyNoise (https://www.greynoise.io)\n", "
\n", "\n", "This notebooks takes you through a guided triage of an Microsoft Sentinel Incident. The triage focuses on investigating the entities that attached to an Microsoft Sentinel Incident. This notebook can be extended with additional triage steps based on specific processes and workflows." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "### Notebook initialization\n", "The next cell:\n", "- Checks for the correct Python version\n", "- Checks versions and optionally installs required packages\n", "- Imports the required packages into the notebook\n", "- Sets a number of configuration options.\n", "\n", "This should complete without errors. If you encounter errors or warnings look at the following two notebooks:\n", "- [TroubleShootingNotebooks](https://github.com/Azure/Azure-Sentinel-Notebooks/blob/master/TroubleShootingNotebooks.ipynb)\n", "- [ConfiguringNotebookEnvironment](https://github.com/Azure/Azure-Sentinel-Notebooks/blob/master/ConfiguringNotebookEnvironment.ipynb)\n", "\n", "If you are running in the Microsoft Sentinel Notebooks environment (Azure Notebooks or Azure ML) you can run live versions of these notebooks:\n", "- [Run TroubleShootingNotebooks](./TroubleShootingNotebooks.ipynb)\n", "- [Run ConfiguringNotebookEnvironment](./ConfiguringNotebookEnvironment.ipynb)\n", "\n", "You may also need to do some additional configuration to successfully use functions such as Threat Intelligence service lookup and Geo IP lookup. \n", "There are more details about this in the `ConfiguringNotebookEnvironment` notebook and in these documents:\n", "- [msticpy configuration](https://msticpy.readthedocs.io/en/latest/getting_started/msticpyconfig.html)\n", "- [Threat intelligence provider configuration](https://msticpy.readthedocs.io/en/latest/data_acquisition/TIProviders.html#configuration-file)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Install MSTICPy and MSTICNb\n", "%pip install msticpy --upgrade\n", "%pip install msticnb --upgrade\n", "\n", "extra_imports = [\n", " \"json\",\n", " \"collections,Counter\",\n", " \"datetime,datetime\",\n", " \"datetime,timedelta\",\n", " \"matplotlib.pyplot,,plt\",\n", " \"numpy,,np\",\n", " \"pandas,,pd\",\n", " \"bokeh.plotting,show\",\n", " \"whois,whois\",\n", " \"pytz\",\n", " \"msticnb,,nb\",\n", " \"msticpy.common.azure_auth,az_connect\",\n", " \"msticpy.common.timespan,TimeSpan\",\n", " \"msticpy.nbtools.nbwidgets,SelectAlert\",\n", " \"msticpy.nbtools.nbwidgets,Progress\",\n", " \"msticpy.data.azure_sentinel,AzureSentinel\",\n", " \"msticpy.nbtools.foliummap,FoliumMap\",\n", " \"msticpy.vis.entity_graph_tools, EntityGraph\",\n", " \"msticpy.data.azure_data, AzureData\",\n", " \"msticpy.data.azure, MicrosoftSentinel\"\n", "]\n", "\n", "from msticpy.common.exceptions import MsticpyDataQueryError\n", "import msticpy\n", "\n", "msticpy.init_notebook(\n", " namespace=globals(),\n", " extra_imports=extra_imports,\n", " additional_packages=[\"python-whois>=0.7.3\"],\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "Note: The following cell creates some helper functions used later in the notebook. This cell has no output.\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def check_ent(items, entity):\n", " \"\"\"Check if entity is present\"\"\"\n", " for item in items:\n", " if item[0].casefold() == entity.casefold():\n", " return True\n", " return False\n", "\n", "\n", "def ti_color_cells(val):\n", " \"\"\"Color cells of output dataframe based on severity\"\"\"\n", " color = \"none\"\n", " if isinstance(val, str):\n", " if val.casefold() == \"high\":\n", " color = \"Red\"\n", " elif val.casefold() == \"warning\" or val.casefold() == \"medium\":\n", " color = \"Orange\"\n", " elif val.casefold() == \"information\" or val.casefold() == \"low\":\n", " color = \"Green\"\n", " return f\"background-color: {color}\"\n", "\n", "\n", "def ent_color_cells(val):\n", " \"\"\"Color table cells based on values in the cells\"\"\"\n", " if isinstance(val, int):\n", " color = \"yellow\" if val < 3 else \"none\"\n", " elif isinstance(val, float):\n", " color = \"yellow\" if val > 4.30891 or val < 2.72120 else \"none\"\n", " else:\n", " color = \"none\"\n", " return \"background-color: %s\" % color\n", "\n", "def ent_alerts(ent_val):\n", " query = f\" SecurityAlert | where TimeGenerated between(datetime({alert_q_times.start})..datetime({alert_q_times.end})) | where Entities contains '{ent_val}'\"\n", " alerts_df = qry_prov.exec_query(query)\n", " if isinstance(alerts_df, pd.DataFrame) and not alerts_df.empty:\n", " nbdisplay.display_timeline(\n", " data=alerts_df,\n", " source_columns=[\"DisplayName\", \"AlertSeverity\", \"ProviderName\"],\n", " title=f\"Alerts involving {ent_val}\",\n", " group_by=\"AlertSeverity\",\n", " height=300,\n", " time_column=\"TimeGenerated\",\n", " )\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Authenticate to Microsoft Sentinel APIs and Select Subscriptions\n", "\n", "This cell connects to the Microsoft Sentinel APIs and gets a list of subscriptions the user has access to for them to select. In order to use this the user must have at least read permissions on the Microsoft Sentinel workspace.\n", "In the drop down select the name of the subscription that contains the Microsoft Sentinel workspace you want to triage incidents from." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "az_data = AzureData()\n", "az_data.connect()\n", "subs = az_data.get_subscriptions()\n", "active_subs = subs[subs[\"State\"] == \"Enabled\"]\n", "ws = WorkspaceConfig()\n", "\n", "if ws.list_workspaces()[\"Default\"] and \"SubscriptionId\" in ws.list_workspaces()[\"Default\"]:\n", " default_sub = active_subs[active_subs['Subscription ID'] == ws.list_workspaces()['Default'][\"SubscriptionId\"]][\"Display Name\"].iloc[0]\n", "else:\n", " default_sub = \"\"\n", "\n", "sub_picker = nbwidgets.SelectItem(\n", " description=\"Select subscription:\",\n", " item_list=active_subs[\"Display Name\"].unique().tolist(),\n", " value=default_sub\n", ")\n", "display(sub_picker)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now select the name of the Microsoft Sentinel workspace in the subscription you want to triage incidents from." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ws_id = None\n", "sub_value = active_subs[active_subs[\"Display Name\"] == sub_picker.value][\n", " \"Subscription ID\"\n", "].iloc[0]\n", "\n", "azure_resources = az_data.get_resources(sub_id=sub_value)\n", "wspcs = azure_resources[\n", " (azure_resources[\"resource_type\"] == \"Microsoft.OperationsManagement/solutions\")\n", " & (azure_resources[\"name\"].str.startswith(\"SecurityInsights\"))\n", " ] \n", "\n", "if ws.list_workspaces():\n", " default_wss = list(set(ws.list_workspaces()).intersection(wspcs))\n", " default_ws = default_wss[0] if default_wss else \"\"\n", "else:\n", " default_ws = \"\"\n", "\n", "if isinstance(wspcs, pd.DataFrame) and len(wspcs.index) > 1:\n", " wspc_picker = nbwidgets.SelectItem(\n", " description=\"Select your Microsoft Sentinel workspace:\",\n", " item_list=list(wspcs['name']),\n", " value = default_ws,\n", " )\n", " display(wspc_picker)\n", "elif wspcs:\n", " ws_id = wspcs[\"resource_id\"].iloc[0]\n", " md(f\"Only one workspace found, selecting {list(wspcs.keys())[0]}\")\n", "else:\n", " md(\n", " f\"{sub_picker.value} has no Microsoft Sentinel Workspaces, please pick another subscription\"\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Authenticate to Microsoft Sentinel, TI providers and load Notebooklets\n", "
\n", "  Details...\n", "If you are using user/device authentication, run the following cell. \n", "- Click the 'Copy code to clipboard and authenticate' button.\n", "- This will pop up an Azure Active Directory authentication dialog (in a new tab or browser window). The device code will have been copied to the clipboard. \n", "- Select the text box and paste (Ctrl-V/Cmd-V) the copied value. \n", "- You should then be redirected to a user authentication page where you should authenticate with a user account that has permission to query your Log Analytics workspace.\n", "\n", "Note: you may occasionally see a JavaScript error displayed at the end of the authentication - you can safely ignore this.
\n", "On successful authentication you should see a ```popup schema``` button.\n", "To find your Workspace Id go to [Log Analytics](https://ms.portal.azure.com/#blade/HubsExtension/Resources/resourceType/Microsoft.OperationalInsights%2Fworkspaces). Look at the workspace properties to find the ID.\n", " \n", "Note that you may see a warning relating to the IPStack service when running this cell. This can be safely ignored as its not used in this case.\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if not ws_id:\n", " ws_id = az_data.get_resource_details(\n", " sub_id=sub_value, resource_id=wspcs[wspcs[\"name\"]==wspc_picker.value][\"resource_id\"].iloc[0] # type: ignore\n", " )['properties']['workspaceResourceId']\n", "\n", "ms_sent = MicrosoftSentinel(ws_id)\n", "ms_sent.connect()\n", "# Set up notebooklets\n", "qry_prov = QueryProvider(\"AzureSentinel\")\n", "qry_prov.connect(WorkspaceConfig(workspace=ws_id.split(\"/\")[-1]))\n", "ti = TILookup()\n", "nb.init(qry_prov)\n", "timespan = TimeSpan(start=datetime.now() - timedelta(days=7))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use the time selector below to set the time range you wish to get incidents from." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "md(\"Select a time range in which to get incidents from:\", \"bold\")\n", "alert_q_times = nbwidgets.QueryTime(units=\"hours\", max_before=72, max_after=1, before=24)\n", "alert_q_times.display()" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "\n", "### Incident Timeline\n", "This timeline shows you all events in the selected workspace, grouped by the severity of the incident." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "incidents = ms_sent.list_incidents()\n", "# Adding timezones to allow comparison with UTC incident times\n", "start = alert_q_times.start.astimezone()\n", "end = alert_q_times.end.astimezone()\n", "if isinstance(incidents, pd.DataFrame) and not incidents.empty:\n", " incidents[\"date\"] = pd.to_datetime(incidents[\"properties.createdTimeUtc\"], utc=True)\n", " filtered_incidents = incidents[incidents[\"date\"].between(start, end)] if not incidents[incidents[\"date\"].between(start, end)].empty else incidents\n", " filtered_incidents.mp_plot.timeline(\n", " source_columns=[\"properties.title\", \"properties.status\"],\n", " title=\"Incidents over time - grouped by severity\",\n", " height=300,\n", " group_by=\"properties.severity\",\n", " time_column=\"date\",\n", " )\n", "else:\n", " md(\"No incidents found\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Select Incident to Triage\n", "From the table below select the incident you wish to triage." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "md(\"Select an incident to triage:\", \"bold\")\n", "\n", "\n", "def display_incident(incident):\n", " details = f\"\"\"\n", "

Selected Incident: {incident['properties.title']},

\n", " Incident time: {incident['properties.createdTimeUtc']} - \n", " Severity: {incident['properties.severity']} - \n", " Assigned to: {incident['properties.owner.userPrincipalName']} - \n", " Status: {incident['properties.status']}\n", " \"\"\"\n", " new_idx = [idx.split(\".\")[-1] for idx in incident.index]\n", " incident.set_axis(new_idx, inplace=True)\n", " return HTML(details), pd.DataFrame(incident)\n", "\n", "\n", "filtered_incidents[\"short_id\"] = filtered_incidents[\"id\"].apply(\n", " lambda x: x.split(\"/\")[-1]\n", ")\n", "\n", "alert_sel = SelectAlert(\n", " alerts=filtered_incidents,\n", " columns=[\"properties.title\", \"properties.severity\", \"properties.status\"],\n", " time_col=\"properties.createdTimeUtc\",\n", " id_col=\"short_id\",\n", " action=display_incident,\n", ")\n", "alert_sel.display()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The cell below shows you key details relating to the incident, including the associated entities and the graph of the relationships between these entities." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "incident_details = ms_sent.get_incident(\n", " alert_sel.selected_alert.id.split(\"/\")[-1], entities=True, alerts=True\n", ")\n", "ent_dfs = []\n", "for ent in incident_details[\"Entities\"][0]:\n", " ent_df = pd.json_normalize(ent[1])\n", " ent_df[\"Type\"] = ent[0]\n", " ent_dfs.append(ent_df)\n", "\n", "md(\"Incident Entities:\", \"bold\")\n", "if ent_dfs:\n", " new_df = pd.concat(ent_dfs, axis=0, ignore_index=True)\n", " grp_df = new_df.groupby(\"Type\")\n", " for grp in grp_df:\n", " md(grp[0], \"bold\")\n", " display(grp[1].dropna(axis=1))\n", "\n", "alert_out = []\n", "if \"Alerts\" in incident_details.columns:\n", " for alert in incident_details.iloc[0][\"Alerts\"]:\n", " qry = f\"SecurityAlert | where TimeGenerated between((datetime({alert_q_times.start})-7d)..datetime({alert_q_times.end})) | where SystemAlertId == '{alert['ID']}'\"\n", " df = qry_prov.exec_query(qry)\n", " display(df)\n", " if df.empty or not df[\"Entities\"].iloc[0]:\n", " alert_full = {\"ID\": alert[\"ID\"], \"Name\": alert[\"Name\"], \"Entities\": None}\n", " else:\n", " alert_full = {\n", " \"ID\": alert[\"ID\"],\n", " \"Name\": alert[\"Name\"],\n", " \"Entities\": json.loads(df[\"Entities\"].iloc[0]),\n", " }\n", " alert_out.append(alert_full)\n", "\n", " incident_details[\"Alerts\"] = [alert_out]\n", "\n", "md(\"Graph of incident entities:\", \"bold\")\n", "graph = EntityGraph(incident_details.iloc[0])\n", "graph.plot(timeline=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Entity Analysis\n", "Below is an analysis of the incident's entities that appear in threat intelligence sources." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "output" ] }, "outputs": [], "source": [ "sev = []\n", "ip_ti_lookup_results = pd.DataFrame()\n", "\n", "# For each entity look it up in Threat Intelligence data\n", "md(\"Looking up entities in TI feeds...\")\n", "prog = Progress(completed_len=len(incident_details[\"Entities\"].iloc[0]))\n", "i = 0\n", "for ent in incident_details[\"Entities\"].iloc[0]:\n", " i += 1\n", " prog.update_progress(i)\n", " if ent[0] == \"Ip\":\n", " resp = ti.lookup_ioc(observable=ent[1][\"address\"], ioc_type=\"ipv4\")\n", " ip_ti_lookup_results = ip_ti_lookup_results.append(ti.result_to_df(resp), ignore_index=True)\n", " for response in resp[1]:\n", " sev.append(response[1].severity)\n", " if ent[0] == \"Url\" or ent[0] == \"DnsResolution\":\n", " if \"url\" in ent[1]:\n", " lkup_dom = ent[1][\"url\"]\n", " else:\n", " lkup_dom = ent[1][\"domainName\"]\n", " resp = ti.lookup_ioc(lkup_dom, ioc_type=\"url\")\n", " ip_ti_lookup_results = ip_ti_lookup_results.append(ti.result_to_df(resp), ignore_index=True)\n", " for response in resp[1]:\n", " sev.append(response[1].severity)\n", " if ent[0] == \"FileHash\":\n", " resp = ti.lookup_ioc(ent[1][\"hashValue\"])\n", " ip_ti_lookup_results = ip_ti_lookup_results.append(ti.result_to_df(resp), ignore_index=True)\n", " for response in resp[1]:\n", " sev.append(response[1].severity)\n", "\n", "# Take overall severity of the entities based on the highest score\n", "if \"high\" in sev:\n", " severity = \"High\"\n", "elif \"warning\" in sev:\n", " severity = \"Warning\"\n", "elif \"information\" in sev:\n", " severity = \"Information\"\n", "else:\n", " severity = \"None\"\n", "\n", "md(\"Checking to see if incident entities appear in TI data...\")\n", "\n", "incident_details[\"TI Severity\"] = severity\n", "# Output TI hits of high or warning severity\n", "if (\n", " incident_details[\"TI Severity\"].iloc[0] == \"High\"\n", " or incident_details[\"TI Severity\"].iloc[0] == \"Warning\"\n", " or incident_details[\"TI Severity\"].iloc[0] == \"Information\"\n", "):\n", " print(\"Incident:\")\n", " display(\n", " incident_details[\n", " [\n", " \"properties.createdTimeUtc\",\n", " \"properties.incidentNumber\",\n", " \"properties.title\",\n", " \"properties.status\",\n", " \"properties.severity\",\n", " \"TI Severity\",\n", " ]\n", " ]\n", " .style.applymap(ti_color_cells)\n", " .hide_index()\n", " )\n", " md(\"TI Results:\", \"bold\")\n", " display(\n", " ip_ti_lookup_results[[\"Ioc\", \"IocType\", \"Provider\", \"Severity\", \"Details\"]]\n", " .sort_values(by=\"Severity\")\n", " .style.applymap(ti_color_cells)\n", " .hide_index()\n", " )\n", "else:\n", " md(\"None of the Entities appeared in TI data\", \"bold\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### IP Entity Analysis\n", "Below is an analysis of all IP entities attached to the incident." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Enrich IP entities using the IP Summary notebooklet\n", "ip_ent_nb = nb.nblts.azsent.network.IpAddressSummary()\n", "\n", "def display_ipnb_details(item, nb_out, header = \"\"):\n", " if nb_out.check_valid_result_data(item, False):\n", " md(header, \"bold\")\n", " display(getattr(nb_out, item))\n", "\n", "def display_ip_map(nb_out):\n", " if nb_out.check_valid_result_data(\"location\", False):\n", " md(f\"Geo IP details for {ip_addr}\", \"bold\")\n", " folium_map.add_ip_cluster([nb_out.ip_entity])\n", " display(folium_map)\n", "\n", "def display_ip_alerts(nb_out):\n", " if nb_out.check_valid_result_data(\"related_alerts\", False):\n", " md(f\"Alerts for {ip_addr}\", \"bold\")\n", " nb_out.related_alerts.mp_plot.timeline(\n", " source_columns=[\"AlertName\", \"Severity\"],\n", " title=f\"Alerts associated with {ip_addr}\",\n", " height=300,\n", " )\n", "\n", "def display_ip_hosts(nb_out):\n", " if ip_ent_nb_out.host_entity[\"IpAddresses\"]:\n", " md(f\"{ip_addr} belongs to a known host\", \"bold\")\n", " display(\n", " pd.DataFrame.from_records(\n", " [\n", " {\n", " x: nb_out.host_entity[x]\n", " for x in nb_out.host_entity.__iter__()\n", " }\n", " ]\n", " )\n", " )\n", "\n", "if not ip_ti_lookup_results.empty and \"ipv4\" in ip_ti_lookup_results[\"IocType\"].unique():\n", " for ip_addr in ip_ti_lookup_results[ip_ti_lookup_results[\"IocType\"] == \"ipv4\"][\"Ioc\"].unique():\n", " folium_map = FoliumMap(width=\"50%\", height=\"50%\")\n", " try:\n", " display(HTML(f\"

Summary of Activity Related to {ip_addr}:

\"))\n", " ip_ent_nb_out = ip_ent_nb.run(value=ip_addr, timespan=timespan, silent=True)\n", " md(\n", " f\"{ip_addr} - {ip_ent_nb_out.ip_origin} - {ip_ent_nb_out.ip_type}\",\n", " \"bold\",\n", " )\n", " display_ipnb_details(\"whois\", ip_ent_nb_out, f\"Whois information for {ip_addr}\")\n", " display_ip_map(ip_ent_nb_out)\n", " display_ipnb_details(\"passive_dns\", ip_ent_nb_out, f\"Passive DNS results for {ip_addr}\")\n", " display_ipnb_details(\"vps_network\", ip_ent_nb_out, f\"{ip_addr} belongs to a known VPS provider\")\n", " display_ip_alerts(ip_ent_nb_out)\n", " display_ipnb_details(\"ti_results\", ip_ent_nb_out, f\"TI results for {ip_addr}\")\n", " display_ip_hosts(ip_ent_nb_out)\n", " md(\"
\")\n", " md(\"

\")\n", " except:\n", " md(f\"Error processing {ip_addr}\", \"bold\")\n", "else:\n", " md(\"No IP entities present\", \"bold\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Domain Entity Analysis\n", "Below is an analysis of all Domain/URL entities attached to the incident." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Enrich Domain entities\n", "domain_items = [\n", " \"name\",\n", " \"org\",\n", " \"city\",\n", " \"state\",\n", " \"country\",\n", " \"registrar\",\n", " \"status\",\n", " \"creation_date\",\n", " \"expiration_date\",\n", " \"updated_date\",\n", " \"name_servers\",\n", " \"dnssec\",\n", "]\n", "\n", "\n", "def Entropy(data):\n", " \"\"\"Calculate entropy of string\"\"\"\n", " s, lens = Counter(data), np.float(len(data))\n", " return -sum(count / lens * np.log2(count / lens) for count in s.values())\n", "\n", "\n", "domain_records = pd.DataFrame()\n", "if not ip_ti_lookup_results.empty and \"url\" in ip_ti_lookup_results[\"IocType\"].unique():\n", " md(\"Domain entity enrichment\", \"bold\")\n", " for url in ip_ti_lookup_results[ip_ti_lookup_results[\"IocType\"] == \"url\"][\"Ioc\"].unique():\n", " display(HTML(f\"

Summary of Activity Related to{url}:

\"))\n", " wis = whois(url)\n", " if not wis.domain_name:\n", " continue\n", " if isinstance(wis[\"domain_name\"], list):\n", " domain = wis[\"domain_name\"][0]\n", " else:\n", " domain = wis[\"domain_name\"]\n", " # Create domain record from whois data\n", " dom_rec = {}\n", " for key in wis.keys():\n", " if key in domain_items:\n", " dom_rec[key] = [wis[key]]\n", " dom_rec[\"domain\"] = domain\n", " dom_record = pd.DataFrame(dom_rec)\n", " page_rank = ti.result_to_df(\n", " ti.lookup_ioc(observable=domain, providers=[\"OPR\"])\n", " )\n", " page_rank_score = page_rank[\"RawResult\"][0][\"response\"][0][\n", " \"page_rank_integer\"\n", " ]\n", " dom_record[\"Page Rank\"] = [page_rank_score]\n", " dom_ent = Entropy(domain)\n", " dom_record[\"Entropy\"] = [dom_ent]\n", " # Highlight page rank of entropy scores of note\n", " display(\n", " dom_record.T.style.applymap(\n", " ent_color_cells, subset=pd.IndexSlice[[\"Page Rank\", \"Entropy\"], 0]\n", " )\n", " )\n", " md(\"If Page Rank or Domain Entropy are highlighted this indicates that their values are outside the expected values of a legitimate website\")\n", " md(f\"The average entropy for the 1M most popular domains is 3.2675\")\n", " md(\"
\")\n", " md(\"

\")\n", "else:\n", " md(\"No Domain entities present\", \"bold\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### User Entity Analysis\n", "Below is an analysis of all User entities attached to the incident." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Enrich Account entities using the AccountSummary notebooklet\n", "timespan = TimeSpan(\n", " start=pd.to_datetime(incident_details.iloc[0][\"properties.firstActivityTimeUtc\"]) - timedelta(days=1),\n", " end=pd.to_datetime(incident_details.iloc[0][\"properties.lastActivityTimeUtc\"]) + timedelta(days=1)\n", ")\n", "account_nb = nb.nblts.azsent.account.AccountSummary()\n", "user = None\n", "uent = None\n", "\n", "def display_accnb_details(item, nb_out, header = \"\"):\n", " if nb_out.check_valid_result_data(item, False):\n", " md(header, \"bold\")\n", " display(getattr(nb_out, item))\n", "\n", "if check_ent(incident_details[\"Entities\"][0], \"account\") or check_ent(\n", " incident_details[\"Entities\"][0], \"mailbox\"\n", "):\n", " md(\"Account entity enrichment\", \"bold\")\n", " for ent in incident_details[\"Entities\"][0]:\n", " if ent[0] == \"Account\" or ent[0] == \"Mailbox\":\n", " if \"accountName\" in ent[1].keys():\n", " uent = ent[1][\"accountName\"]\n", " elif \"aadUserId\" in ent[1].keys():\n", " uent = ent[1][\"aadUserId\"]\n", " elif \"upn\" in ent[1].keys():\n", " uent = ent[1][\"upn\"]\n", " if \"upnSuffix\" in ent[1].keys():\n", " user = uent + \"@\" + ent[1][\"upnSuffix\"]\n", " else:\n", " user = uent\n", " if user:\n", " try:\n", " display(HTML(f\"

Summary of Activity Related to{user}:

\"))\n", " ac_nb = account_nb.run(timespan=timespan, value=user, silent=True)\n", " if ac_nb.account_selector is not None:\n", " md(\"Warning: multiple matching accounts found\")\n", " display(ac_nb.account_selector)\n", " display_accnb_details(\"account_activity\", ac_nb, \"Recent activity\")\n", " display_accnb_details(\"related_alerts\", ac_nb, \"Related alerts\")\n", " ac_nb.get_additional_data(silent=True)\n", " display_accnb_details(\"host_logon_summary\", ac_nb, \"Host Logons\")\n", " display_accnb_details(\"azure_activity_summary\", ac_nb, \"Azure Activity\")\n", " display_accnb_details(\"azure_timeline_by_provider\", ac_nb)\n", " display_accnb_details(\"ip_summary\", ac_nb, \"IP summary\")\n", " except:\n", " print(f\"Error processing {user}\")\n", "else:\n", " md(\"No Account entities present\", \"bold\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Host Entity Analysis\n", "Below is an analysis of all Host entities attached to the incident." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Enrich Host entities using the HostSummary notebooklet\n", "timespan = TimeSpan(\n", " start=pd.to_datetime(incident_details.iloc[0][\"properties.firstActivityTimeUtc\"]) - timedelta(days=1),\n", " end=pd.to_datetime(incident_details.iloc[0][\"properties.lastActivityTimeUtc\"]) + timedelta(days=1)\n", ")\n", "host_nb = nb.nblts.azsent.host.HostSummary()\n", "\n", "if check_ent(incident_details[\"Entities\"][0], \"host\"):\n", " md(\"Host entity enrichment\", \"bold\")\n", " for ent in incident_details[\"Entities\"][0]:\n", " if ent[0] == \"Host\":\n", " if \"dnsDomain\" in ent[1]:\n", " host_name = ent[1][\"hostName\"] + \".\" + ent[1][\"dnsDomain\"], \"\"\n", " else:\n", " host_name = ent[1][\"hostName\"]\n", " md(f\"Host summary for {host_name}\", \"bold\")\n", " try:\n", " display(HTML(f\"

Summary of Activity Related to{host_name}:

\"))\n", " host_sum_out = host_nb.run(value=host_name, timespan=timespan)\n", " except:\n", " print(f\"Error processing {host_name}\")\n", "else:\n", " md(\"No Host entities present\", \"bold\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Other Entity Analysis\n", "If there are other entity types not analyzed above, a timeline of their appearance in security alerts appears below." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ent_map = {\n", " \"FieHash\": \"hashValue\",\n", " \"Malware\": \"malwareName\",\n", " \"File\": \"fileName\",\n", " \"CloudApplication\": \"appId\",\n", " \"AzureResource\": \"ResourceId\",\n", " \"RegistryValue\": \"registryName\",\n", " \"SecurityGroup\": \"SID\",\n", " \"IoTDevice\": \"deviceId\",\n", " \"Mailbox\": \"mailboxPrimaryAddress\",\n", " \"MailMessage\": \"networkMessageId\",\n", " \"SubmissionMail\": \"submissionId\",\n", "}\n", "for ent in incident_details[\"Entities\"][0]:\n", " if ent[0] in ent_map:\n", " ent_alerts(ent[1][ent_map[ent[0]]])" ] } ], "metadata": { "interpreter": { "hash": "70673dbb0e081aa3831869ef2042eea6ce08ea300fe5aabb70c669fac0ce2a09" }, "kernelspec": { "display_name": "Python 3.8 - AzureML", "language": "python", "name": "python38-azureml" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": { "0040cad1767f4b95a00aefbc70d06bc1": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "01069a28b66840f5908dbf5167e08482": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "" } }, "14eaa102acb64e0b8073da21f45e83b5": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_e28b52485fcb486c91ec902f5b7c61db", "IPY_MODEL_db98f91c5e394abeb6b76ed5fb4284ad", "IPY_MODEL_6125ee42c10541e3bca956f190da4496" ], "layout": "IPY_MODEL_47880b93603046cea618b9d10a7f192c" } }, "195c48cd5c414746b418dac44c964c18": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "100px" } }, "2483892439044ba69f374f2c0bb01c72": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "" } }, "2b5f387ba79b44b9a764af8c44827521": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "LabelModel", "state": { "layout": "IPY_MODEL_af3398b31ebc4934a2dc1ed71efeb55c", "style": "IPY_MODEL_01069a28b66840f5908dbf5167e08482" } }, "3338fc72841a43b983a7a5d7ab114635": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "initial" } }, "34aa9860ecc94a71b4ec1920d9554694": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "70%" } }, "3c3908a4efe34c62a0a008f31eefd1c8": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_d8ba0aa2aad54cd0aa69760a5354b452", "IPY_MODEL_94d2f3d7a77d475fa56029c6c1b102a2" ], "layout": "IPY_MODEL_b108e5c7f71d41aa896d812172987157" } }, "3c990d1c0dac4fac9be32569b11c773a": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "initial" } }, "3de1a85313a54edab63eab8a97d013cd": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "" } }, "41ce3c950bf641e982dd88dc1439cc85": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_6d846f2a40af446183bbc9999494c25c", "IPY_MODEL_db4165bc3d9e4a3182d06b7fca3178e4", "IPY_MODEL_aad0360f0cb94309b96360ef49ef7474" ], "layout": "IPY_MODEL_7601235d1fbb40478da390e5c635bde4" } }, "424d17d0ee4b4d929ea90e253f069ed7": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntRangeSliderModel", "state": { "_model_name": "IntRangeSliderModel", "_view_name": "IntRangeSliderView", "description": "Time Range", "layout": "IPY_MODEL_847bf20ca3504a108341090f44a5d399", "max": 28, "min": -28, "style": "IPY_MODEL_ecd5058213f7439db39bd205512843e5", "value": [ -1, 1 ] } }, "442fd1263e334d45ad7d171c3457d7cd": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "TextModel", "state": { "description": "Time (24hr)", "layout": "IPY_MODEL_d1f7f46ac3b64c818536834c60392fea", "style": "IPY_MODEL_3de1a85313a54edab63eab8a97d013cd", "value": "22:38:45.575783" } }, "47880b93603046cea618b9d10a7f192c": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "4bf47ca149934c799ae842ef53122f0d": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "50%" } }, "511af61975284928bb839f6a946ae2b6": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "" } }, "56dbb96a024b4062bb16295c93bb8386": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "" } }, "5d170286dedd41889a7345023f650a33": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "50%" } }, "6125ee42c10541e3bca956f190da4496": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "TextModel", "state": { "description": "Query end time (UTC) : ", "layout": "IPY_MODEL_4bf47ca149934c799ae842ef53122f0d", "style": "IPY_MODEL_c8d4203d9a214a2faf7c33159211f3ad", "value": "2021-07-03 22:38:35.047441" } }, "621702c9f018481183b96930e706cc54": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "6d846f2a40af446183bbc9999494c25c": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HTMLModel", "state": { "layout": "IPY_MODEL_af92228a3694413aacca38bdf0d6db3a", "style": "IPY_MODEL_ff485c7bb935466a8425b6a4ae8f8da9", "value": "

Set time range for pivot functions.

" } }, "722e044af71d41c6b6a82690cd8a577c": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DropdownModel", "state": { "_options_labels": [ "minute", "hour", "day", "week" ], "index": 2, "layout": "IPY_MODEL_96fa332bb44f43b19d7a373d509f7afb", "style": "IPY_MODEL_2483892439044ba69f374f2c0bb01c72" } }, "7601235d1fbb40478da390e5c635bde4": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "777e16e2c58745df8e5d76524f5a1433": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "7a9485f145724c38b81876500dbb43f2": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HTMLModel", "state": { "layout": "IPY_MODEL_fa1b0cab6957493e935f4e9a8d428cb2", "style": "IPY_MODEL_94439f6f9f9b400496af079cd6e37604", "value": "

Set query time boundaries

" } }, "81676b130d4a4af3a1b88a9a378dd60d": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "" } }, "82a64b7fb54640eda6c0c87406c628d2": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "50%" } }, "847bf20ca3504a108341090f44a5d399": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "70%" } }, "8c8eab82b42945dc89a91bbb570eb170": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "" } }, "8f45b292a74043d0a1cee653bc57689a": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "8f4f079d2f044d36a7adfaf4efdd27cc": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "95%" } }, "927b173de2034b0dbe37d9e1ae388c9a": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_7a9485f145724c38b81876500dbb43f2", "IPY_MODEL_d1fa63f01abb4c59a0158af8c3af9d8d", "IPY_MODEL_14eaa102acb64e0b8073da21f45e83b5" ], "layout": "IPY_MODEL_8f45b292a74043d0a1cee653bc57689a" } }, "94439f6f9f9b400496af079cd6e37604": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "" } }, "949f237e510542789ff9e149560d5181": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DatePickerModel", "state": { "description": "Origin Date", "disabled": false, "layout": "IPY_MODEL_dcd9308cd0474c24827bcc6cec31e96d", "style": "IPY_MODEL_81676b130d4a4af3a1b88a9a378dd60d", "value": { "date": 2, "month": 6, "year": 2021 } } }, "94d2f3d7a77d475fa56029c6c1b102a2": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DropdownModel", "state": { "_options_labels": [ "minute", "hour", "day", "week" ], "index": 2, "layout": "IPY_MODEL_195c48cd5c414746b418dac44c964c18", "style": "IPY_MODEL_8c8eab82b42945dc89a91bbb570eb170" } }, "96fa332bb44f43b19d7a373d509f7afb": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "100px" } }, "a445ee0e426c4f13af21b260b700e05f": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "99%" } }, "a4d3df3b4447488f93e32ac4b3ada8c9": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "initial" } }, "aad0360f0cb94309b96360ef49ef7474": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "children": [ "IPY_MODEL_3c3908a4efe34c62a0a008f31eefd1c8", "IPY_MODEL_f5fe70128cdf4eadaf8455cdbbd719cb", "IPY_MODEL_ae8c36ba95ab4ffb883b6cef6ffa6ac7" ], "layout": "IPY_MODEL_777e16e2c58745df8e5d76524f5a1433" } }, "ae8c36ba95ab4ffb883b6cef6ffa6ac7": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "TextModel", "state": { "description": "Query end time (UTC) : ", "layout": "IPY_MODEL_82a64b7fb54640eda6c0c87406c628d2", "style": "IPY_MODEL_f85fee408dda49ffadbae38d3f49eab9", "value": "2021-07-02 22:38:45.575783" } }, "af3398b31ebc4934a2dc1ed71efeb55c": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "99%" } }, "af92228a3694413aacca38bdf0d6db3a": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "b108e5c7f71d41aa896d812172987157": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "b7cffa19b0144d8eb66f2c87e47282f6": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "50%" } }, "c8d4203d9a214a2faf7c33159211f3ad": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "initial" } }, "d1f7f46ac3b64c818536834c60392fea": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "d1fa63f01abb4c59a0158af8c3af9d8d": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_949f237e510542789ff9e149560d5181", "IPY_MODEL_e0f304182b2543cc88d79e19c5bae2c6" ], "layout": "IPY_MODEL_621702c9f018481183b96930e706cc54" } }, "d43e2535709949c7bbe3b426483ff4ae": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "70%" } }, "d6fa1751257f48c5a6161393ac096efc": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "d8ba0aa2aad54cd0aa69760a5354b452": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "IntRangeSliderModel", "state": { "_model_name": "IntRangeSliderModel", "_view_name": "IntRangeSliderView", "description": "Time Range", "layout": "IPY_MODEL_d43e2535709949c7bbe3b426483ff4ae", "max": 28, "min": -28, "style": "IPY_MODEL_a4d3df3b4447488f93e32ac4b3ada8c9", "value": [ -1, 0 ] } }, "db4165bc3d9e4a3182d06b7fca3178e4": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_ed5543a1b31c4370ab95fdb59cf1453e", "IPY_MODEL_442fd1263e334d45ad7d171c3457d7cd" ], "layout": "IPY_MODEL_f3278667c52b4c6986fe59f6854be181" } }, "db98f91c5e394abeb6b76ed5fb4284ad": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "TextModel", "state": { "description": "Query start time (UTC):", "layout": "IPY_MODEL_5d170286dedd41889a7345023f650a33", "style": "IPY_MODEL_3c990d1c0dac4fac9be32569b11c773a", "value": "2021-07-01 22:38:35.047441" } }, "dcd9308cd0474c24827bcc6cec31e96d": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "debbd947449c4860aef557d0d8c54d08": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "70%" } }, "e0f304182b2543cc88d79e19c5bae2c6": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "TextModel", "state": { "description": "Time (24hr)", "layout": "IPY_MODEL_d6fa1751257f48c5a6161393ac096efc", "style": "IPY_MODEL_56dbb96a024b4062bb16295c93bb8386", "value": "22:38:35.047441" } }, "e28b52485fcb486c91ec902f5b7c61db": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": { "children": [ "IPY_MODEL_424d17d0ee4b4d929ea90e253f069ed7", "IPY_MODEL_722e044af71d41c6b6a82690cd8a577c" ], "layout": "IPY_MODEL_0040cad1767f4b95a00aefbc70d06bc1" } }, "e41efc3621cc45e399078cf24332bf67": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "height": "150px", "width": "300px" } }, "ec9a50e5fb5646669c679ce5dcf6f26a": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "ecd5058213f7439db39bd205512843e5": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "SliderStyleModel", "state": { "description_width": "initial" } }, "ed5543a1b31c4370ab95fdb59cf1453e": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DatePickerModel", "state": { "description": "Origin Date", "disabled": false, "layout": "IPY_MODEL_ec9a50e5fb5646669c679ce5dcf6f26a", "style": "IPY_MODEL_511af61975284928bb839f6a946ae2b6", "value": { "date": 2, "month": 6, "year": 2021 } } }, "f3278667c52b4c6986fe59f6854be181": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "f5fe70128cdf4eadaf8455cdbbd719cb": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "TextModel", "state": { "description": "Query start time (UTC):", "layout": "IPY_MODEL_b7cffa19b0144d8eb66f2c87e47282f6", "style": "IPY_MODEL_3338fc72841a43b983a7a5d7ab114635", "value": "2021-07-01 22:38:45.575783" } }, "f662b92adde64b5da4e13750c0fa88c0": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "width": "70%" } }, "f85fee408dda49ffadbae38d3f49eab9": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "initial" } }, "f90cc4c565664db79c4aa5220fe7f94c": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "height": "150px", "width": "300px" } }, "fa1b0cab6957493e935f4e9a8d428cb2": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {} }, "ff485c7bb935466a8425b6a4ae8f8da9": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "description_width": "" } } }, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }