Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,6 @@ morphchart_package/
/docs/notebooks/kqlmagic/*
/kqlmagic/**
/GitExtensions.settings

# Guardian files
/.gdn/**
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,27 @@ repos:
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
- repo: https://github.com/ambv/black
rev: 24.10.0
rev: 25.9.0
hooks:
- id: black
language: python
- repo: https://github.com/PyCQA/pylint
rev: v3.3.1
rev: v4.0.2
hooks:
- id: pylint
args:
- --disable=duplicate-code,import-error
- --ignore-patterns=test_
- repo: https://github.com/pycqa/flake8
rev: 7.1.1
rev: 7.3.0
hooks:
- id: flake8
args:
- --extend-ignore=E401,E501,W503
- --max-line-length=90
- --exclude=tests,test*.py
- repo: https://github.com/pycqa/isort
rev: 5.13.2
rev: 7.0.0
hooks:
- id: isort
name: isort (python)
Expand All @@ -43,7 +43,7 @@ repos:
- --convention=numpy
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.8.0
rev: v0.14.1
hooks:
# Run the linter.
- id: ruff
Expand Down
4 changes: 0 additions & 4 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ persistent=yes
# Specify a configuration file.
#rcfile=

# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes

# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
Expand Down
163 changes: 100 additions & 63 deletions docs/source/data_acquisition/DataProv-MSDefender.rst
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
Microsoft 365 Defender Provider
===============================
Microsoft Defender Provider
===========================

This driver lets you query the Microsoft Defender APIs.

.. note:: This section applies to both Microsoft 365 Defender and Microsoft Defender
for Endpoint (MDE). The former supersedes and is a subset of the the latter
but both are still available to use.
.. note:: This provider supports multiple API endpoints for accessing Microsoft Defender data:

- **M365DGraph** (Recommended): Uses the Microsoft Graph API with ThreatHunting permissions.
This is the preferred and most modern API.
- **MDE/MDATP**: Uses the Microsoft Defender for Endpoint API (formerly MDATP).
This is the fallback option when M365DGraph is not available.
- **M365D** (Removed): The Microsoft 365 Defender API provider has been removed from
MSTICPy. If you use the "M365D" provider name, it will automatically use the MDE
API endpoints instead.

Many components in MSTICPy still use the old abbreviation **MDATP**
(Microsoft Advanced Threat Protection).
(Microsoft Advanced Threat Protection) for backwards compatibility.

M365 Defender Configuration
---------------------------
Defender Configuration
----------------------

Creating a Client App for M365 Defender
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Creating a Client App for Microsoft Defender
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Microsoft 365 Defender APIs can be accessed in both `application <https://learn.microsoft.com/en-us/defender-endpoint/api/exposed-apis-create-app-webapp>`
and `delegated user contexts <https://learn.microsoft.com/en-us/defender-endpoint/api/exposed-apis-create-app-nativeapp>`.
Accessing Microsoft 365 Defender APIs as an application requires
Microsoft Defender APIs can be accessed in both
`application <https://learn.microsoft.com/en-us/defender-endpoint/api/exposed-apis-create-app-webapp>`__
and `delegated user contexts <https://learn.microsoft.com/en-us/defender-endpoint/api/exposed-apis-create-app-nativeapp>`__.
Accessing Microsoft Defender APIs as an application requires
either a client secret or certificate, while delegated user auth requires
an interactive signin through a browser or via device code.

As such, the details on registering an Azure AD application for MS 365 Defender
As such, the details on registering an Azure AD application for MS Defender
are different for application and delegated user auth scenarios. Please
see the above links for more information. Notably, delegated user auth
scenarios do not require a application credential and thus is preferrable.
Expand All @@ -38,18 +45,24 @@ and auth scenario (application or delegated user):
+-----------------------------+------------------------+------------------+
| API Name | Permission | Data Environment |
+=============================+========================+==================+
| WindowsDefenderATP | AdvancedQuery.Read | MDE, MDATP |
+-----------------------------+------------------------+------------------+
| Microsoft Threat Protection | AdvancedHunting.Read | M365D |
+-----------------------------+------------------------+------------------+
| Microsoft Graph | ThreatHunting.Read.All | M365DGraph |
+-----------------------------+------------------------+------------------+
| WindowsDefenderATP | AdvancedQuery.Read | MDE, MDATP |
+-----------------------------+------------------------+------------------+

.. note:: **M365DGraph is the recommended data environment** as it uses the modern
Microsoft Graph API. The MDE/MDATP endpoints are maintained for backwards
compatibility and as a fallback option.

The Microsoft Threat Protection API provider (M365D) has been removed. If you
specify "M365D" as the provider name, it will automatically use MDE endpoints
for backwards compatibility.

Once you have registered the application, you can use it to connect to
the MS Defender API using the chosen data environment.
the MS Defender API using your chosen data environment.

M365 Defender Configuration in MSTICPy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Defender Configuration in MSTICPy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can store your connection details in *msticpyconfig.yaml*.

Expand Down Expand Up @@ -88,7 +101,7 @@ Your configuration when using Key Vault should look like the following:
KeyVault:
TenantId: "TENANT ID"

You can create multiple instances of M365 Defender settings by adding
You can create multiple instances of Defender settings by adding
an instance string to the "MicrosoftDefender" section name.

.. code:: yaml
Expand Down Expand Up @@ -134,71 +147,95 @@ See :doc:`msticpy Settings Editor <../getting_started/SettingsEditor>`.
PrivateKeySecret:
KeyVault:

Loading a QueryProvider for M365 Defender
-----------------------------------------
Loading a QueryProvider for Microsoft Defender
----------------------------------------------

**Recommended: Use M365DGraph**

.. code:: ipython3

defender_prov = QueryProvider("M365DGraph")

**Alternative: Use MDE (legacy/fallback)**

.. code:: ipython3

mdatp_prov = QueryProvider("M365D")
mde_prov = QueryProvider("MDE")

You can also use the aliases "MDE" and "MDATP".
You can also use the alias "MDATP" for backwards compatibility.

Specifying the Defender Cloud Instance to Connect to
----------------------------------------------------
.. note:: The "M365D" alias has been removed but is still accepted for backwards
compatibility - it will automatically use MDE endpoints. We recommend using
"M365DGraph" for new implementations.

Specifying the Defender Cloud Instance
--------------------------------------

If connecting to the Defender API to run queries there are a number of
different endpoints you can connect to.
Which one is most applicable will depend on your location and which
cloud you are using.

By default 'https://api.securitycenter.microsoft.com/' or
'https://api.security.microsoft.com/' is used, but others can be
specified either in your MSTICPy config file, or by passing
in the name with the cloud keyword:
**For M365DGraph (Microsoft Graph API):**

By default 'https://graph.microsoft.com/' is used. For government clouds,
the appropriate Graph endpoint will be selected automatically based on the
cloud parameter.

.. code:: ipython3

mdatp_prov = QueryProvider("MDE", cloud="gcc")
defender_prov = QueryProvider("M365DGraph", cloud="gcc")

**For MDE (Defender for Endpoint API):**

If using an MDE-specific API endpoint, the "name" (the first parameter to QueryProvider in the example above) must be "MDE".
By default 'https://api.securitycenter.microsoft.com/' is used, but others can be
specified either in your MSTICPy config file, or by passing
in the name with the cloud keyword:

+----------+----------------------------------------------+----------------------------------------+
| Cloud | MDE | M365D |
+==========+==============================================+========================================+
| global | https://api.securitycenter.microsoft.com/ | https://api.security.microsoft.com/ |
+----------+----------------------------------------------+----------------------------------------+
| uk | https://api-uk.securitycenter.microsoft.com/ | https://api-uk.security.microsoft.com/ |
+----------+----------------------------------------------+----------------------------------------+
| us | https://api-us.securitycenter.microsoft.com/ | https://api-us.security.microsoft.com/ |
+----------+----------------------------------------------+----------------------------------------+
| eu | https://api-eu.securitycenter.microsoft.com/ | https://api-eu.security.microsoft.com/ |
+----------+----------------------------------------------+----------------------------------------+
| gcc | https://api-gcc.securitycenter.microsoft.us/ | NA |
+----------+----------------------------------------------+----------------------------------------+
| gcc-high | https://api-gov.securitycenter.microsoft.us/ | NA |
+----------+----------------------------------------------+----------------------------------------+
| dod | https://api-gov.securitycenter.microsoft.us/ | NA |
+----------+----------------------------------------------+----------------------------------------+
.. code:: ipython3

Connecting to M365 Defender
---------------------------
mde_prov = QueryProvider("MDE", cloud="gcc")


+----------+----------------------------------------------+
| Cloud | MDE Endpoint |
+==========+==============================================+
| global | https://api.securitycenter.microsoft.com/ |
+----------+----------------------------------------------+
| uk | https://api-uk.securitycenter.microsoft.com/ |
+----------+----------------------------------------------+
| us | https://api-us.securitycenter.microsoft.com/ |
+----------+----------------------------------------------+
| eu | https://api-eu.securitycenter.microsoft.com/ |
+----------+----------------------------------------------+
| gcc | https://api-gcc.securitycenter.microsoft.us/ |
+----------+----------------------------------------------+
| gcc-high | https://api-gov.securitycenter.microsoft.us/ |
+----------+----------------------------------------------+
| dod | https://api-gov.securitycenter.microsoft.us/ |
+----------+----------------------------------------------+

.. note:: M365DGraph uses Microsoft Graph endpoints which are automatically
configured for government clouds. The above table applies only to MDE/MDATP endpoints.

Connecting to Microsoft Defender
--------------------------------

The parameters required for connection to Defender can be passed in
a number of ways. The simplest is to configure your settings
in msticpyconfig. You can then just call connect with no parameters.

.. code:: ipython3

mdatp_prov.connect()
defender_prov.connect()


If you have configured multiple instances you must specify
an instance name when you call connect.

.. code:: ipython3

mdatp_prov.connect(instance="Tenant2")
defender_prov.connect(instance="Tenant2")

If you want to use delegated authentication for your application
you can specify this when you call connect. By default, this will
Expand All @@ -208,7 +245,7 @@ auth_type to "device".

.. code:: ipython3

mdatp_prov.connect(delegated_auth=True, auth_type="device")
defender_prov.connect(delegated_auth=True, auth_type="device")

You can also pass connection parameters as
keyword arguments or a connection string.
Expand All @@ -228,8 +265,8 @@ The client_secret and username parameters are mutually exclusive.
ten_id = input('Tenant ID')
client_id = input('Client ID')
client_secret = input('Client Secret')
md_prov = QueryProvider('M365D')
md_prov.connect(tenant_id=ten_id, client_id=client_id, client_secret=client_secret)
defender_prov = QueryProvider('M365DGraph')
defender_prov.connect(tenant_id=ten_id, client_id=client_id, client_secret=client_secret)

You can also specify these parameters as a connection string of the form:

Expand All @@ -246,12 +283,12 @@ You can also specify these parameters as a connection string of the form:
)
md_prov.connect(conn_str)

Other M365 Defender Documentation
---------------------------------
Other Microsoft Defender Documentation
--------------------------------------

For examples of using the MS Defender provider, see the sample
`M365 Defender Notebook<https://github.com/microsoft/msticpy/blob/master/docs/notebooks/MDATPQuery.ipynb>`
`Microsoft Defender Notebook<https://github.com/microsoft/msticpy/blob/master/docs/notebooks/MDATPQuery.ipynb>`__

Built-in :ref:`data_acquisition/DataQueries:Queries for Microsoft 365 Defender`.
Built-in :ref:`data_acquisition/DataQueries:Queries for Microsoft Defender`.

:py:mod:`M365 Defender driver API documentation<msticpy.data.drivers.mdatp_driver>`
:py:mod:`Microsoft Defender driver API documentation<msticpy.data.drivers.mdatp_driver>`
2 changes: 1 addition & 1 deletion msticpy/_version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Version file."""

VERSION = "2.17.1"
VERSION = "2.17.2"
1 change: 1 addition & 0 deletions msticpy/common/provider_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def _return_secrets_client(

# Create a SecretsClient instance if it can be imported when
# the module is imported.
# pylint: disable=invalid-name
_SECRETS_CLIENT: Any = None
# Create the secrets client closure
_SET_SECRETS_CLIENT: Callable[..., "SecretsClient" | None] = get_secrets_client_func()
Expand Down
4 changes: 2 additions & 2 deletions msticpy/context/azure/azure_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@
from azure.mgmt.network.models import NetworkInterface
from azure.mgmt.subscription.models import Subscription
except ImportError as imp_err:
error_msg: str = (
ERROR_MSG: str = (
"Cannot use this feature without these azure packages installed:\n"
"azure.mgmt.network\n"
"azure.mgmt.resource\n"
"azure.mgmt.monitor\n"
"azure.mgmt.compute\n"
)
raise MsticpyImportExtraError(
error_msg,
ERROR_MSG,
title="Error importing azure module",
extra="azure",
) from imp_err
Expand Down
1 change: 1 addition & 0 deletions msticpy/context/ip_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def _get_asns_dict() -> dict[str, str]:


# Create the dictionary accessor from the fetch_asns wrapper
# pylint: disable=invalid-name
_ASNS_DICT: Callable[[], dict[str, str]] = _fetch_asns()


Expand Down
Loading
Loading