Notebook Version: 1.0
Python Version: Python 3.6 (including Python 3.6 - AzureML)
Required Packages: msticpy, plotly, ruamel.yaml, requests_html, attackcti, qgrid, pandas, numpy, matplotlib, ipywidgets, ipython
Platforms Supported:
This Notebooks brings together analysis and visualization of all analytics queries (hunting and detection) in Microsoft Sentinel community Github. Optionally, you can also connect to your own workspace to gather similar data enabled in your environment using REST API. The notebook further cleans, processes and enriches the data and then converts it into structured tabular data. The final data can be visualized in a number of ways with example visualization in this notebooks for items such as Heatmaps, Radar charts, embedded ATT&CK Navigator.
#imports
import requests
import zipfile
import io
import re
import glob
import qgrid
import yaml
import json
import csv
import os
import sys
import plotly.graph_objects as go
from pathlib import Path
from ipywidgets import Layout
from IPython.display import display, HTML, Markdown
from requests.exceptions import HTTPError
from requests_html import HTMLSession
from attackcti import attack_client
from typing import Optional, IO
from plotly.subplots import make_subplots
from datetime import date
from tqdm.notebook import tqdm
REQ_PYTHON_VER=(3, 6)
REQ_MSTICPY_VER=(1, 6, 0)
display(HTML("Checking for msticpy update"))
%pip install --upgrade msticpy
import msticpy
#msticpy imports
from msticpy.nbtools import nbwidgets
from msticpy.data.azure.sentinel_core import MicrosoftSentinel
from msticpy.data.uploaders.loganalytics_uploader import LAUploader
msticpy.init_notebook(
namespace=globals(),
additional_packages=["plotly", "ruamel.yaml", "requests_html", "attackcti", "qgrid", "tqdm"],
);
#Set pandas options
pd.get_option('max_rows',10)
pd.set_option('max_colwidth',50)
All packages are already installed
You can retrieve Detections and hunting Queries via below 2 methods.
In the first method, you can directly download from public Microsoft Sentinel GitHub to download templates. The templates are available withing Analytics pane and must be explicitly enabled and onboarded.
Alternatively, you can also point it to your private GitHub repository if available. If you want to read more about Microsoft Sentinel DevOps process, refer the blog Deploying and Managing Microsoft Sentinel as Code.
In the below cell, various functions have been declared which will be used later in the notebook separate sections.
def get_sentinel_queries_from_github(
git_url: Optional[
str
] = "https://github.com/Azure/Azure-Sentinel/archive/master.zip",
outputdir: Optional[str] = None,
) -> bool:
"""
Download Microsoft Sentinel Github archive and extract detection and hunting queries.
Parameters
----------
git_url : str, optional
URL of the GIT Repository to be downloaded, by default "https://github.com/Azure/Azure-Sentinel/archive/master.zip"
outputdir : str, optional
Provide absolute path to the output folder to save downloaded archive (e.g. '/usr/home' or 'C:\downloads'),
If no path provided, it will download to .msticpy dir under Azure-Sentinel directory.
"""
if outputdir is None:
outputdir = Path.joinpath(Path("~").expanduser(), ".msticpy", "Azure-Sentinel")
try:
with requests.get(git_url, stream=True) as response:
response = requests.get(git_url, stream=True)
total_size_in_bytes = int(response.headers.get("content-length", 0))
block_size = 1024
progress_bar = tqdm(
desc="Downloading from Microsoft Sentinel Github",
initial=0,
unit="iB",
unit_scale=True,
)
response.raise_for_status()
repo_zip = Path.joinpath(Path(outputdir), "Azure-Sentinel.zip")
with open(repo_zip, "wb") as file:
for data in response.iter_content(chunk_size=10000):
progress_bar.update(len(data))
file.write(data)
progress_bar.close()
archive = zipfile.ZipFile(repo_zip, mode="r")
# Only extract Detections and Hunting Queries Folder
for file in archive.namelist():
if file.startswith(
(
"Azure-Sentinel-master/Detections/",
"Azure-Sentinel-master/Hunting Queries/",
)
):
archive.extract(file, path=outputdir)
print("Downloaded and Extracted Files successfully")
except HTTPError as http_err:
warnings.warn(f"HTTP error occurred trying to download from Github: {http_err}")
def parse_yaml(parent_dir: str, child_dir: str) -> pd.DataFrame:
sentinel_repourl = "https://github.com/Azure/Azure-Sentinel/blob/master"
# Collect list of files recusrively uinder a folder
yaml_queries = glob.glob(f"{parent_dir}/{child_dir}/**/*.yaml", recursive=True)
df = pd.DataFrame()
# Recursively load yaml Files and append to dataframe
for query in yaml_queries:
with open(query, "r", encoding="utf-8", errors="ignore") as f:
parsed_yaml_df = pd.json_normalize(yaml.load(f, Loader=yaml.FullLoader))
parsed_yaml_df["DetectionURL"] = query.replace(parent_dir, sentinel_repourl)
df = df.append(parsed_yaml_df, ignore_index=True, sort=True)
if child_dir == "Detections":
df["DetectionType"] = "Analytics"
elif child_dir == "Hunting Queries":
df["DetectionType"] = "Hunting"
df["DetectionService"] = "Microsoft Sentinel Community Github"
return df
def get_fusion_alerts(
url: Optional[
str
] = "https://docs.microsoft.com/azure/sentinel/fusion-scenario-reference",
) -> pd.DataFrame:
session = HTMLSession()
r = session.get(url)
fusion_df = pd.DataFrame(
re.findall(r"<li><p><strong>(.*)</strong></p>", r.text), columns=["name"]
)
fusion_df["tactics"] = "N.A."
fusion_df["relevantTechniques"] = "N.A."
fusion_df["connectorId"] = "N.A."
fusion_df["dataTypes"] = "N.A."
for i in range(0, 5):
fusion_df["tactics"][i] = ["InitialAccess", "Impact"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1496"]
for i in range(5, 10):
fusion_df["tactics"][i] = ["InitialAccess", "Exfiltration", "Collection"]
fusion_df["relevantTechniques"][i] = ["T1078", "T114", "T1020"]
for i in range(10, 15):
fusion_df["tactics"][i] = ["InitialAccess", "Exfiltration"]
fusion_df["connectorId"][i] = [
"MicrosoftCloudAppSecurity",
"AzureActiveDirectoryIdentityProtection",
]
for i in range(15, 20):
fusion_df["tactics"][i] = ["Initial Access", "Exfiltration"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1567"]
for i in range(20, 25):
fusion_df["tactics"][i] = ["Initial Access", "Lateral Movement", "Exfiltration"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1534"]
for i in range(25, 30):
fusion_df["tactics"][i] = ["Initial Access", "Exfiltration"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1567"]
for i in range(30, 35):
fusion_df["tactics"][i] = ["InitialAccess", "Exfiltration"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1567"]
for i in range(35, 40):
fusion_df["tactics"][i] = ["InitialAccess", "Impact"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1485"]
for i in range(40, 45):
fusion_df["tactics"][i] = ["Initial Access", "Impact"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1485"]
for i in range(45, 50):
fusion_df["tactics"][i] = ["InitialAccess", "Impact"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1499"]
for i in range(50, 55):
fusion_df["tactics"][i] = ["InitialAccess", "LateralMovement"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1534"]
for i in range(55, 60):
fusion_df["tactics"][i] = ["InitialAccess", "LateralMovement", "Exfiltration"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1534", "T1020"]
for i in range(60, 65):
fusion_df["tactics"][i] = [
"InitialAccess",
"Persistence",
"DefenseEvasion",
"LateralMovement",
"Collection",
"Exfiltration",
"Impact",
]
fusion_df["relevantTechniques"][i] = ["T1078"]
for i in range(65, 70):
fusion_df["tactics"][i] = ["InitialAccess", "Impact"]
fusion_df["relevantTechniques"][i] = ["T1078", "T1486"]
for i in range(0, 69):
fusion_df["connectorId"][i] = [
"MicrosoftCloudAppSecurity",
"AzureActiveDirectoryIdentityProtection",
]
fusion_df["dataTypes"][i] = ["SecurityAlert"]
# Custom dataset for non-standard formatted alerts in the doc. - May need updates to keep it current
df2 = pd.DataFrame(
[
[
"PowerShell made a suspicious network connection, followed by anomalous traffic flagged by Palo Alto Networks firewall",
["Execution"],
["T1059"],
["MicrosoftDefenderAdvancedThreatProtection", "PaloAltoNetworks"],
["SecurityAlert"],
],
[
"Suspicious remote WMI execution followed by anomalous traffic flagged by Palo Alto Networks firewall",
["Execution", "Discovery"],
["T1047"],
["MicrosoftDefenderAdvancedThreatProtection", "PaloAltoNetworks"],
["SecurityAlert"],
],
[
"Network request to TOR anonymization service followed by anomalous traffic flagged by Palo Alto Networks firewall",
["CommandAndControl"],
["T1573", "T1090"],
["MicrosoftDefenderAdvancedThreatProtection", "PaloAltoNetworks"],
["SecurityAlert"],
],
[
"Outbound connection to IP with a history of unauthorized access attempts followed by anomalous traffic flagged by Palo Alto Networks firewall",
["CommandAndControl"],
["T1071"],
["MicrosoftDefenderAdvancedThreatProtection", "PaloAltoNetworks"],
["SecurityAlert"],
],
[
"Suspected use of attack framework followed by anomalous traffic flagged by Palo Alto Networks firewall",
[
"InitialAccess",
"Execution",
"LateralMovement",
"PrivilegeEscalation",
],
["T1190", "T1203", "T1210", "T1068"],
["MicrosoftDefenderAdvancedThreatProtection", "PaloAltoNetworks"],
["SecurityAlert"],
],
[
"Suspicious resource / resource group deployment by a previously unseen caller following suspicious Azure AD sign-in",
[
"InitialAccess",
"Impact",
],
["T1078", "T1496"],
["AzureSentinel", "AzureActiveDirectoryIdentityProtection"],
["SecurityAlert"],
],
],
columns=[
"name",
"tactics",
"relevantTechniques",
"connectorId",
"dataTypes",
],
)
result = fusion_df.append(df2, ignore_index=True)
result["DetectionType"] = "Fusion"
result["DetectionService"] = "Microsoft Sentinel"
result["DetectionURL"] = url
# Exploding columns to flatten the table
columns_to_expand = [
"tactics",
"relevantTechniques",
"connectorId",
"dataTypes",
]
for column in columns_to_expand:
result = result.explode(column).reset_index(drop=True)
# Populate new column Platform based on custom mapping
result["Platform"] = result.connectorId.map(platform_mapping)
result = result.explode("Platform").reset_index(drop=True)
result["IngestedDate"] = date.today()
return result
def clean_and_preprocess_data(df):
columns = [
"DetectionType",
"DetectionService",
"id",
"name",
"description",
"query",
"queryFrequency",
"queryPeriod",
"triggerOperator",
"triggerThreshold",
"tactics",
"relevantTechniques",
"requiredDataConnectors",
"severity",
"DetectionURL",
"IngestedDate",
]
# Reording columns
df = df[columns]
# Inserting additional columns to list at specific index for later use
columns.insert(5, "connectorId")
columns.insert(6, "dataTypes")
# Ignoring the records with invalid connector values
df = df[df.requiredDataConnectors.apply(lambda x: x != [{"connectorId": []}])]
# Handle null values in required data connectors
isnull = df.requiredDataConnectors.isnull()
if len(df[isnull]) > 0:
df.loc[isnull, "requiredDataConnectors"] = [[[]] * isnull.sum()]
no_of_records_with_emptylist_connectors = len(
df[df["requiredDataConnectors"].map(lambda d: len(d)) == 0]
)
# Separate Null and Not Null requiredDataConnectors
not_null_df = (
df[df["requiredDataConnectors"].map(lambda d: len(d)) > 0]
.reset_index()
.drop("index", axis=1)
)
empty_null_df = (
df[df.requiredDataConnectors.isnull()].reset_index().drop("index", axis=1)
)
null_df = (
df[df["requiredDataConnectors"].map(lambda d: len(d)) == 0]
.reset_index()
.drop("index", axis=1)
)
# Exploding columns to flatten the table
columns_to_expand = ["tactics", "relevantTechniques", "requiredDataConnectors"]
for column in columns_to_expand:
not_null_df = not_null_df.explode(column).reset_index(drop=True)
# #Apply Data wrangling to derive columns from Json response
final_not_null_df = pd.DataFrame(
not_null_df["requiredDataConnectors"].values.tolist()
)
# Concatenate 2 dataframs vertically
result_not_null_df = pd.concat([not_null_df, final_not_null_df], axis=1)
# Exploding dataTypes column
result_not_null_df = result_not_null_df.explode("dataTypes").reset_index(drop=True)
new_columns = [
"DetectionType",
"DetectionService",
"id",
"name",
"description",
"connectorId",
"dataTypes",
"query",
"queryFrequency",
"queryPeriod",
"triggerOperator",
"triggerThreshold",
"tactics",
"relevantTechniques",
"severity",
"DetectionURL",
"IngestedDate",
]
result_not_null_df = result_not_null_df[new_columns]
result_not_null_df["Platform"] = result_not_null_df.connectorId.map(
platform_mapping
)
result_not_null_df = result_not_null_df.explode("Platform").reset_index(drop=True)
# Exploding columns to flatten the table
columns_to_expand = ["tactics", "relevantTechniques"]
for column in columns_to_expand:
null_df = null_df.explode(column).reset_index(drop=True)
null_df["connectorId"] = "CustomConnector"
null_df["dataTypes"] = null_df.DetectionURL.apply(
lambda x: pd.Series(str(x).split("/")[-2] + "_CL")
)
null_df["Platform"] = ""
new_columns = [
"DetectionType",
"DetectionService",
"id",
"name",
"description",
"connectorId",
"dataTypes",
"query",
"queryFrequency",
"queryPeriod",
"triggerOperator",
"triggerThreshold",
"tactics",
"relevantTechniques",
"severity",
"DetectionURL",
"IngestedDate",
"Platform",
]
result_null_df = null_df[new_columns]
result = pd.concat([result_not_null_df, result_null_df], axis=0)
return result
def get_mitre_matrix_flat():
# Create the client
lift = attack_client()
# Pull all the techniques without STIX Format
all_techniques = lift.get_techniques(stix_format=False)
techniques_normalized = pd.json_normalize(all_techniques)
# Selecting specific columns of output dataset and reindex the dataframe
techniques = techniques_normalized.reindex(
["matrix", "tactic", "technique", "technique_id"], axis=1
)
mitre_attack = techniques["matrix"] == "mitre-attack"
mitre_attack_df = techniques[mitre_attack]
mitre_attack_df = mitre_attack_df.reset_index(drop=True)
# Exploding Platform and Tactic Columns to flatten the table
mitre_attack_df = mitre_attack_df.explode("tactic").reset_index(drop=True)
# Creae a new column by removing subtechniques
mitre_attack_df["technique_id_parsed"] = mitre_attack_df["technique_id"].str.split(
".", n=1, expand=True
)[0]
return mitre_attack_df
# Custom ConnectorId to Platform Mapping
platform_mapping = {
"AIVectraDetect": ["Azure", "Windows", "Linux"],
"AlsidForAD": ["Azure", "Azure AD"],
"AWS": ["AWS"],
"AWSS3": ["AWS", "SaaS"],
"AzureActiveDirectory": ["Azure", "Azure AD"],
"AzureActiveDirectoryIdentityProtection": ["Azure", "Azure AD"],
"AzureActivity": ["Azure", "SaaS"],
"AzureFirewall": ["Azure", "Windows", "Linux"],
"AzureDevOpsAuditing": ["Azure", "SaaS"],
"AzureMonitor": ["SaaS"],
"AzureMonitor(IIS)": ["Azure"],
"AzureMonitor(Keyvault)": ["Azure"],
"AzureMonitor(Query Audit)": ["Azure"],
"AzureMonitor(VMInsights)": ["Azure", "Windows", "Linux"],
"AzureMonitor(WindowsEventLogs)": ["Azure", "Windows"],
"AzureMonitor(WireData)": ["Azure", "Windows", "Linux"],
"AzureNetworkWatcher": ["Azure", "Windows", "Linux"],
"AzureSecurityCenter": ["Azure", "SaaS"],
"Barracuda": ["Azure", "Windows", "Linux"],
"BehaviorAnalytics": ["Azure AD", "Azure", "Windows"],
"CEF": ["Azure", "Windows", "Linux"],
"CheckPoint": ["Azure", "Windows", "Linux"],
"CiscoASA": ["Azure", "Windows", "Linux"],
"CiscoUmbrellaDataConnector": ["Windows", "Linux"],
"CognniSentinelDataConnector": ["SaaS"],
"CyberpionSecurityLogs": ["SaaS"],
"CustomConnector": ["Unknown"],
"DNS": ["Azure", "Windows", "Linux"],
"EsetSMC": ["Azure", "Windows", "Linux"],
"F5": ["Azure", "Windows", "Linux"],
"Fortinet": ["Azure", "Windows", "Linux"],
"GitHub": ["SaaS", "Windows", "Linux"],
"InfobloxNIOS": ["Azure", "Windows", "Linux"],
"Microsoft365Defender": ["Azure", "Windows"],
"MicrosoftCloudAppSecurity": ["Azure", "AWS", "GCP", "SaaS"],
"MicrosoftDefenderAdvancedThreatProtection": ["Windows", "Linux"],
"MicrosoftThreatProtection": ["Azure", "Windows"],
"Office365": ["Office 365"],
"OfficeATP": ["Office 365"],
"OktaSSO": ["Azure AD", "AWS", "GCP", "SaaS"],
"PaloAltoNetworks": ["Azure", "Windows", "Linux"],
"ProofpointPOD": ["Office 365"],
"ProofpointTAP": ["Office 365"],
"PulseConnectSecure": ["Azure", "Windows", "Linux"],
"QualysVulnerabilityManagement": ["Azure", "Windows", "Linux", "macOS"],
"SecurityEvents": ["Windows"],
"SophosXGFirewall": ["Azure", "Windows", "Linux"],
"SymantecProxySG": ["Azure", "Windows", "Linux"],
"SymantecVIP": ["Azure", "Windows", "Linux"],
"Syslog": ["Linux"],
"ThreatIntelligence": [
"Windows",
"Linux",
"macOS",
"Azure",
"AWS",
"Azure AD",
"Office 365",
],
"ThreatIntelligenceTaxii": [
"Windows",
"Linux",
"macOS",
"Azure",
"AWS",
"Azure AD",
"Office 365",
],
"TeamsLogs": ["Windows", "Linux", "macOS"],
"TrendMicro": ["Windows", "Linux", "macOS"],
"TrendMicroXDR": ["Windows", "Linux", "macOS"],
"VMwareCarbonBlack": ["Windows", "Linux", "macOS"],
"WAF": ["Azure", "SaaS"],
"WindowsFirewall": ["Windows"],
"WindowsSecurityEvents": ["Windows"],
"Zscaler": ["Azure", "Windows", "Linux"],
"ZoomLogs": ["SaaS"],
}
print(
"Utility functions created:: \n get_sentinel_queries_from_github, parse_yaml, get_fusion_alerts, clean_and_preprocess_data, get_mitre_matrix_flat "
)
Utility functions created:: get_sentinel_queries_from_github, parse_yaml, get_fusion_alerts, clean_and_preprocess_data, get_mitre_matrix_flat
def_path = Path.joinpath(Path(os.getcwd()))
path_wgt = widgets.Text(value=str(def_path),
description='Path to extract to zipped repo files: ',
layout=Layout(width='50%'),
style={'description_width': 'initial'})
path_wgt
Text(value='/home/jovyan/Azure-Sentinel-Notebooks', description='Path to extract to zipped repo files: ', layo…
# Download the Microsoft Sentinel Github repo as ZIP
azsentinel_git_url = 'https://github.com/Azure/Azure-Sentinel/archive/master.zip'
get_sentinel_queries_from_github(git_url=azsentinel_git_url, outputdir=path_wgt.value)
HBox(children=(FloatProgress(value=1.0, bar_style='info', description='Downloading from Microsoft Sentinel Git…
Downloaded and Extracted Files successfully
QUERIES_PATH = 'Azure-Sentinel-master'
sentinel_root = Path(path_wgt.value) / QUERIES_PATH
display(HTML("<h3>Listings under Detections...</h2>"))
print(*Path("Azure-Sentinel-master/Detections/").iterdir(), sep="\n")
display(HTML("<h3>Listings under Hunting Queries...</h2>"))
print(*Path("Azure-Sentinel-master/Hunting Queries/").iterdir(), sep="\n")
Azure-Sentinel-master/Detections/Heartbeat Azure-Sentinel-master/Detections/ThreatIntelligenceIndicator Azure-Sentinel-master/Detections/SymantecProxySG Azure-Sentinel-master/Detections/DeviceFileEvents Azure-Sentinel-master/Detections/SophosXGFirewall Azure-Sentinel-master/Detections/W3CIISLog Azure-Sentinel-master/Detections/VectraAI Azure-Sentinel-master/Detections/SigninLogs Azure-Sentinel-master/Detections/ZoomLogs Azure-Sentinel-master/Detections/AzureActivity Azure-Sentinel-master/Detections/Syslog Azure-Sentinel-master/Detections/DeviceNetworkEvents Azure-Sentinel-master/Detections/TrendMicroXDR Azure-Sentinel-master/Detections/SecurityAlert Azure-Sentinel-master/Detections/AWSCloudTrail Azure-Sentinel-master/Detections/ASimDNS Azure-Sentinel-master/Detections/QualysVM Azure-Sentinel-master/Detections/AzureDiagnostics Azure-Sentinel-master/Detections/DeviceEvents Azure-Sentinel-master/Detections/MultipleDataSources Azure-Sentinel-master/Detections/EsetSMC Azure-Sentinel-master/Detections/OfficeActivity Azure-Sentinel-master/Detections/ASimAuthentication Azure-Sentinel-master/Detections/AWSGuardDuty Azure-Sentinel-master/Detections/AuditLogs Azure-Sentinel-master/Detections/SecurityEvent Azure-Sentinel-master/Detections/AzureFirewall Azure-Sentinel-master/Detections/AlsidForAD Azure-Sentinel-master/Detections/readme.md Azure-Sentinel-master/Detections/LAQueryLogs Azure-Sentinel-master/Detections/DnsEvents Azure-Sentinel-master/Detections/InfobloxNIOS Azure-Sentinel-master/Detections/ProofpointPOD Azure-Sentinel-master/Detections/SymantecVIP Azure-Sentinel-master/Detections/AzureDevOpsAuditing Azure-Sentinel-master/Detections/VMwareCarbonBlack Azure-Sentinel-master/Detections/GitHub Azure-Sentinel-master/Detections/ASimFileEvent Azure-Sentinel-master/Detections/PulseConnectSecure Azure-Sentinel-master/Detections/CommonSecurityLog Azure-Sentinel-master/Detections/DeviceProcessEvents Azure-Sentinel-master/Detections/http_proxy_oab_CL Azure-Sentinel-master/Detections/CiscoUmbrella Azure-Sentinel-master/Detections/SecurityNestedRecommendation Azure-Sentinel-master/Detections/ASimWebSession Azure-Sentinel-master/Detections/Duo Security Azure-Sentinel-master/Detections/AzureAppServices Azure-Sentinel-master/Detections/Cognni Azure-Sentinel-master/Detections/OktaSSO Azure-Sentinel-master/Detections/CyberpionSecurityLogs Azure-Sentinel-master/Detections/QualysVMV2 Azure-Sentinel-master/Detections/ASimNetworkSession Azure-Sentinel-master/Detections/ASimProcess
Azure-Sentinel-master/Hunting Queries/AWSS3 Azure-Sentinel-master/Hunting Queries/WireData Azure-Sentinel-master/Hunting Queries/ThreatIntelligenceIndicator Azure-Sentinel-master/Hunting Queries/W3CIISLog Azure-Sentinel-master/Hunting Queries/Microsoft 365 Defender Azure-Sentinel-master/Hunting Queries/SigninLogs Azure-Sentinel-master/Hunting Queries/ZoomLogs Azure-Sentinel-master/Hunting Queries/AzureActivity Azure-Sentinel-master/Hunting Queries/Syslog Azure-Sentinel-master/Hunting Queries/SecurityAlert Azure-Sentinel-master/Hunting Queries/AWSCloudTrail Azure-Sentinel-master/Hunting Queries/AzureDiagnostics Azure-Sentinel-master/Hunting Queries/BehaviorAnalytics Azure-Sentinel-master/Hunting Queries/MultipleDataSources Azure-Sentinel-master/Hunting Queries/OfficeActivity Azure-Sentinel-master/Hunting Queries/AuditLogs Azure-Sentinel-master/Hunting Queries/SecurityEvent Azure-Sentinel-master/Hunting Queries/readme.md Azure-Sentinel-master/Hunting Queries/LAQueryLogs Azure-Sentinel-master/Hunting Queries/QUERY_TEMPLATE.md Azure-Sentinel-master/Hunting Queries/DnsEvents Azure-Sentinel-master/Hunting Queries/ProofpointPOD Azure-Sentinel-master/Hunting Queries/SQLServer Azure-Sentinel-master/Hunting Queries/AzureDevOpsAuditing Azure-Sentinel-master/Hunting Queries/GitHub Azure-Sentinel-master/Hunting Queries/CommonSecurityLog Azure-Sentinel-master/Hunting Queries/AzureStorage Azure-Sentinel-master/Hunting Queries/ASimProcess
Known API Limitations:
azs = MicrosoftSentinel()
azs.connect()
# Query for our subscriptions
subs = azs.get_subscriptions()
# Display subscriptions (masked names) in a pick list
print("Select a subscription:")
sub = nbwidgets.SelectItem(
item_list=subs['Display Name'].to_list(),
auto_display=True
)
Select a subscription:
VBox(children=(Text(value='CyberSecSOC', description='Filter:', style=DescriptionStyle(description_width='init…
# Get the subscription ID
sub_id = subs[subs['Display Name'] == sub.value].iloc[0]['Subscription ID']
# Query for workspaces in that subscription
workspaces = azs.get_sentinel_workspaces(sub_id = sub_id)
# Display workspaces in a list
print("Select an Microsoft Sentinel Workspace:")
ws = nbwidgets.SelectItem(
item_dict=workspaces,
auto_display=True
)
Finding Microsoft Sentinel Workspaces... Select an Microsoft Sentinel Workspace:
VBox(children=(Text(value='CyberSecuritySOC', description='Filter:', style=DescriptionStyle(description_width=…
hunting_queries = azs.get_hunting_queries()
hunting_queries.head().drop(columns=["id", "etag", "name"])
alert_rules = azs.get_alert_rules()
alert_rules.head().drop(columns=["id", "etag", "name"])
base_dir = path_wgt.value + "/Azure-Sentinel-master"
print('Parsing YAML files of detections and hunting queries...')
detections_df = parse_yaml(parent_dir=base_dir, child_dir="Detections")
hunting_df = parse_yaml(parent_dir=base_dir, child_dir="Hunting Queries")
fusion_df = get_fusion_alerts()
frames = [detections_df, hunting_df]
sentinel_github_df = pd.concat(frames).reset_index()
sentinel_github_df = sentinel_github_df.copy()
sentinel_github_df["DetectionURL"] = sentinel_github_df["DetectionURL"].str.replace(
" ", "%20", regex=True
)
sentinel_github_df["IngestedDate"] = date.today()
# Displaying basic statistics of yaml files
display(HTML("<h3>Microsoft Sentinel Github Stats...</h3>"))
print(
f"""Total Queries in Microsoft Sentinel Github:: {len(sentinel_github_df)}
No of Detections :: {len(detections_df)}
No of Hunting Queries:: {len(hunting_df)}
Total No of Fusion ML Detections:: {fusion_df["name"].nunique()}
"""
)
Parsing YAML files of detections and hunting queries...
Total Queries in Microsoft Sentinel Github:: 1106 No of Detections :: 376 No of Hunting Queries:: 730 Total No of Fusion ML Detections:: 116
result = clean_and_preprocess_data(df=sentinel_github_df)
# Append the Fusion dataset to Pre-procesed result
result = result.append(fusion_df, ignore_index=True)
result.head()
DetectionType | DetectionService | id | name | description | connectorId | dataTypes | query | queryFrequency | queryPeriod | triggerOperator | triggerThreshold | tactics | relevantTechniques | severity | DetectionURL | IngestedDate | Platform | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Analytics | Microsoft Sentinel Community Github | 106813db-679e-4382-a51b-1bfc463befc3 | TI map URL entity to PaloAlto data | 'Identifies a match in PaloAlto data from any ... | PaloAltoNetworks | CommonSecurityLog | \nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14... | 1h | 14d | gt | 0.0 | Impact | NaN | Medium | https://github.com/Azure/Azure-Sentinel/blob/m... | 2022-02-05 | Azure |
1 | Analytics | Microsoft Sentinel Community Github | 106813db-679e-4382-a51b-1bfc463befc3 | TI map URL entity to PaloAlto data | 'Identifies a match in PaloAlto data from any ... | PaloAltoNetworks | CommonSecurityLog | \nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14... | 1h | 14d | gt | 0.0 | Impact | NaN | Medium | https://github.com/Azure/Azure-Sentinel/blob/m... | 2022-02-05 | Windows |
2 | Analytics | Microsoft Sentinel Community Github | 106813db-679e-4382-a51b-1bfc463befc3 | TI map URL entity to PaloAlto data | 'Identifies a match in PaloAlto data from any ... | PaloAltoNetworks | CommonSecurityLog | \nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14... | 1h | 14d | gt | 0.0 | Impact | NaN | Medium | https://github.com/Azure/Azure-Sentinel/blob/m... | 2022-02-05 | Linux |
3 | Analytics | Microsoft Sentinel Community Github | 106813db-679e-4382-a51b-1bfc463befc3 | TI map URL entity to PaloAlto data | 'Identifies a match in PaloAlto data from any ... | ThreatIntelligence | ThreatIntelligenceIndicator | \nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14... | 1h | 14d | gt | 0.0 | Impact | NaN | Medium | https://github.com/Azure/Azure-Sentinel/blob/m... | 2022-02-05 | Windows |
4 | Analytics | Microsoft Sentinel Community Github | 106813db-679e-4382-a51b-1bfc463befc3 | TI map URL entity to PaloAlto data | 'Identifies a match in PaloAlto data from any ... | ThreatIntelligence | ThreatIntelligenceIndicator | \nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14... | 1h | 14d | gt | 0.0 | Impact | NaN | Medium | https://github.com/Azure/Azure-Sentinel/blob/m... | 2022-02-05 | Linux |
mitre_attack_df = get_mitre_matrix_flat()
mitre_attack_df.head()
matrix | tactic | technique | technique_id | technique_id_parsed | |
---|---|---|---|---|---|
0 | mitre-attack | defense-evasion | Resource Forking | T1564.009 | T1564 |
1 | mitre-attack | defense-evasion | Downgrade Attack | T1562.010 | T1562 |
2 | mitre-attack | persistence | Login Items | T1547.015 | T1547 |
3 | mitre-attack | privilege-escalation | Login Items | T1547.015 | T1547 |
4 | mitre-attack | defense-evasion | Reflective Code Loading | T1620 | T1620 |
newdf = pd.merge(
result,
mitre_attack_df,
left_on=["relevantTechniques"],
right_on=["technique_id_parsed"],
how="outer",
)
# Renaming columns
newdf = newdf.rename(
columns={
"matrix": "MITREMatrix",
"platform": "Platform",
"id": "DetectionId",
"name": "DetectionName",
"description": "DetectionDescription",
"connectorId": "ConnectorId",
"dataTypes": "DataTypes",
"severity": "DetectionSeverity",
"tactics": "Tactic",
"relevantTechniques": "TechniqueId",
"technique": "TechniqueName",
"query": "Query",
"queryFrequency": "QueryFrequency",
"queryPeriod": "QueryPeriod",
"triggerOperator": "TriggerOperator",
"triggerThreshold": "TriggerThreshold",
"DetectionURL": "DetectionUrl",
}
)
# Column Seletion and Ordering
columns = [
"MITREMatrix",
"Tactic",
"TechniqueId",
"TechniqueName",
"Platform",
"DetectionType",
"DetectionService",
"DetectionId",
"DetectionName",
"DetectionDescription",
"ConnectorId",
"DataTypes",
"Query",
"QueryFrequency",
"QueryPeriod",
"TriggerOperator",
"TriggerThreshold",
"DetectionSeverity",
"DetectionUrl",
"IngestedDate",
]
newdf = newdf[columns]
# Drop duplicates before exporting
newdf = newdf.loc[newdf.astype(str).drop_duplicates().index]
# Displaying top 10 records
newdf.head()
MITREMatrix | Tactic | TechniqueId | TechniqueName | Platform | DetectionType | DetectionService | DetectionId | DetectionName | DetectionDescription | ConnectorId | DataTypes | Query | QueryFrequency | QueryPeriod | TriggerOperator | TriggerThreshold | DetectionSeverity | DetectionUrl | IngestedDate | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | Impact | NaN | NaN | Azure | Analytics | Microsoft Sentinel Community Github | 106813db-679e-4382-a51b-1bfc463befc3 | TI map URL entity to PaloAlto data | 'Identifies a match in PaloAlto data from any ... | PaloAltoNetworks | CommonSecurityLog | \nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14... | 1h | 14d | gt | 0.0 | Medium | https://github.com/Azure/Azure-Sentinel/blob/m... | 2022-02-05 |
1 | NaN | Impact | NaN | NaN | Windows | Analytics | Microsoft Sentinel Community Github | 106813db-679e-4382-a51b-1bfc463befc3 | TI map URL entity to PaloAlto data | 'Identifies a match in PaloAlto data from any ... | PaloAltoNetworks | CommonSecurityLog | \nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14... | 1h | 14d | gt | 0.0 | Medium | https://github.com/Azure/Azure-Sentinel/blob/m... | 2022-02-05 |
2 | NaN | Impact | NaN | NaN | Linux | Analytics | Microsoft Sentinel Community Github | 106813db-679e-4382-a51b-1bfc463befc3 | TI map URL entity to PaloAlto data | 'Identifies a match in PaloAlto data from any ... | PaloAltoNetworks | CommonSecurityLog | \nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14... | 1h | 14d | gt | 0.0 | Medium | https://github.com/Azure/Azure-Sentinel/blob/m... | 2022-02-05 |
3 | NaN | Impact | NaN | NaN | Windows | Analytics | Microsoft Sentinel Community Github | 106813db-679e-4382-a51b-1bfc463befc3 | TI map URL entity to PaloAlto data | 'Identifies a match in PaloAlto data from any ... | ThreatIntelligence | ThreatIntelligenceIndicator | \nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14... | 1h | 14d | gt | 0.0 | Medium | https://github.com/Azure/Azure-Sentinel/blob/m... | 2022-02-05 |
4 | NaN | Impact | NaN | NaN | Linux | Analytics | Microsoft Sentinel Community Github | 106813db-679e-4382-a51b-1bfc463befc3 | TI map URL entity to PaloAlto data | 'Identifies a match in PaloAlto data from any ... | ThreatIntelligence | ThreatIntelligenceIndicator | \nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14... | 1h | 14d | gt | 0.0 | Medium | https://github.com/Azure/Azure-Sentinel/blob/m... | 2022-02-05 |
#Export the whole dataset
newdf.to_csv('MicrosoftSentinel.csv', header=False, index=False)
#Export the whole dataset with headers
newdf.to_csv('MicrosoftSentinel-with-Headers.csv', index=False)
def get_azure_defender_alerts():
alerts_url = (
"https://docs.microsoft.com/azure/security-center/alerts-reference"
)
list_of_df = pd.read_html(alerts_url)
providers = [
"Windows",
"Linux",
"Azure App Service",
"Azure Containers and Kubernetes clusters",
"SQL Database and Synapse Analytics",
"Open source relational Databases",
"Azure Resource Manager",
"Azure DNS",
"Azure Storage",
"Azure Cosmos DB (Preview)",
"Azure Network Layer",
"Azure Key Vault",
"Azure DDoS Protection",
"Security Incident",
]
for i in range(14):
list_of_df[i]["Provider"] = providers[i]
# Clean-up dataset by renaming some columns
list_of_df[0] = list_of_df[0].rename(columns={"Alert (alert type)": "Alert"})
list_of_df[1] = list_of_df[1].rename(columns={"Alert (alert type)": "Alert"})
list_of_df[2] = list_of_df[2].rename(columns={"Alert (alert type)": "Alert"})
list_of_df[3] = list_of_df[3].rename(columns={"Alert (alert type)": "Alert"})
list_of_df[5] = list_of_df[5].rename(columns={"Alert (alert type)": "Alert"})
list_of_df[6] = list_of_df[6].rename(columns={"Alert (alert type)": "Alert"})
list_of_df[7] = list_of_df[7].rename(columns={"Alert (alert type)": "Alert"})
list_of_df[8] = list_of_df[8].rename(columns={"Alert (alert type)": "Alert"})
list_of_df[11] = list_of_df[11].rename(columns={"Alert (alert type)": "Alert"})
# Merge all the tables
frames = [
list_of_df[0],
list_of_df[1],
list_of_df[2],
list_of_df[3],
list_of_df[4],
list_of_df[5],
list_of_df[6],
list_of_df[7],
list_of_df[8],
list_of_df[9],
list_of_df[10],
list_of_df[11],
list_of_df[12],
list_of_df[13],
]
azdefender_df = pd.concat(frames).reset_index().dropna().drop("index", axis=1)
# Add and Rename columns
azdefender_df["Detection Service"] = (
"Microsoft Defender" + " for " + azdefender_df["Provider"]
)
azdefender_df = azdefender_df.rename(
columns={"MITRE tactics(Learn more)": "Tactic"}
)
azdefender_df[["Alert", "Description", "Severity", "Provider", "Tactic"]]
azdefender_df["DetectionURL"] = alerts_url
azdefender_df["connectorId"] = "AzureSecurityCenter"
azdefender_df["dataTypes"] = "SecurityAlert (ASC)"
return azdefender_df
def get_azure_ipc_alerts():
alerts_url = "https://docs.microsoft.com/azure/active-directory/identity-protection/concept-identity-protection-risks"
list_of_df = pd.read_html(alerts_url)
# Merge All dataframes
frames = (list_of_df[0], list_of_df[1], list_of_df[2])
aip_df = pd.concat(frames).dropna().reset_index().drop("index", axis=1)
# Add and Rename columns
aip_df["Tactic"] = "N.A."
aip_df["Severity"] = "N.A."
aip_df["Provider"] = "N.A."
aip_df["Detection Service"] = "Azure Identity Protection Center (IPC)"
aip_df = aip_df.rename(columns={"Risk detection": "Alert"}).drop(
"Detection type", axis=1
)
aip_df["connectorId"] = "AzureActiveDirectoryIdentityProtection"
aip_df["dataTypes"] = "SecurityAlert (IPC)"
aip_df["DetectionURL"] = alerts_url
return aip_df
def get_azure_defender_identity_alerts():
alerts_url = "https://docs.microsoft.com/azure-advanced-threat-protection/suspicious-activity-guide?tabs=external"
list_of_df = pd.read_html(alerts_url)
atp_df = list_of_df[0].reset_index().dropna().drop("index", axis=1)
atp_df["Description"] = "N.A."
atp_df["Provider"] = "N.A."
atp_df = atp_df.rename(
columns={"Security alert name": "Alert", "MITRE ATT&CK Matrix™": "Tactic"}
).drop("Unique external ID", axis=1)
atp_df["Detection Service"] = "Microsoft Defender for Identity"
atp_df = atp_df[
["Alert", "Description", "Tactic", "Severity", "Provider", "Detection Service"]
]
atp_df["connectorId"] = "AzureAdvancedThreatProtection"
atp_df["dataTypes"] = "SecurityAlert (AATP)"
atp_df["DetectionURL"] = alerts_url
return atp_df
def get_mcas_alerts():
alerts_url = (
"https://docs.microsoft.com/cloud-app-security/investigate-anomaly-alerts"
)
session = HTMLSession()
r = session.get(alerts_url)
mcas_df = pd.DataFrame(
re.findall(r"<h3 id=.*>(.*)</h3>", r.text), columns=["Alert"]
)
mcas_df["Description"] = "N.A."
mcas_df["Tactic"] = "N.A."
for i in range(6):
mcas_df["Tactic"][i] = "InitialAccess"
for i in range(6, 9):
mcas_df["Tactic"][i] = "Execution"
for i in range(9, 13):
mcas_df["Tactic"][i] = "Persistence"
mcas_df["Tactic"][13] = "PrivilegeEscalation"
mcas_df["Tactic"][14] = "CredentialAccess"
for i in range(15, 18):
mcas_df["Tactic"][i] = "Collection"
for i in range(18, 21):
mcas_df["Tactic"][i] = "Exfiltration"
for i in range(21, 24):
mcas_df["Tactic"][i] = "Impact"
mcas_df["Severity"] = "N.A."
mcas_df["Provider"] = "N.A."
mcas_df["Detection Service"] = "Microsoft Defender for Cloud Apps"
mcas_df["DetectionURL"] = alerts_url
mcas_df["connectorId"] = "MicrosoftCloudAppSecurity"
mcas_df["dataTypes"] = "SecurityAlert (MCAS) | McasShadowItReporting"
return mcas_df
az_defender_alerts = get_azure_defender_alerts()
#Display top 5 records
az_defender_alerts.head()
Alert | Description | Tactic | Severity | Provider | Detection Service | DetectionURL | connectorId | dataTypes | |
---|---|---|---|---|---|---|---|---|---|
0 | A logon from a malicious IP has been detected.... | A successful remote authentication for the acc... | - | High | Windows | Microsoft Defender for Windows | https://docs.microsoft.com/azure/security-cent... | AzureSecurityCenter | SecurityAlert (ASC) |
1 | Addition of Guest account to Local Administrat... | Analysis of host data has detected the additio... | - | Medium | Windows | Microsoft Defender for Windows | https://docs.microsoft.com/azure/security-cent... | AzureSecurityCenter | SecurityAlert (ASC) |
2 | An event log was cleared | Machine logs indicate a suspicious event log c... | - | Informational | Windows | Microsoft Defender for Windows | https://docs.microsoft.com/azure/security-cent... | AzureSecurityCenter | SecurityAlert (ASC) |
3 | Antimalware Action Failed | Microsoft Antimalware has encountered an error... | - | Medium | Windows | Microsoft Defender for Windows | https://docs.microsoft.com/azure/security-cent... | AzureSecurityCenter | SecurityAlert (ASC) |
4 | Antimalware Action Taken | Microsoft Antimalware for Azure has taken an a... | - | Medium | Windows | Microsoft Defender for Windows | https://docs.microsoft.com/azure/security-cent... | AzureSecurityCenter | SecurityAlert (ASC) |
az_ipc_alerts = get_azure_ipc_alerts()
#Display top 5 records
az_ipc_alerts.head()
Alert | Description | Tactic | Severity | Provider | Detection Service | connectorId | dataTypes | DetectionURL | |
---|---|---|---|---|---|---|---|---|---|
0 | Anonymous IP address | This risk detection type indicates sign-ins fr... | N.A. | N.A. | N.A. | Azure Identity Protection Center (IPC) | AzureActiveDirectoryIdentityProtection | SecurityAlert (IPC) | https://docs.microsoft.com/azure/active-direct... |
1 | Atypical travel | This risk detection type identifies two sign-i... | N.A. | N.A. | N.A. | Azure Identity Protection Center (IPC) | AzureActiveDirectoryIdentityProtection | SecurityAlert (IPC) | https://docs.microsoft.com/azure/active-direct... |
2 | Anomalous Token | This detection indicates that there are abnorm... | N.A. | N.A. | N.A. | Azure Identity Protection Center (IPC) | AzureActiveDirectoryIdentityProtection | SecurityAlert (IPC) | https://docs.microsoft.com/azure/active-direct... |
3 | Token Issuer Anomaly | This risk detection indicates the SAML token i... | N.A. | N.A. | N.A. | Azure Identity Protection Center (IPC) | AzureActiveDirectoryIdentityProtection | SecurityAlert (IPC) | https://docs.microsoft.com/azure/active-direct... |
4 | Malware linked IP address | This risk detection type indicates sign-ins fr... | N.A. | N.A. | N.A. | Azure Identity Protection Center (IPC) | AzureActiveDirectoryIdentityProtection | SecurityAlert (IPC) | https://docs.microsoft.com/azure/active-direct... |
az_defender_for_identity_alerts = get_azure_defender_identity_alerts()
#Display top 5 records
az_defender_for_identity_alerts.head()
Alert | Description | Tactic | Severity | Provider | Detection Service | connectorId | dataTypes | DetectionURL | |
---|---|---|---|---|---|---|---|---|---|
0 | Account enumeration reconnaissance | N.A. | Discovery | Medium | N.A. | Microsoft Defender for Identity | AzureAdvancedThreatProtection | SecurityAlert (AATP) | https://docs.microsoft.com/azure-advanced-thre... |
1 | Active Directory attributes reconnaissance (LDAP) | N.A. | Discovery | Medium | N.A. | Microsoft Defender for Identity | AzureAdvancedThreatProtection | SecurityAlert (AATP) | https://docs.microsoft.com/azure-advanced-thre... |
2 | Data exfiltration over SMB | N.A. | Exfiltration,Lateral movement,Command and control | High | N.A. | Microsoft Defender for Identity | AzureAdvancedThreatProtection | SecurityAlert (AATP) | https://docs.microsoft.com/azure-advanced-thre... |
3 | Exchange Server Remote Code Execution (CVE-202... | N.A. | Lateral movement | High | N.A. | Microsoft Defender for Identity | AzureAdvancedThreatProtection | SecurityAlert (AATP) | https://docs.microsoft.com/azure-advanced-thre... |
4 | Honeytoken activity | N.A. | Credential access,Discovery | Medium | N.A. | Microsoft Defender for Identity | AzureAdvancedThreatProtection | SecurityAlert (AATP) | https://docs.microsoft.com/azure-advanced-thre... |
mcas_df = get_mcas_alerts()
#Display top 5 records
mcas_df.head()
Alert | Description | Tactic | Severity | Provider | Detection Service | DetectionURL | connectorId | dataTypes | |
---|---|---|---|---|---|---|---|---|---|
0 | Please rate your experience | N.A. | InitialAccess | N.A. | N.A. | Microsoft Defender for Cloud Apps | https://docs.microsoft.com/cloud-app-security/... | MicrosoftCloudAppSecurity | SecurityAlert (MCAS) | McasShadowItReporting |
1 | Activity from anonymous IP address | N.A. | InitialAccess | N.A. | N.A. | Microsoft Defender for Cloud Apps | https://docs.microsoft.com/cloud-app-security/... | MicrosoftCloudAppSecurity | SecurityAlert (MCAS) | McasShadowItReporting |
2 | Activity from infrequent country | N.A. | InitialAccess | N.A. | N.A. | Microsoft Defender for Cloud Apps | https://docs.microsoft.com/cloud-app-security/... | MicrosoftCloudAppSecurity | SecurityAlert (MCAS) | McasShadowItReporting |
3 | Activity from suspicious IP addresses | N.A. | InitialAccess | N.A. | N.A. | Microsoft Defender for Cloud Apps | https://docs.microsoft.com/cloud-app-security/... | MicrosoftCloudAppSecurity | SecurityAlert (MCAS) | McasShadowItReporting |
4 | Impossible Travel | N.A. | InitialAccess | N.A. | N.A. | Microsoft Defender for Cloud Apps | https://docs.microsoft.com/cloud-app-security/... | MicrosoftCloudAppSecurity | SecurityAlert (MCAS) | McasShadowItReporting |
frames = [az_defender_alerts, az_ipc_alerts, az_defender_for_identity_alerts, mcas_df]
msft_df = pd.concat(frames)
#Display top 5 records
msft_df.head()
Alert | Description | Tactic | Severity | Provider | Detection Service | DetectionURL | connectorId | dataTypes | |
---|---|---|---|---|---|---|---|---|---|
0 | A logon from a malicious IP has been detected.... | A successful remote authentication for the acc... | - | High | Windows | Microsoft Defender for Windows | https://docs.microsoft.com/azure/security-cent... | AzureSecurityCenter | SecurityAlert (ASC) |
1 | Addition of Guest account to Local Administrat... | Analysis of host data has detected the additio... | - | Medium | Windows | Microsoft Defender for Windows | https://docs.microsoft.com/azure/security-cent... | AzureSecurityCenter | SecurityAlert (ASC) |
2 | An event log was cleared | Machine logs indicate a suspicious event log c... | - | Informational | Windows | Microsoft Defender for Windows | https://docs.microsoft.com/azure/security-cent... | AzureSecurityCenter | SecurityAlert (ASC) |
3 | Antimalware Action Failed | Microsoft Antimalware has encountered an error... | - | Medium | Windows | Microsoft Defender for Windows | https://docs.microsoft.com/azure/security-cent... | AzureSecurityCenter | SecurityAlert (ASC) |
4 | Antimalware Action Taken | Microsoft Antimalware for Azure has taken an a... | - | Medium | Windows | Microsoft Defender for Windows | https://docs.microsoft.com/azure/security-cent... | AzureSecurityCenter | SecurityAlert (ASC) |
#Export the whole dataset
msft_df.to_csv('MSFTAlerts.csv', header=False, index=False)
#Export the whole dataset with headers
msft_df.to_csv('MSFTAlerts-with-Headers.csv', index=False)
If you are using Jupyterlab, check out the project docs to install relevant extensions.
Install the qgrid-jupyterlab extension and enable:
jupyter labextension install qgrid2
# list of Valid Tactics Values
Tactics = [
"InitialAccess",
"Execution",
"Persistence",
"PrivilegeEscalation",
"DefenseEvasion",
"CredentialAccess",
"Discovery",
"LateralMovement",
"Collection",
"CommandAndControl",
"Exfiltration",
"Impact",
]
columns = [
"Tactic",
"TechniqueId",
"Platform",
"DetectionType",
"DetectionName",
"ConnectorId",
"DataTypes",
]
df = newdf[columns].rename_axis(None)
qgrid_widget = qgrid.show_grid(df, show_toolbar=True)
qgrid_widget
QgridWidget(grid_options={'fullWidthRows': True, 'syncColumnCellResize': True, 'forceFitColumns': True, 'defau…
heatmap = newdf[newdf["Tactic"].isin(Tactics)]
heatmap= heatmap.loc[heatmap[["ConnectorId","Tactic","DetectionName"]].astype(str).drop_duplicates().index]
# Plot HeatMap
pd.crosstab(heatmap["ConnectorId"], heatmap["Tactic"]).style.background_gradient(
cmap="PuBuGn"
)
Tactic | Collection | CommandAndControl | CredentialAccess | DefenseEvasion | Discovery | Execution | Exfiltration | Impact | InitialAccess | LateralMovement | Persistence | PrivilegeEscalation |
---|---|---|---|---|---|---|---|---|---|---|---|---|
ConnectorId | ||||||||||||
AIVectraDetect | 4 | 5 | 4 | 0 | 4 | 0 | 4 | 4 | 0 | 5 | 0 | 0 |
AWS | 0 | 6 | 3 | 5 | 2 | 3 | 0 | 1 | 8 | 1 | 4 | 7 |
AlsidForAD | 0 | 0 | 11 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Azure Active Directory | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
AzureActiveDirectory | 3 | 5 | 30 | 4 | 4 | 2 | 0 | 8 | 55 | 5 | 23 | 11 |
AzureActiveDirectoryIdentityProtection | 11 | 0 | 0 | 5 | 0 | 0 | 40 | 30 | 51 | 15 | 5 | 1 |
AzureActivity | 0 | 4 | 7 | 4 | 1 | 2 | 0 | 15 | 2 | 6 | 4 | 3 |
AzureFirewall | 0 | 16 | 3 | 0 | 1 | 2 | 0 | 3 | 3 | 1 | 2 | 0 |
AzureKeyVault | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 |
AzureMonitor | 1 | 0 | 0 | 6 | 0 | 1 | 0 | 0 | 0 | 0 | 6 | 0 |
AzureMonitor(IIS) | 1 | 6 | 3 | 0 | 1 | 3 | 1 | 1 | 18 | 0 | 6 | 5 |
AzureMonitor(Query Audit) | 6 | 0 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 0 |
AzureMonitor(VMInsights) | 0 | 19 | 3 | 0 | 0 | 2 | 2 | 3 | 3 | 0 | 2 | 0 |
AzureMonitor(WindowsEventLogs) | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 6 | 5 |
AzureMonitor(WireData) | 0 | 4 | 0 | 0 | 0 | 0 | 1 | 2 | 1 | 0 | 0 | 0 |
AzureNetworkWatcher | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 1 | 0 | 0 | 0 |
AzureSecurityCenter | 5 | 1 | 0 | 0 | 5 | 0 | 0 | 8 | 5 | 6 | 5 | 0 |
AzureSentinel | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
Barracuda | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
BehaviorAnalytics | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 5 | 2 | 4 | 2 |
CEF | 1 | 2 | 0 | 0 | 0 | 1 | 1 | 2 | 2 | 0 | 2 | 0 |
CheckPoint | 1 | 2 | 0 | 0 | 0 | 1 | 1 | 2 | 3 | 0 | 2 | 0 |
CiscoASA | 1 | 18 | 4 | 0 | 2 | 2 | 2 | 5 | 5 | 0 | 2 | 0 |
CiscoUmbrellaDataConnector | 0 | 9 | 0 | 1 | 0 | 0 | 1 | 0 | 2 | 0 | 0 | 0 |
CognniSentinelDataConnector | 15 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
CustomConnector | 7 | 7 | 10 | 19 | 3 | 16 | 8 | 10 | 16 | 2 | 21 | 2 |
CyberpionSecurityLogs | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
DNS | 0 | 24 | 3 | 0 | 2 | 2 | 6 | 5 | 3 | 0 | 2 | 0 |
EsetSMC | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 |
F5 | 1 | 2 | 0 | 0 | 0 | 1 | 1 | 2 | 2 | 0 | 2 | 0 |
Fortinet | 1 | 4 | 0 | 0 | 0 | 1 | 1 | 3 | 5 | 1 | 2 | 0 |
InfobloxNIOS | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
Microsoft365Defender | 13 | 0 | 0 | 0 | 18 | 76 | 43 | 20 | 0 | 1 | 48 | 0 |
MicrosoftCloudAppSecurity | 15 | 1 | 0 | 5 | 5 | 0 | 41 | 31 | 49 | 20 | 10 | 0 |
MicrosoftDefenderAdvancedThreatProtection | 1 | 7 | 1 | 0 | 1 | 4 | 0 | 0 | 3 | 3 | 8 | 3 |
MicrosoftThreatProtection | 3 | 12 | 3 | 3 | 1 | 11 | 0 | 3 | 3 | 3 | 12 | 1 |
N.A. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
Office365 | 13 | 12 | 5 | 4 | 2 | 5 | 8 | 6 | 13 | 0 | 11 | 3 |
OfficeATP | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
OktaSSO | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
PaloAltoNetworks | 1 | 22 | 5 | 0 | 3 | 5 | 3 | 9 | 8 | 1 | 2 | 1 |
ProofpointPOD | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 0 | 15 | 0 | 0 | 0 |
PulseConnectSecure | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
QualysVulnerabilityManagement | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 |
SecurityEvents | 13 | 11 | 17 | 12 | 7 | 29 | 4 | 9 | 12 | 13 | 24 | 18 |
SophosXGFirewall | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
SymantecProxySG | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
SymantecVIP | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Syslog | 0 | 4 | 7 | 2 | 1 | 9 | 1 | 4 | 5 | 0 | 7 | 0 |
ThreatIntelligence | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 41 | 2 | 0 | 0 | 0 |
ThreatIntelligenceTaxii | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 40 | 2 | 0 | 0 | 0 |
TrendMicro | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
VMwareCarbonBlack | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 |
WAF | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 6 | 0 | 0 | 0 |
WindowsFirewall | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 2 | 2 | 0 | 1 | 0 |
WindowsSecurityEvents | 3 | 1 | 4 | 6 | 0 | 5 | 0 | 2 | 3 | 4 | 11 | 7 |
Zscaler | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
Please note, these may not correctly display all the gaps, as there are various columns populated as 0 even though techniques do not fall under Tactics since it is Heatmap for all Tactics against all Techniques.
For better gap analysis, look at ATT&CK navigator visualization section.
heatmap = newdf[newdf["Tactic"].isin(Tactics)]
heatmap= heatmap[["Tactic","TechniqueName","DetectionName"]].drop_duplicates().reset_index()
# Plot HeatMap
pd.crosstab(heatmap["TechniqueName"], heatmap["Tactic"]).style.background_gradient(
cmap="PuBuGn"
)
Tactic | Collection | CommandAndControl | CredentialAccess | DefenseEvasion | Discovery | Execution | Exfiltration | Impact | InitialAccess | LateralMovement | Persistence | PrivilegeEscalation |
---|---|---|---|---|---|---|---|---|---|---|---|---|
TechniqueName | ||||||||||||
/etc/passwd and /etc/shadow | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Abuse Elevation Control Mechanism | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 |
Access Token Manipulation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 |
Accessibility Features | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Account Access Removal | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 |
Account Discovery | 3 | 0 | 0 | 0 | 7 | 2 | 0 | 0 | 1 | 1 | 0 | 1 |
Account Manipulation | 2 | 0 | 2 | 9 | 0 | 2 | 0 | 7 | 5 | 0 | 61 | 27 |
Active Scanning | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
Active Setup | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Add Office 365 Global Administrator Role | 2 | 0 | 2 | 9 | 0 | 2 | 0 | 7 | 5 | 0 | 61 | 27 |
Add-ins | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Additional Cloud Credentials | 2 | 0 | 2 | 9 | 0 | 2 | 0 | 7 | 5 | 0 | 61 | 27 |
AppCert DLLs | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
AppInit DLLs | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
AppleScript | 3 | 0 | 0 | 3 | 2 | 20 | 0 | 0 | 0 | 0 | 8 | 0 |
Application Access Token | 0 | 0 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Application Exhaustion Flood | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | 5 | 0 | 0 | 0 |
Application Layer Protocol | 0 | 22 | 0 | 0 | 1 | 3 | 3 | 1 | 4 | 1 | 0 | 0 |
Application Shimming | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Application or System Exploitation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | 5 | 0 | 0 | 0 |
Asymmetric Cryptography | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Asynchronous Procedure Call | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
At (Linux) | 0 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 9 | 1 |
At (Windows) | 0 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 9 | 1 |
Authentication Package | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Automated Collection | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Automated Exfiltration | 13 | 0 | 0 | 0 | 0 | 0 | 21 | 0 | 10 | 5 | 0 | 0 |
Bash History | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Bidirectional Communication | 0 | 5 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
Binary Padding | 0 | 0 | 0 | 4 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
Boot or Logon Autostart Execution | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Boot or Logon Initialization Scripts | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 3 | 0 |
Bootkit | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Browser Extensions | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Brute Force | 0 | 0 | 56 | 0 | 0 | 0 | 0 | 0 | 9 | 5 | 0 | 0 |
Bypass User Account Control | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 |
Cached Domain Credentials | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Change Default File Association | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Clear Command History | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Clear Linux or Mac System Logs | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Clear Windows Event Logs | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Cloud Account | 4 | 0 | 0 | 0 | 7 | 2 | 0 | 0 | 2 | 4 | 12 | 1 |
Cloud Accounts | 11 | 4 | 10 | 11 | 2 | 0 | 36 | 40 | 98 | 20 | 40 | 32 |
Cloud Groups | 2 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Cloud Instance Metadata API | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Code Repositories | 10 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 |
Command and Scripting Interpreter | 3 | 0 | 0 | 3 | 2 | 20 | 0 | 0 | 0 | 0 | 8 | 0 |
Compile After Delivery | 0 | 0 | 0 | 4 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
Component Firmware | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Component Object Model Hijacking | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Compromise Accounts | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 2 | 0 | 0 |
Compromise Client Software Binary | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 |
Compromise Hardware Supply Chain | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 |
Compromise Software Dependencies and Development Tools | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 |
Compromise Software Supply Chain | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 |
Confluence | 10 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 |
Container API | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Container Orchestration Job | 0 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 9 | 1 |
Create Account | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 3 | 12 | 0 |
Create Cloud Instance | 0 | 0 | 0 | 7 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Create Process with Token | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 |
Create Snapshot | 0 | 0 | 0 | 7 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Credential Stuffing | 0 | 0 | 56 | 0 | 0 | 0 | 0 | 0 | 9 | 5 | 0 | 0 |
Credentials In Files | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Credentials from Password Stores | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Credentials from Web Browsers | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Credentials in Registry | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Cron | 0 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 9 | 1 |
DCSync | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
DNS | 0 | 22 | 0 | 0 | 1 | 3 | 3 | 1 | 4 | 1 | 0 | 0 |
DNS Calculation | 0 | 14 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 |
Data Destruction | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 15 | 5 | 0 | 0 | 0 |
Data Encrypted for Impact | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 5 | 0 | 0 | 0 |
Data Staged | 2 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Data Transfer Size Limits | 0 | 1 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 0 |
Data from Cloud Storage Object | 24 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 |
Data from Information Repositories | 10 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 |
Data from Local System | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Dead Drop Resolver | 0 | 5 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
Default Accounts | 11 | 4 | 10 | 11 | 2 | 0 | 36 | 40 | 98 | 20 | 40 | 32 |
Delete Cloud Instance | 0 | 0 | 0 | 7 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Deobfuscate/Decode Files or Information | 0 | 0 | 0 | 3 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
Direct Network Flood | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 2 | 0 | 0 | 0 | 0 |
Disable Cloud Logs | 0 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 0 |
Disable Windows Event Logging | 0 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 0 |
Disable or Modify Cloud Firewall | 0 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 0 |
Disable or Modify System Firewall | 0 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 0 |
Disable or Modify Tools | 0 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 0 |
Disk Content Wipe | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
Disk Structure Wipe | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
Disk Wipe | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
Distributed Component Object Model | 0 | 2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 6 | 2 | 0 |
Domain Account | 4 | 0 | 0 | 0 | 7 | 2 | 0 | 0 | 2 | 4 | 12 | 1 |
Domain Accounts | 11 | 4 | 10 | 11 | 2 | 0 | 36 | 40 | 98 | 20 | 40 | 32 |
Domain Fronting | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Domain Generation Algorithms | 0 | 14 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 |
Domain Groups | 2 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Domain Policy Modification | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Domain Trust Discovery | 2 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Domain Trust Modification | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Double File Extension | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Downgrade Attack | 0 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 0 |
Drive-by Compromise | 0 | 3 | 0 | 0 | 0 | 3 | 0 | 0 | 4 | 0 | 0 | 0 |
Dynamic Resolution | 0 | 14 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 |
Dynamic-link Library Injection | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Elevated Execution with Prompt | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 |
Email Account | 3 | 0 | 0 | 0 | 7 | 2 | 0 | 0 | 1 | 1 | 0 | 1 |
Email Accounts | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 2 | 0 | 0 |
Email Collection | 12 | 0 | 0 | 0 | 1 | 1 | 4 | 0 | 2 | 0 | 2 | 1 |
Email Forwarding Rule | 12 | 0 | 0 | 0 | 1 | 1 | 4 | 0 | 2 | 0 | 2 | 1 |
Email Hiding Rules | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Emond | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Encrypted Channel | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Endpoint Denial of Service | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | 5 | 0 | 0 | 0 |
Event Triggered Execution | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Exchange Email Delegate Permissions | 2 | 0 | 2 | 9 | 0 | 2 | 0 | 7 | 5 | 0 | 61 | 27 |
Exfiltration Over Alternative Protocol | 0 | 5 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 0 |
Exfiltration Over Asymmetric Encrypted Non-C2 Protocol | 0 | 5 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 0 |
Exfiltration Over Bluetooth | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 0 | 0 | 0 | 0 | 0 |
Exfiltration Over Other Network Medium | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 0 | 0 | 0 | 0 | 0 |
Exfiltration Over Symmetric Encrypted Non-C2 Protocol | 0 | 5 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 0 |
Exfiltration Over Unencrypted/Obfuscated Non-C2 Protocol | 0 | 5 | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 0 | 0 | 0 |
Exfiltration Over Web Service | 0 | 1 | 0 | 0 | 0 | 0 | 17 | 0 | 5 | 0 | 0 | 0 |
Exfiltration to Cloud Storage | 0 | 1 | 0 | 0 | 0 | 0 | 17 | 0 | 5 | 0 | 0 | 0 |
Exfiltration to Code Repository | 0 | 1 | 0 | 0 | 0 | 0 | 17 | 0 | 5 | 0 | 0 | 0 |
Exploit Public-Facing Application | 1 | 0 | 0 | 0 | 1 | 3 | 0 | 4 | 36 | 1 | 0 | 1 |
Exploitation for Client Execution | 0 | 3 | 0 | 0 | 0 | 10 | 0 | 1 | 6 | 1 | 0 | 1 |
Exploitation for Privilege Escalation | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 2 |
Exploitation of Remote Services | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 4 | 0 | 1 |
External Proxy | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
External Remote Services | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
Extra Window Memory Injection | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Fallback Channels | 0 | 11 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 |
Fast Flux DNS | 0 | 14 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 |
File Deletion | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
File Transfer Protocols | 0 | 22 | 0 | 0 | 1 | 3 | 3 | 1 | 4 | 1 | 0 | 0 |
Group Policy Modification | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Group Policy Preferences | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
HTML Smuggling | 0 | 0 | 0 | 4 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
Hardware Additions | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
Hidden File System | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Hidden Files and Directories | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Hidden Users | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Hidden Window | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Hide Artifacts | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
IIS Components | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 6 | 2 |
Image File Execution Options Injection | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Impair Command History Logging | 0 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 0 |
Impair Defenses | 0 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 0 |
Indicator Blocking | 0 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 0 |
Indicator Removal from Tools | 0 | 0 | 0 | 4 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
Indicator Removal on Host | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Ingress Tool Transfer | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Internal Proxy | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Internal Spearphishing | 0 | 0 | 0 | 0 | 0 | 0 | 10 | 0 | 10 | 10 | 0 | 0 |
Invalid Code Signature | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
JavaScript | 3 | 0 | 0 | 3 | 2 | 20 | 0 | 0 | 0 | 0 | 8 | 0 |
Kernel Modules and Extensions | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Keychain | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
LC_LOAD_DYLIB Addition | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
LSA Secrets | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
LSASS Driver | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
LSASS Memory | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Lateral Tool Transfer | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 2 | 9 | 0 | 0 |
Launchctl | 0 | 0 | 2 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Launchd | 0 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 9 | 1 |
Local Account | 4 | 0 | 0 | 0 | 7 | 2 | 0 | 0 | 2 | 4 | 12 | 1 |
Local Accounts | 11 | 4 | 10 | 11 | 2 | 0 | 36 | 40 | 98 | 20 | 40 | 32 |
Local Data Staging | 2 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Local Email Collection | 12 | 0 | 0 | 0 | 1 | 1 | 4 | 0 | 2 | 0 | 2 | 1 |
Local Groups | 2 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Login Items | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Logon Script (Mac) | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 3 | 0 |
Logon Script (Windows) | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 3 | 0 |
Mail Protocols | 0 | 22 | 0 | 0 | 1 | 3 | 3 | 1 | 4 | 1 | 0 | 0 |
Make and Impersonate Token | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 |
Malicious File | 0 | 1 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 |
Malicious Image | 0 | 1 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 |
Malicious Link | 0 | 1 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 |
Masquerade Task or Service | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Masquerading | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Match Legitimate Name or Location | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Modify Cloud Compute Infrastructure | 0 | 0 | 0 | 7 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Multi-hop Proxy | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
NTDS | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
NTFS File Attributes | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Netsh Helper DLL | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Network Denial of Service | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 2 | 0 | 0 | 0 | 0 |
Network Device CLI | 3 | 0 | 0 | 3 | 2 | 20 | 0 | 0 | 0 | 0 | 8 | 0 |
Network Logon Script | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 3 | 0 |
Network Service Scanning | 0 | 1 | 0 | 0 | 8 | 0 | 0 | 2 | 0 | 1 | 0 | 0 |
Network Share Connection Removal | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Network Sniffing | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Non-Standard Port | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
OS Credential Dumping | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
OS Exhaustion Flood | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | 5 | 0 | 0 | 0 |
Obfuscated Files or Information | 0 | 0 | 0 | 4 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
Office Application Startup | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Office Template Macros | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Office Test | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
One-Way Communication | 0 | 5 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
Outlook Forms | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Outlook Home Page | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Outlook Rules | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Parent PID Spoofing | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 |
Pass the Hash | 0 | 0 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Pass the Ticket | 0 | 0 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Password Cracking | 0 | 0 | 56 | 0 | 0 | 0 | 0 | 0 | 9 | 5 | 0 | 0 |
Password Guessing | 0 | 0 | 56 | 0 | 0 | 0 | 0 | 0 | 9 | 5 | 0 | 0 |
Password Managers | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Password Policy Discovery | 2 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Password Spraying | 0 | 0 | 56 | 0 | 0 | 0 | 0 | 0 | 9 | 5 | 0 | 0 |
Permission Groups Discovery | 2 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Phishing | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 |
Plist Modification | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Port Monitors | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Portable Executable Injection | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
PowerShell | 3 | 0 | 0 | 3 | 2 | 20 | 0 | 0 | 0 | 0 | 8 | 0 |
PowerShell Profile | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Pre-OS Boot | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Print Processors | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Private Keys | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Proc Filesystem | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Proc Memory | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Process Doppelgänging | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Process Hollowing | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Process Injection | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Proxy | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Ptrace System Calls | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Python | 3 | 0 | 0 | 3 | 2 | 20 | 0 | 0 | 0 | 0 | 8 | 0 |
RC Scripts | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 3 | 0 |
ROMMONkit | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Re-opened Applications | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Reflection Amplification | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 2 | 0 | 0 | 0 | 0 |
Registry Run Keys / Startup Folder | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Remote Access Software | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 4 | 0 |
Remote Data Staging | 2 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Remote Desktop Protocol | 0 | 2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 6 | 2 | 0 |
Remote Email Collection | 12 | 0 | 0 | 0 | 1 | 1 | 4 | 0 | 2 | 0 | 2 | 1 |
Remote Services | 0 | 2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 6 | 2 | 0 |
Remote System Discovery | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Rename System Utilities | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Resource Forking | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Resource Hijacking | 0 | 1 | 0 | 0 | 0 | 2 | 0 | 33 | 6 | 0 | 7 | 5 |
Revert Cloud Instance | 0 | 0 | 0 | 7 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Right-to-Left Override | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Rogue Domain Controller | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Run Virtual Instance | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
SID-History Injection | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 |
SMB/Windows Admin Shares | 0 | 2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 6 | 2 | 0 |
SQL Stored Procedures | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 6 | 2 |
SSH | 0 | 2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 6 | 2 | 0 |
SSH Authorized Keys | 2 | 0 | 2 | 9 | 0 | 2 | 0 | 7 | 5 | 0 | 61 | 27 |
Safe Mode Boot | 0 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | 0 |
Scanning IP Blocks | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
Scheduled Task | 0 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 9 | 1 |
Scheduled Task/Job | 0 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 9 | 1 |
Screensaver | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Security Account Manager | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Security Support Provider | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Securityd Memory | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Server Software Component | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 6 | 2 |
Service Execution | 0 | 0 | 2 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
Service Exhaustion Flood | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | 5 | 0 | 0 | 0 |
Service Stop | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
Setuid and Setgid | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 |
Sharepoint | 10 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 |
Shortcut Modification | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Social Media Accounts | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 2 | 0 | 0 |
Software Deployment Tools | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
Software Packing | 0 | 0 | 0 | 4 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
Space after Filename | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Spearphishing Attachment | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 |
Spearphishing Link | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 |
Spearphishing via Service | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 |
Startup Items | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 3 | 0 |
Steal Application Access Token | 0 | 0 | 5 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Steganography | 0 | 0 | 0 | 4 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
Sudo and Sudo Caching | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 |
Supply Chain Compromise | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 |
Symmetric Cryptography | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
System Firmware | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
System Services | 0 | 0 | 2 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
System Shutdown/Reboot | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 |
Systemd Timers | 0 | 0 | 0 | 0 | 0 | 9 | 0 | 0 | 0 | 0 | 9 | 1 |
TFTP Boot | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Thread Execution Hijacking | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Thread Local Storage | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Time Providers | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
Timestomp | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Token Impersonation/Theft | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 |
Traffic Duplication | 13 | 0 | 0 | 0 | 0 | 0 | 21 | 0 | 10 | 5 | 0 | 0 |
Transfer Data to Cloud Account | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 |
Transport Agent | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 6 | 2 |
Trap | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Trusted Relationship | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 4 | 0 | 1 | 0 |
Unix Shell | 3 | 0 | 0 | 3 | 2 | 20 | 0 | 0 | 0 | 0 | 8 | 0 |
Unix Shell Configuration Modification | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Unsecured Credentials | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Unused/Unsupported Cloud Regions | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Use Alternate Authentication Material | 0 | 0 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
User Execution | 0 | 1 | 0 | 0 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 |
VBA Stomping | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
VDSO Hijacking | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
VNC | 0 | 2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 6 | 2 | 0 |
Valid Accounts | 11 | 4 | 10 | 11 | 2 | 0 | 36 | 40 | 98 | 20 | 40 | 32 |
Visual Basic | 3 | 0 | 0 | 3 | 2 | 20 | 0 | 0 | 0 | 0 | 8 | 0 |
Vulnerability Scanning | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
Web Protocols | 0 | 22 | 0 | 0 | 1 | 3 | 3 | 1 | 4 | 1 | 0 | 0 |
Web Service | 0 | 5 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
Web Session Cookie | 0 | 0 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Web Shell | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 6 | 2 |
Windows Command Shell | 3 | 0 | 0 | 3 | 2 | 20 | 0 | 0 | 0 | 0 | 8 | 0 |
Windows Credential Manager | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Windows Management Instrumentation | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Windows Management Instrumentation Event Subscription | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Windows Remote Management | 0 | 2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 6 | 2 | 0 |
Winlogon Helper DLL | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
XDG Autostart Entries | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 |
def generate_navigator_layerfiles(inputfile:str, outputdir:str) -> IO[str]:
# Read csv file as input
with open(inputfile, "r") as f:
reader = csv.DictReader(f)
a = list(reader)
# Creating set of Platforms and list of platforms
platforms = []
for t in a:
if t["Platform"] not in platforms:
platforms.append(t["Platform"])
# remove empty platforms
platforms.remove("")
# Empty Platform Data structure for Layer json file
platforms_list = []
for item in platforms:
platform_dict = dict()
platform_dict[item] = []
platforms_list.append(platform_dict)
# Creating list of techniques per platfdorm and create Techniques data strcuture to iterate further
for aplatform in platforms_list:
for ap, techniques_list in aplatform.items():
for t in a:
if ap == t["Platform"]:
technique_dict = dict()
technique_dict["techniqueId"] = t["TechniqueId"]
technique_dict["DetectionName"] = t["DetectionName"]
technique_dict["DataTypes"] = t["DataTypes"]
if technique_dict not in techniques_list:
techniques_list.append(technique_dict)
# Code to Generate ATT&CK navigator Layer json file using Data Structures - Platforms and Techniques used
for platform in platforms_list:
for k, v in platform.items():
technique_mappings = dict()
for technique in v:
metadata = dict()
metadata["name"] = technique["DetectionName"]
metadata["value"] = technique["DataTypes"]
if technique["techniqueId"] not in technique_mappings:
technique_mappings[technique["techniqueId"]] = []
if metadata not in technique_mappings[technique["techniqueId"]]:
technique_mappings[technique["techniqueId"]].append(metadata)
VERSION = {
"attack": "10",
"navigator": "4.5.4",
"layer": "4.2"
}
NAME = "{} Layer Json File for Microsoft Sentinel".format(k)
DESCRIPTION = "{} ATT&CK Matrix Coverage for Microsoft Sentinel".format(k)
DOMAIN = "mitre-enterprise"
platform_layer = {
"description": DESCRIPTION,
"name": NAME,
"domain": DOMAIN,
"versions": VERSION,
"filters": {"stages": ["act"], "platforms": [k]},
"techniques": [
{"score": 1, "techniqueID": k, "metadata": v}
for k, v in technique_mappings.items()
],
"gradient": {
"colors": ["#ffffff", "##8ec843"],
"minValue": 0,
"maxValue": 1,
},
"legendItems": [{"label": "Techniques researched", "color": "#66fff3"}],
}
#output layer files to directory
layerdir = outputdir
if not os.path.exists(layerdir):
os.makedirs(layerdir)
with open((f"./{layerdir}/{k}.json"), "w") as f:
print(f'Writing the Layer file for {k}')
f.write(json.dumps(platform_layer))
generate_navigator_layerfiles(
inputfile="MicrosoftSentinel-with-Headers.csv", outputdir="Layers"
)
Writing the Layer file for Azure Writing the Layer file for Windows Writing the Layer file for Linux Writing the Layer file for macOS Writing the Layer file for AWS Writing the Layer file for Azure AD Writing the Layer file for Office 365 Writing the Layer file for SaaS Writing the Layer file for GCP
import IPython
import warnings
warnings.filterwarnings("ignore")
# Azure ATT&CK Coverage
iframe = '''<iframe src="https://mitre-attack.github.io/attack-navigator/enterprise/
#layerURL=https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/MITRE%20ATT%26CK/Layers/Azure.json
&tabs=false&selecting_techniques=false" width="1000" height="400"></iframe>
'''
IPython.display.HTML(iframe)
If you are using Jupyterlab, be sure to install Jupyterlab extension to render plots.
renderer support
jupyter labextension install jupyterlab-plotly
OPTIONAL: Jupyter widgets extension
jupyter labextension install @jupyter-widgets/jupyterlab-manager plotlywidget
output_df = pd.read_csv("MicrosoftSentinel-with-Headers.csv")
Tactics = [
"InitialAccess",
"Execution",
"Persistence",
"PrivilegeEscalation",
"DefenseEvasion",
"CredentialAccess",
"Discovery",
"LateralMovement",
"Collection",
"CommandAndControl",
"Exfiltration",
"Impact",
]
df_plot = (
output_df[["Tactic", "DetectionType", "DetectionName"]]
.dropna()
.groupby(["Tactic", "DetectionType"])["DetectionName"]
.nunique()
.reset_index(level=[0, 1])
)
df_plot = df_plot.rename(columns={"DetectionName": "Count"}).fillna(0)
df_plot = df_plot[df_plot["Tactic"].isin(Tactics)]
df_stats = df_plot.pivot(index="Tactic", columns="DetectionType", values="Count")
df_stats = df_stats.fillna(0).astype('int')
df_stats
DetectionType | Analytics | Fusion | Hunting |
---|---|---|---|
Tactic | |||
Collection | 33 | 10 | 49 |
CommandAndControl | 49 | 2 | 30 |
CredentialAccess | 75 | 0 | 25 |
DefenseEvasion | 35 | 5 | 26 |
Discovery | 15 | 1 | 37 |
Execution | 30 | 3 | 116 |
Exfiltration | 21 | 40 | 75 |
Impact | 59 | 31 | 55 |
InitialAccess | 69 | 52 | 69 |
LateralMovement | 16 | 16 | 28 |
Persistence | 59 | 5 | 121 |
PrivilegeEscalation | 23 | 1 | 31 |
hunting_count=[]
detection_count=[]
fusion_count=[]
for tactic in Tactics:
detection_count.append(df_stats.loc[tactic,'Analytics'])
hunting_count.append(df_stats.loc[tactic,'Hunting'])
fusion_count.append(df_stats.loc[tactic,'Fusion'])
print(f'Detections Count per Tactics : {detection_count}')
print(f'Hunting Queries Count per Tactics : {hunting_count}')
print(f'Fusion ML Count per Tactics : {fusion_count}')
Detections Count per Tactics : [69, 30, 59, 23, 35, 75, 15, 16, 33, 49, 21, 59] Hunting Queries Count per Tactics : [69, 116, 121, 31, 26, 25, 37, 28, 49, 30, 75, 55] Fusion ML Count per Tactics : [52, 3, 5, 1, 5, 0, 1, 16, 10, 2, 40, 31]
fig = go.Figure()
fig.add_trace(go.Scatterpolar(
r=detection_count,
theta=Tactics,
fill='toself',
name='Analytics'
))
fig.add_trace(go.Scatterpolar(
r=hunting_count,
theta=Tactics,
fill='toself',
name='Hunting'
))
fig.add_trace(go.Scatterpolar(
r=fusion_count,
theta=Tactics,
fill='toself',
name='Fusion'
))
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True
)),
height=600, width=800,
showlegend=True,
title="MITRE ATT&CK Tactics Coverage by Detection Type ", title_x=0.5
)
fig.show()
df_platform = (
output_df[["Tactic", "Platform", "DetectionName"]]
.dropna()
.groupby(["Tactic", "Platform"])["DetectionName"]
.nunique()
.reset_index(level=[0, 1])
)
df_platform = df_platform.rename(columns={"DetectionName": "Count"})
df_platform = df_platform[df_platform["Tactic"].isin(Tactics)]
df_platform = (
df_platform.pivot(index="Tactic", columns="Platform", values="Count")
.fillna(0)
.astype(int)
)
df_platform
Platform | AWS | Azure | Azure AD | GCP | Linux | Office 365 | SaaS | Windows | macOS |
---|---|---|---|---|---|---|---|---|---|
Tactic | |||||||||
Collection | 15 | 45 | 14 | 15 | 6 | 13 | 31 | 32 | 0 |
CommandAndControl | 7 | 52 | 5 | 1 | 62 | 13 | 7 | 61 | 0 |
CredentialAccess | 5 | 69 | 44 | 2 | 22 | 5 | 9 | 36 | 0 |
DefenseEvasion | 10 | 20 | 11 | 5 | 5 | 4 | 15 | 16 | 0 |
Discovery | 7 | 42 | 4 | 5 | 14 | 2 | 6 | 39 | 0 |
Execution | 3 | 98 | 3 | 0 | 18 | 5 | 4 | 116 | 2 |
Exfiltration | 43 | 107 | 42 | 41 | 17 | 14 | 41 | 63 | 2 |
Impact | 70 | 128 | 77 | 31 | 59 | 43 | 52 | 85 | 41 |
InitialAccess | 60 | 144 | 110 | 50 | 27 | 29 | 64 | 37 | 4 |
LateralMovement | 21 | 42 | 22 | 20 | 11 | 0 | 27 | 29 | 1 |
Persistence | 14 | 113 | 32 | 10 | 17 | 11 | 20 | 96 | 0 |
PrivilegeEscalation | 7 | 28 | 13 | 0 | 4 | 3 | 3 | 29 | 0 |
aws=[]
azure=[]
gcp = []
azuread=[]
o365=[]
windows=[]
linux=[]
macos=[]
for tactic in Tactics:
aws.append(df_platform.loc[tactic,'AWS'])
azure.append(df_platform.loc[tactic,'Azure'])
gcp.append(df_platform.loc[tactic,'GCP'])
azuread.append(df_platform.loc[tactic,'Azure AD'])
o365.append(df_platform.loc[tactic,'Office 365'])
windows.append(df_platform.loc[tactic,'Windows'])
linux.append(df_platform.loc[tactic,'Linux'])
macos.append(df_platform.loc[tactic,'macOS'])
print(f'AWS Count per Tactics : {aws}')
print(f'Azure Queries Count per Tactics : {azure}')
print(f'GCP Queries Count per Tactics : {gcp}')
print(f'Azure AD Count per Tactics : {azuread}')
print(f'Office 365 Count per Tactics : {o365}')
print(f'Windows Count per Tactics : {windows}')
print(f'Linux Count per Tactics : {linux}')
print(f'Mac OS Count per Tactics : {macos}')
AWS Count per Tactics : [60, 3, 14, 7, 10, 5, 7, 21, 15, 7, 43, 70] Azure Queries Count per Tactics : [144, 98, 113, 28, 20, 69, 42, 42, 45, 52, 107, 128] GCP Queries Count per Tactics : [50, 0, 10, 0, 5, 2, 5, 20, 15, 1, 41, 31] Azure AD Count per Tactics : [110, 3, 32, 13, 11, 44, 4, 22, 14, 5, 42, 77] Office 365 Count per Tactics : [29, 5, 11, 3, 4, 5, 2, 0, 13, 13, 14, 43] Windows Count per Tactics : [37, 116, 96, 29, 16, 36, 39, 29, 32, 61, 63, 85] Linux Count per Tactics : [27, 18, 17, 4, 5, 22, 14, 11, 6, 62, 17, 59] Mac OS Count per Tactics : [4, 2, 0, 0, 0, 0, 0, 1, 0, 0, 2, 41]
fig = go.Figure()
fig = make_subplots(rows=3, cols=2,
specs=[[{'type': 'polar'}, {'type': 'polar'}],
[{'type': 'polar'}, {'type': 'polar'}],
[{'type': 'polar'}, {'type': 'polar'}]])
fig.add_traces(
[go.Scatterpolar(r=aws, theta=Tactics, fill='toself', name='AWS'),
go.Scatterpolar(r=azure, theta=Tactics, fill='toself', name='Azure'),
go.Scatterpolar(r=azuread, theta=Tactics, fill='toself', name='Azure AD'),
go.Scatterpolar(r=o365, theta=Tactics, fill='toself', name='Office 365'),
go.Scatterpolar(r=windows, theta=Tactics, fill='toself', name='Windows'),
go.Scatterpolar(r=linux, theta=Tactics, fill='toself', name='Linux')
],
rows=[1, 1, 2, 2, 3, 3],
cols=[1, 2, 1, 2, 1, 2]
)
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True
)),
height=1200, width=800,
showlegend=True,
title="MITRE ATT&CK Tactics Coverage Per Platform", title_x=0.5
)
fig.show()
fig = go.Figure()
fig.add_trace(go.Scatterpolar(
r=aws,
theta=Tactics,
fill='toself',
name='AWS'
))
fig.add_trace(go.Scatterpolar(
r=azure,
theta=Tactics,
fill='toself',
name='Azure'
))
fig.add_trace(go.Scatterpolar(
r=azuread,
theta=Tactics,
fill='toself',
name='Azure AD'
))
fig.add_trace(go.Scatterpolar(
r=gcp,
theta=Tactics,
fill='toself',
name='GCP'
))
fig.add_trace(go.Scatterpolar(
r=o365,
theta=Tactics,
fill='toself',
name='Office 365'
))
fig.add_trace(go.Scatterpolar(
r=windows,
theta=Tactics,
fill='toself',
name='Windows'
))
fig.add_trace(go.Scatterpolar(
r=linux,
theta=Tactics,
fill='toself',
name='Linux'
))
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True
)),
height=600, width=800,
showlegend=True,
title="MITRE ATT&CK Tactics Coverage Per Platform", title_x=0.5
)
fig.show()
msft_df_tactics = (
msft_df.groupby("Detection Service")["Alert"]
.nunique()
.to_frame(name="Count")
.sort_values(by=["Count"], ascending=False)
.reset_index()
)
display(msft_df_tactics)
labels = msft_df_tactics["Detection Service"]
values = msft_df_tactics["Count"]
# Use `hole` to create a donut-like pie chart
fig = go.Figure(data=[go.Pie(labels=labels, values=values, hole=0.4)])
fig.update_layout(
title={
'text': "Microsoft Threat Protection Solutions",
'y':0.9,
'x':0.5})
fig.show()
Detection Service | Count | |
---|---|---|
0 | Microsoft Defender for Linux | 107 |
1 | Microsoft Defender for Windows | 102 |
2 | Microsoft Defender for Azure Containers and Ku... | 65 |
3 | Microsoft Defender for Identity | 43 |
4 | Microsoft Defender for Azure App Service | 40 |
5 | Microsoft Defender for Azure Resource Manager | 36 |
6 | Microsoft Defender for Cloud Apps | 29 |
7 | Microsoft Defender for Azure Storage | 18 |
8 | Azure Identity Protection Center (IPC) | 17 |
9 | Microsoft Defender for Azure Network Layer | 15 |
10 | Microsoft Defender for Azure DNS | 13 |
11 | Microsoft Defender for SQL Database and Synaps... | 13 |
12 | Microsoft Defender for Azure Key Vault | 10 |
13 | Microsoft Defender for Open source relational ... | 10 |
14 | Microsoft Defender for Security Incident | 4 |
15 | Microsoft Defender for Azure DDoS Protection | 2 |
16 | Microsoft Defender for Azure Cosmos DB (Preview) | 2 |
msft_df_providers = (
msft_df[msft_df["Provider"] != "N.A."]
.groupby("Provider")["Alert"]
.nunique()
.to_frame(name="Count")
.sort_values(by=["Count"], ascending=False)
.reset_index()
)
display(msft_df_providers)
labels = msft_df_providers["Provider"]
values = msft_df_providers["Count"]
fig = go.Figure(data=[go.Pie(labels=labels, values=values, hole=0.3)])
fig.update_layout(
title={
'text': "Azure Defender Resource Level Breakdown",
'y':0.9,
'x':0.5})
fig.show()
Provider | Count | |
---|---|---|
0 | Linux | 107 |
1 | Windows | 102 |
2 | Azure Containers and Kubernetes clusters | 65 |
3 | Azure App Service | 40 |
4 | Azure Resource Manager | 36 |
5 | Azure Storage | 18 |
6 | Azure Network Layer | 15 |
7 | Azure DNS | 13 |
8 | SQL Database and Synapse Analytics | 13 |
9 | Azure Key Vault | 10 |
10 | Open source relational Databases | 10 |
11 | Security Incident | 4 |
12 | Azure Cosmos DB (Preview) | 2 |
13 | Azure DDoS Protection | 2 |
la_ws_id = widgets.Text(description='Workspace ID:')
la_ws_key = widgets.Password(description='Workspace Key:')
display(la_ws_id)
display(la_ws_key)
Text(value='', description='Workspace ID:')
Password(description='Workspace Key:')
if la_ws_id.value:
# Instantiate our Uploader
la_up = LAUploader(workspace=la_ws_id.value, workspace_secret=la_ws_key.value, debug=True)
# Upload dataframe
la_up.upload_df(data=newdf, table_name='AzSentinelMITRE')
la_up.upload_df(data=msft_df, table_name='MSFTAlerts')
else:
print('No Workspace details provided in previous cell')
No Workspace details provided in previous cell