Skip to content

Commit 6eed3ff

Browse files
petebryanPete Bryanianhelle
authored
Added features to support new notebooklet development. (#456)
* Added new queries for Windows Events and Syslog Added ability for cross provider query sharing Added timeout feature to screenshot Fixed issues with Alert Selector * fixed data_providers merge issue * Fixed issue with KQL Driver passing UA * [fix] Doc fixes - TIProviders.rst, TimeSeriesAnomalies.rst [update] DataQueries.rst new list. * [update] Update version to v2.0.0.rc3 Co-authored-by: Pete Bryan <pebryan@microsoft.com> Co-authored-by: Ian Hellen <ianhelle@microsoft.com>
1 parent 930f65d commit 6eed3ff

24 files changed

+675
-251
lines changed

docs/source/data_acquisition/DataQueries.rst

Lines changed: 218 additions & 102 deletions
Large diffs are not rendered by default.

docs/source/data_acquisition/TIProviders.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ Pivot functions also call the `lookup_iocs` method of this class.
325325

326326
Brief help is shown below. You can read more details about the
327327
attributes and functions in the
328-
[TILookup documentation](https://msticpy.readthedocs.io/api/msticpy.context.tilookup.html)
328+
:py:mod:`TILookup documentation <msticpy.context.tilookup>`
329329

330330
To use TILookup, you need to create an instance of the class.
331331
Avoid creating lots of instances of this class:
@@ -528,7 +528,7 @@ Lookup an IoC from a single provider
528528
And show the output
529529

530530
.. code-block:: ipython3
531-
:emphasize-lines:1
531+
:emphasize-lines: 1
532532
533533
result, details = ti_lookup.lookup_ioc(observable="38.75.137.9", providers=["OTX"])
534534

docs/source/visualization/TimeSeriesAnomalies.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ TechCommunity blog posts.
3333
Time Series analysis & its applications in Security
3434
<https://techcommunity.microsoft.com/t5/azure-sentinel/looking-for-unknown-anomalies-what-is-normal-time-series/ba-p/555052>`__
3535

36-
- `Time Series visualization of Palo Alto logs to detect data exfiltration
37-
<https://techcommunity.microsoft.com/t5/azure-sentinel/time-series-visualization-of-palo-alto-logs-to-detect-data/ba-p/666344>`__
36+
- `Time Series visualization of Palo Alto logs to detect data exfiltration <https://techcommunity.microsoft.com/t5/azure-sentinel/time-series-visualization-of-palo-alto-logs-to-detect-data/ba-p/666344>`__
3837

3938
Some useful background reading on Forecasting and prediction using time
4039
series here `Forecasting: Principals and Practice <https://otexts.com/fpp2/>`__

msticpy/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
"""Version file."""
2-
VERSION = "2.0.0-pre2"
2+
VERSION = "2.0.0-pre3"

msticpy/context/domain_utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,10 @@ def screenshot(url: str, api_key: str = None) -> httpx.Response:
9898
)
9999
# Wait until the screenshot is ready and keep user updated with progress
100100
print("Getting screenshot")
101-
progress = IntProgress(min=0, max=40)
101+
progress = IntProgress(min=0, max=100)
102102
display.display(progress)
103103
ready = False
104-
while not ready:
104+
while not ready and progress.value < 100:
105105
progress.value += 1
106106
status_data = httpx.get(
107107
status_string, timeout=config.get_http_timeout(), headers=mp_ua_header()
@@ -111,9 +111,9 @@ def screenshot(url: str, api_key: str = None) -> httpx.Response:
111111
ready = True
112112
else:
113113
time.sleep(0.05)
114-
progress.value = 40
114+
progress.value = 100
115115

116-
# Once ready get the screenshot
116+
# Once ready or timed out get the screenshot
117117
image_data = httpx.get(image_string, timeout=config.get_http_timeout())
118118

119119
if image_data.status_code != 200:

msticpy/context/tilookup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ def _combine_results(
785785

786786
if not result_list:
787787
print("No IoC matches")
788-
return pd.concat(result_list, sort=False)
788+
return pd.concat(result_list, sort=False) if result_list else None
789789

790790

791791
def _make_sync(future):

msticpy/context/tiproviders/kql_base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,9 @@ def lookup_iocs(
228228
)
229229
all_results.append(combined_results_df)
230230

231-
return pd.concat(all_results, ignore_index=True, sort=False, axis=0)
231+
if all_results:
232+
return pd.concat(all_results, ignore_index=True, sort=False, axis=0)
233+
return pd.DataFrame()
232234

233235
@staticmethod
234236
def _add_failure_status(src_ioc_frame: pd.DataFrame, lookup_status: LookupStatus):

msticpy/data/core/data_providers.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
__author__ = "Ian Hellen"
3030

3131
_DB_QUERY_FLAGS = ("print", "debug_query", "print_query")
32+
_COMPATIBLE_DRIVER_MAPPINGS = {"mssentinel": ["m365d"], "mde": ["m365d"]}
3233

3334

3435
@export
@@ -482,24 +483,30 @@ def _get_query_options(
482483
}
483484
return query_options
484485

485-
def _get_query_folder_for_env(self, root_path: str, environment: str) -> Path:
486+
def _get_query_folder_for_env(self, root_path: str, environment: str) -> List[Path]:
486487
"""Return query folder for current environment."""
487-
environment = "MDE" if environment == "M365D" else environment
488-
return self._resolve_package_path(root_path).joinpath(environment.casefold())
488+
data_envs = [environment]
489+
if environment.casefold() in _COMPATIBLE_DRIVER_MAPPINGS:
490+
data_envs += _COMPATIBLE_DRIVER_MAPPINGS[environment.casefold()]
491+
return [
492+
self._resolve_package_path(root_path).joinpath(data_env.casefold())
493+
for data_env in data_envs
494+
]
489495

490496
def _read_queries_from_paths(self, query_paths) -> Dict[str, QueryStore]:
491497
"""Fetch queries from YAML files in specified paths."""
492498
settings: Dict[str, Any] = config.settings.get( # type: ignore
493499
"QueryDefinitions"
494500
) # type: ignore
495-
all_query_paths = []
501+
all_query_paths: List[Union[Path, str]] = []
496502
for def_qry_path in settings.get("Default"): # type: ignore
497503
# only read queries from environment folder
498-
builtin_qry_path = self._get_query_folder_for_env(
504+
builtin_qry_paths = self._get_query_folder_for_env(
499505
def_qry_path, self.environment
500506
)
501-
if builtin_qry_path and builtin_qry_path.is_dir():
502-
all_query_paths.append(str(builtin_qry_path))
507+
all_query_paths.extend(
508+
str(qry_path) for qry_path in builtin_qry_paths if qry_path.is_dir()
509+
)
503510

504511
if settings.get("Custom") is not None:
505512
for custom_path in settings.get("Custom"): # type: ignore
@@ -511,7 +518,6 @@ def _read_queries_from_paths(self, query_paths) -> Dict[str, QueryStore]:
511518
param_qry_path = self._resolve_path(param_path)
512519
if param_qry_path:
513520
all_query_paths.append(param_qry_path)
514-
515521
if all_query_paths:
516522
return QueryStore.import_files(
517523
source_path=all_query_paths,

msticpy/data/drivers/kql_driver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def __init__(self, connection_str: str = None, **kwargs):
100100
if not self._loaded:
101101
self._load_kql_magic()
102102

103-
self._set_kql_option("request_user_agent-tag", MSTICPY_USER_AGENT)
103+
self._set_kql_option("request_user_agent_tag", MSTICPY_USER_AGENT)
104104
self._schema: Dict[str, Any] = {}
105105
self.environment = kwargs.pop("data_environment", DataEnvironment.MSSentinel)
106106
self.kql_cloud, self.az_cloud = self._set_kql_cloud()

msticpy/data/queries/m365d/kql_mdatp_file.yaml

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
metadata:
22
version: 1
33
description: MDATP Queries
4-
data_environments: [MDATP, MDE, M365D]
5-
data_families: [MDATP]
4+
data_environments: [MDATP, MDE, M365D, LogAnalytics]
5+
data_families: [MDATP, MDE]
66
tags: ["file"]
77
defaults:
88
metadata:
@@ -22,15 +22,19 @@ defaults:
2222
description: Additional query clauses
2323
type: str
2424
default: ""
25+
time_column:
26+
description: The name of the column detailing the time the event was generated.
27+
type: str
28+
default: "Timestamp"
2529
sources:
2630
list_files:
2731
description: Lists all file events by filename
2832
metadata:
2933
args:
3034
query: '
3135
{table}
32-
| where Timestamp >= datetime({start})
33-
| where Timestamp <= datetime({end})
36+
| where {time_column} >= datetime({start})
37+
| where {time_column} <= datetime({end})
3438
| where FileName has "{file_name}"
3539
{add_query_items}'
3640
uri: None
@@ -44,8 +48,8 @@ sources:
4448
args:
4549
query: '
4650
{table}
47-
| where Timestamp >= datetime({start})
48-
| where Timestamp <= datetime({end})
51+
| where {time_column} >= datetime({start})
52+
| where {time_column} <= datetime({end})
4953
| where FolderPath contains "{path}"
5054
{add_query_items}'
5155
parameters:
@@ -58,8 +62,8 @@ sources:
5862
args:
5963
query: '
6064
{table}
61-
| where Timestamp >= datetime({start})
62-
| where Timestamp <= datetime({end})
65+
| where {time_column} >= datetime({start})
66+
| where {time_column} <= datetime({end})
6367
| where SHA1 == "{file_hash}" or SHA256 == "{file_hash}" or MD5 == "{file_hash}"
6468
{add_query_items}'
6569
uri: None

0 commit comments

Comments
 (0)