45e6b901a2
* add description to hunting schema; change queries to be a list
* update createremotethreat by process hunt
* update dll hijack and masquerading as MSFT library
* remove sysmon specific dDLL hijack via masquerading MSFT library
* updated Masquerading Attempts as Native Windows Binaries
* updates Rare DLL Side-Loading by Occurrence
* updates Rare LSASS Process Access Attempts
* update DNS Queries via LOLBins with Low Occurence Frequency
* updated Low Occurrence of Drivers Loaded on Unique Hosts
* updates Excessive RDP Network Activity by Host and User
* updates Excessive SMB Network Activity by Process ID
* updated Executable File Creation by an Unusual Microsoft Binary
* Frequency of Process Execution and Network Logon by Source Address
* updates Frequency of Process Execution and Network Logon by Source Address
* updated Execution via Remote Services by Client Address
* updated Startup Execution with Low Occurrence Frequency by Unique Host
* updated Low Frequency of Process Execution via WMI by Unique Agent
* updated Low Frequency of Process Execution via Windows Scheduled Task by Unique Agent
* updated Low Occurence of Process Execution via Windows Services with Unique Agent
* Updated High Count of Network Connection Over Extended Period by Process
* update Libraries Loaded by svchost with Low Occurrence Frequency
* updated Microsoft Office Child Processes with Low Occurrence Frequency by Unique Agent
* updated Network Discovery via Sensitive Ports by Unusual Process
* updated PE File Transfer via SMB_Admin Shares by Agent or User
* updated Persistence via Run Key with Low Occurrence Frequency
* updates Persistence via Startup with Low Occurrence Frequency by Unique Host
* updates "Persistence via Run Key with Low Occurrence Frequency"; adjusted file names to remove data source
* updates "Low Occurrence of Suspicious Launch Agent or Launch Daemon"
* updates "Egress Network Connections with Total Bytes Greater than Threshold"
* updates "Rundll32 Execution Aggregated by Command Line"
* updates "Scheduled tasks Creation by Action via Registry"
* updates "Scheduled Tasks Creation for Unique Hosts by Task Command"
* updates "Suspicious Base64 Encoded Powershell Command"
* updates "Suspicious DNS TXT Record Lookups by Process"
* updates "Unique Windows Services Creation by Service File Name"
* Updates "Unique Windows Services Creation by Service File Name"
* updates "Windows Command and Scripting Interpreter from Unusual Parent Process"
* updates "Windows Logon Activity by Source IP"
* updates "Suspicious Network Connections by Unsigned Mach-O"
* updates LLM hunting queries
* re-generated markdown files; updated generate markdown py file
* updated test_hunt_data
* Update hunting/macos/queries/suspicious_network_connections_by_unsigned_macho.toml
Co-authored-by: Mika Ayenson <Mikaayenson@users.noreply.github.com>
* Update hunting/windows/queries/drivers_load_with_low_occurrence_frequency.toml
Co-authored-by: Mika Ayenson <Mikaayenson@users.noreply.github.com>
* Update hunting/windows/queries/domain_names_queried_via_lolbins_and_with_low_occurence_frequency.toml
Co-authored-by: Mika Ayenson <Mikaayenson@users.noreply.github.com>
* Update hunting/windows/queries/excessive_rdp_network_activity_by_source_host_and_user.toml
Co-authored-by: Mika Ayenson <Mikaayenson@users.noreply.github.com>
* Update hunting/windows/queries/excessive_rdp_network_activity_by_source_host_and_user.toml
Co-authored-by: Mika Ayenson <Mikaayenson@users.noreply.github.com>
* updated missing integrations
* updated MD docs according to recent hunting changes
* Update hunting/windows/queries/executable_file_creation_by_an_unusual_microsoft_binary.toml
Co-authored-by: Jonhnathan <26856693+w0rk3r@users.noreply.github.com>
* Update hunting/windows/queries/detect_rare_dll_sideload_by_occurrence.toml
Co-authored-by: Jonhnathan <26856693+w0rk3r@users.noreply.github.com>
* Update hunting/windows/queries/detect_masquerading_attempts_as_native_windows_binaries.toml
Co-authored-by: Jonhnathan <26856693+w0rk3r@users.noreply.github.com>
* Update hunting/windows/queries/detect_dll_hijack_via_masquerading_as_microsoft_native_libraries.toml
Co-authored-by: Jonhnathan <26856693+w0rk3r@users.noreply.github.com>
* Update hunting/llm/queries/aws_bedrock_dos_resource_exhaustion_detection.toml
Co-authored-by: Jonhnathan <26856693+w0rk3r@users.noreply.github.com>
* added enrichment policy link to rule
* Update hunting/windows/docs/execution_via_windows_management_instrumentation_by_occurrence_frequency_by_unique_agent.md
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
* Update hunting/windows/docs/windows_command_and_scripting_interpreter_from_unusual_parent.md
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
* Update hunting/windows/docs/windows_command_and_scripting_interpreter_from_unusual_parent.md
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
* Update hunting/windows/docs/rundll32_execution_aggregated_by_cmdline.md
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
* Update hunting/windows/docs/microsoft_office_child_processes_with_low_occurrence_frequency.md
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
* Update hunting/windows/docs/microsoft_office_child_processes_with_low_occurrence_frequency.md
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
* Update hunting/windows/queries/execution_via_windows_management_instrumentation_by_occurrence_frequency_by_unique_agent.toml
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
* Update hunting/windows/queries/execution_via_windows_management_instrumentation_by_occurrence_frequency_by_unique_agent.toml
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
* Update hunting/index.md
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
* Update hunting/windows/docs/execution_via_network_logon_by_occurrence_frequency_by_top_source_ip.md
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
* Update hunting/windows/queries/execution_via_network_logon_by_occurrence_frequency_by_top_source_ip.toml
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
---------
Co-authored-by: Mika Ayenson <Mikaayenson@users.noreply.github.com>
Co-authored-by: Jonhnathan <26856693+w0rk3r@users.noreply.github.com>
Co-authored-by: Samirbous <64742097+Samirbous@users.noreply.github.com>
(cherry picked from commit 632e169f7a)
140 lines
5.3 KiB
Python
140 lines
5.3 KiB
Python
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
# or more contributor license agreements. Licensed under the Elastic License
|
|
# 2.0; you may not use this file except in compliance with the Elastic License
|
|
# 2.0.
|
|
|
|
"""Lightweight builtin toml-markdown converter."""
|
|
|
|
import tomllib
|
|
import urllib3
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
from typing import List, Optional
|
|
|
|
HUNTING_DIR = Path(__file__).parent
|
|
ATLAS_URL = "https://atlas.mitre.org/techniques/"
|
|
ATTACK_URL = "https://attack.mitre.org/techniques/"
|
|
|
|
# the standard link takes `integration.package` and converts the link to `integration/package`, however, there are
|
|
# some exceptions such as `aws_bedrock.invocation` which should be linked to `aws_bedrock` instead
|
|
# https://docs.elastic.co/integrations/aws_bedrock
|
|
STATIC_INTEGRATION_LINK_MAP = {
|
|
'aws_bedrock.invocation': 'aws_bedrock'
|
|
}
|
|
|
|
|
|
@dataclass
|
|
class Hunt:
|
|
"""Dataclass to represent a hunt."""
|
|
|
|
author: str
|
|
description: str
|
|
integration: list[str]
|
|
uuid: str
|
|
name: str
|
|
language: str
|
|
license: str
|
|
query: list[str]
|
|
notes: Optional[List[str]] = field(default_factory=list)
|
|
mitre: Optional[List[str]] = field(default_factory=list)
|
|
references: Optional[List[str]] = field(default_factory=list)
|
|
|
|
|
|
def load_toml(contents: str) -> Hunt:
|
|
"""Load and validate TOML content as Hunt dataclass."""
|
|
toml_dict = tomllib.loads(contents)
|
|
return Hunt(**toml_dict["hunt"])
|
|
|
|
|
|
def load_all_toml(base_path: Path) -> List[tuple[Hunt, Path]]:
|
|
"""Load all TOML files from the directory and return a list of Hunt configurations and their paths."""
|
|
hunts = []
|
|
for toml_file in base_path.rglob("*.toml"):
|
|
hunt_config = load_toml(toml_file.read_text())
|
|
hunts.append((hunt_config, toml_file))
|
|
return hunts
|
|
|
|
|
|
def validate_link(link: str):
|
|
"""Validate and return the link."""
|
|
response = urllib3.request('get', link)
|
|
if response.status != 200:
|
|
raise ValueError(f"Invalid link: {link}")
|
|
|
|
|
|
def generate_integration_links(integrations: list[str]) -> list[str]:
|
|
base_url = 'https://docs.elastic.co/integrations'
|
|
generated = []
|
|
for integration in integrations:
|
|
if integration in STATIC_INTEGRATION_LINK_MAP:
|
|
link_str = STATIC_INTEGRATION_LINK_MAP[integration]
|
|
else:
|
|
link_str = integration.replace('.', '/')
|
|
link = f'{base_url}/{link_str}'
|
|
validate_link(link)
|
|
generated.append(f'[{integration}]({link})')
|
|
|
|
return generated
|
|
|
|
|
|
def convert_toml_to_markdown(hunt_config: Hunt, file_path: Path) -> str:
|
|
"""Convert Hunt to Markdown format."""
|
|
markdown = f"# {hunt_config.name}\n\n---\n\n"
|
|
markdown += "## Metadata\n\n"
|
|
markdown += f"- **Author:** {hunt_config.author}\n"
|
|
markdown += f"- **Description:** {hunt_config.description}\n"
|
|
markdown += f"- **UUID:** `{hunt_config.uuid}`\n"
|
|
markdown += f"- **Integration:** {", ".join(generate_integration_links(hunt_config.integration))}\n"
|
|
markdown += f"- **Language:** `{hunt_config.language}`\n\n"
|
|
markdown += "## Query\n\n"
|
|
for query in hunt_config.query:
|
|
markdown += f"```sql\n{query}```\n\n"
|
|
|
|
if hunt_config.notes:
|
|
markdown += "## Notes\n\n" + "\n".join(f"- {note}" for note in hunt_config.notes)
|
|
if hunt_config.mitre:
|
|
markdown += "\n## MITRE ATT&CK Techniques\n\n" + "\n".join(
|
|
f"- [{tech}]({ATLAS_URL if tech.startswith('AML') else ATTACK_URL}"
|
|
f"{tech.replace('.', '/') if tech.startswith('T') else tech})"
|
|
for tech in hunt_config.mitre
|
|
)
|
|
if hunt_config.references:
|
|
markdown += "\n## References\n\n" + "\n".join(f"- {ref}" for ref in hunt_config.references)
|
|
markdown += f"\n- [{hunt_config.name}]({Path('../queries') / file_path.name})"
|
|
|
|
markdown += f"\n\n## License\n\n- `{hunt_config.license}`\n"
|
|
return markdown
|
|
|
|
|
|
def process_toml_files(base_path: Path) -> None:
|
|
"""Process all TOML files in the directory recursively and convert them to Markdown."""
|
|
hunts = load_all_toml(base_path)
|
|
index_content = "# List of Available Queries\n\nHere are the queries currently available:"
|
|
directories = {}
|
|
|
|
for hunt_config, toml_file in hunts:
|
|
markdown_content = convert_toml_to_markdown(hunt_config, toml_file)
|
|
markdown_path = toml_file.parent.parent / "docs" / f"{toml_file.stem}.md"
|
|
markdown_path.parent.mkdir(parents=True, exist_ok=True)
|
|
markdown_path.write_text(markdown_content, encoding="utf-8")
|
|
print(f"Markdown generated: {markdown_path}")
|
|
relative_path = markdown_path.relative_to(base_path)
|
|
folder_name = toml_file.parent.parent.name
|
|
directories.setdefault(folder_name, []).append((relative_path, hunt_config.name, hunt_config.language))
|
|
|
|
# Build index content
|
|
for folder, files in sorted(directories.items()):
|
|
index_content += f"\n\n## {folder}\n"
|
|
for file_path, rule_name, language in sorted(files):
|
|
index_path = "./" + str(file_path)
|
|
index_content += f"- [{rule_name}]({index_path}) ({language})\n"
|
|
|
|
# Write the index file at the base directory level
|
|
index_path = base_path / "index.md"
|
|
index_path.write_text(index_content, encoding="utf-8")
|
|
print(f"Index Markdown generated at: {index_path}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
process_toml_files(HUNTING_DIR)
|