Skip to content
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ workspaces/custom_parser/ # workspace root
│ └── custom_parser.py # CoreParser-based template
├── tests/
│ └── test_custom_parser.py # generated from template to test custom_parser
├── data.json # example data to run the code
├── LICENSE.md # copied from main project
├── .gitignore # copied from main project
├── .pre-commit-config.yaml # copied from main project
Expand Down
148 changes: 147 additions & 1 deletion docs/basic_usage.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,155 @@

# Getting started: Basic usage

Basic usage of the DetectMate Library.
In this section, we will show different examples of the basic usage of the DetectMate Library.

## Parser

In this example, we will use the [`MatcherParser`](parsers/template_matcher.md) to parse audit data from the [AIT Log Data Set V2.0](https://zenodo.org/records/5789064). The code loads the logs, parse them and save the input and output in json files using [`from_to`](helper/from_to.md) module.

```python
from detectmatelibrary.parsers.template_matcher import MatcherParser
from detectmatelibrary.helper.from_to import From, To


config_dict = {
"parsers": {
"MatcherParser": {
"auto_config": True,
"method_type": "matcher_parser",
"path_templates": "ait_audit.txt",
"log_format": r'type=<Type> msg=audit\(<Time>:<Serial>\): <Content>'
}
}
}
parser = MatcherParser(name="MatcherParser", config=config_dict)


for i, log in enumerate(From.log(parser, "audit.log", do_process=False)):
To.json(log, "logs.json")

parsed_log = parser.process(log)
To.json(parsed_log, "parsed_log.json")

```

The logs will be saved in `logs.json` in this format:

```json
{
"0": {
"log": "type=USER_ACCT msg=audit(1642723741.072:375): pid=10125 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:accounting acct=\"root\" exe=\"/usr/sbin/cron\" hostname=? addr=? terminal=cron res=success'",
"__version__": "1.0.0",
"hostname": "",
"logSource": "",
"logID": "0"
},
...
}
```
And the `parsed_log.json`:

```json
{
"0": {
"parserID": "MatcherParser",
"parsedLogID": "10",
"logID": "0",
"parsedTimestamp": 1772027171,
"logFormatVariables": {
"Type": "USER_ACCT",
"Serial": "375",
"Time": "1642723741.072",
"Content": "pid=10125 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:accounting acct=\"root\" exe=\"/usr/sbin/cron\" hostname=? addr=? terminal=cron res=success'"
},
"__version__": "1.0.0",
"receivedTimestamp": 1772027171,
"variables": [
"10125",
"0",
"4294967295",
"4294967295",
"PAM:accounting",
"\"root\"",
"\"/usr/sbin/cron\"",
"?",
"?",
"cron",
"success"
],
"log": "type=USER_ACCT msg=audit(1642723741.072:375): pid=10125 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:accounting acct=\"root\" exe=\"/usr/sbin/cron\" hostname=? addr=? terminal=cron res=success'",
"parserType": "matcher_parser",
"EventID": 0,
"template": "pid=<*> uid=<*> auid=<*> ses=<*> msg='op=<*> acct=<*> exe=<*> hostname=<*> addr=<*> terminal=<*> res=<*>'"
},
...
}
```

## Detector

In this example, we will use the [`RandomDetector`](detectors/random_detector.md) with the parsed logs from the previous example.

```python
from detectmatelibrary.parsers.template_matcher import MatcherParser
from detectmatelibrary.helper.from_to import From, To, FromTo

config_dict = {
"detectors": {
"RandomDetector": {
"auto_config": False,
"method_type": "random_detector",
"params": {},
"events": {
1: {
"test": {
"params": {},
"variables": [{
"pos": 0,
"name": "process",
"params": {
"threshold": 0.
}
}]
}
}
}
}
}
}
detector = RandomDetector(name="RandomDetector", config=config_dict)

for alert in FromTo.json2json(detector, "parsed_log.json", "alerts.json"):
if alert is not None:
print("Anomaly detected!")
```

The alerts will be saved in `alerts.json` in this format:

```json
{
"0": {
"extractedTimestamps": [
1642723752
],
"receivedTimestamp": 1772032073,
"score": 1.0,
"detectionTimestamp": 1772032073,
"alertID": "10",
"detectorType": "random_detector",
"detectorID": "RandomDetector",
"description": "",
"__version__": "1.0.0",
"logIDs": [
"6"
],
"alertsObtain": {
"process": "1.0"
}
},
...
}
```


Go back to [Index](index.md), to previous step: [Installation](installation.md) or to next step: [Create new component](create_components.md).
13 changes: 10 additions & 3 deletions docs/create_components.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ DetectMateLibrary includes a small CLI helper to bootstrap standalone workspaces
for custom parsers and detectors. This is useful if you want to develop and test
components in isolation while still using the same library and schemas.

### Usage
## Usage

The CLI entry point is `mate` with a `create` command:

Expand All @@ -20,7 +20,7 @@ mate create --type <parser|detector> --name <workspace_name> --dir <target_dir>
| `--dir` | Directory where the workspace will be created |


### What gets generated
## What gets generated

For example:

Expand All @@ -37,14 +37,21 @@ workspaces/custom_parser/ # workspace root
│ └── custom_parser.py # CoreParser-based template
├── tests/
│ └── test_custom_parser.py # generated from template to test custom_parser
├── data.json # example data to run the code
├── LICENSE.md # copied from main project
├── .gitignore # copied from main project
├── .pre-commit-config.yaml # copied from main project
├── pyproject.toml # minimal project + dev extras
└── README.md # setup instructions
```

## Add component to DetectMateLibrary

To add the new component to the `DetectMateLibrary`, you need to add the component file to the specific folder and update the import paths.

* **Detector**: Add the detector file component in `src/detectmatelibrary/detectors` and the unit tests in `tests/test_detectors`.
* **Parsers**: Add the parser file component in `src/detectmatelibrary/parsers` and the unit tests in `tests/test_parsers`.

Go back to [Index](index.md), to previous step: [Basic usage](basic_usage.md) or to next step: [Implement new component](implement_components.md).
Once that is complete, **ensure that all unit tests and the pre-commit process are successful**.

Go back to [Index](index.md), to previous step: [Basic usage](basic_usage.md).
7 changes: 0 additions & 7 deletions docs/implement_components.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ List of steps to follow for new users of the library:
* [Installation](installation.md): steps to install all the components need it.
* [Basic usage](basic_usage.md): create a basic script with the different components.
* [Create new component](create_components.md): guide to use the mate commands.
* [Implement new component](implement_components.md): guide to implement your own component.

## Components

Expand Down
1 change: 0 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ nav:
- Installation: installation.md
- Basic usage: basic_usage.md
- Create new component: create_components.md
- Implement new component: implement_components.md
- Components:
- Overall architecture: overall_architecture.md
- Schemas: schemas.md
Expand Down
2 changes: 1 addition & 1 deletion src/detectmatelibrary/common/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def process(self, data: BaseSchema | bytes) -> BaseSchema | bytes | None:
logger.info(f"<<{self.name}>> returns None")
return None

logger.info(f"<<{self.name}>> processed:\n{output_}")
logger.debug(f"<<{self.name}>> processed:\n{output_}")
return SchemaPipeline.postprocess(output_, is_byte=is_byte)

def get_config(self) -> Dict[str, Any]:
Expand Down
9 changes: 9 additions & 0 deletions src/tools/workspace/create_workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
TEMPLATE_DIR = BASE_DIR / "workspace" / "templates"

META_FILES = ["LICENSE.md", ".gitignore", ".pre-commit-config.yaml"]
DATA_FILES = {
"parser": "src/tools/workspace/templates/data/logs.json",
"detector": "src/tools/workspace/templates/data/parsed_log.json"
}


def copy_file(src: Path, dst: Path) -> None:
Expand Down Expand Up @@ -61,6 +65,7 @@ def create_tests(type_: str, name: str, workspace_root: Path, pkg_name: str) ->
# replace the remaining occurrences of CustomParser/CustomDetector
# with the new class name (inside the tests)
content = content.replace(base_class, new_class)
content = content.replace(f'"custom_{type_}"', f'"{name}_{type_}"')
content = content.rstrip() + "\n"

test_file.write_text(content)
Expand Down Expand Up @@ -106,6 +111,7 @@ def create_workspace(type_: str, name: str, target_dir: Path) -> None:
original_class = f"Custom{type_.capitalize()}"
new_class = camelize(name)
template_content = template_content.replace(original_class, new_class)
template_content = template_content.replace(f"custom_{type_}", f"{name}_{type_}")

target_code_file.write_text(template_content)

Expand All @@ -116,6 +122,9 @@ def create_workspace(type_: str, name: str, target_dir: Path) -> None:

create_tests(type_=type_, name=name, workspace_root=workspace_root, pkg_name=pkg_name)

# Copy data
copy_file(PROJECT_ROOT / DATA_FILES[type_], workspace_root / "data.json")

# Copy meta/root files
for file_name in META_FILES:
src = PROJECT_ROOT / file_name
Expand Down
10 changes: 10 additions & 0 deletions src/tools/workspace/templates/CustomDetector.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from detectmatelibrary.common.detector import CoreDetector, CoreDetectorConfig
from detectmatelibrary.utils.data_buffer import BufferMode
from detectmatelibrary.helper.from_to import From
from detectmatelibrary import schemas


Expand Down Expand Up @@ -54,3 +55,12 @@ def detect(
output_["alertsObtain"]["type"] = "Anomaly detected by CustomDetector" # Additional info

return result


if __name__ == "__main__":

print(detector := CustomDetector())

print("Running with data...")
for alerts in From.json(detector, "data.json"):
print(alerts)
10 changes: 10 additions & 0 deletions src/tools/workspace/templates/CustomParser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Any

from detectmatelibrary.common.parser import CoreParser, CoreParserConfig
from detectmatelibrary.helper.from_to import From
from detectmatelibrary import schemas


Expand Down Expand Up @@ -43,3 +44,12 @@ def parse(
output_["EventID"] = 2 # Number of the log template
output_["variables"].extend(["dummy_variable"]) # Variables found in the log
output_["template"] = "This is a dummy template" # Log template


if __name__ == "__main__":

print(parser := CustomParser())

print("Running with data...")
for parsed_log in From.json(parser, "data.json"):
print(parsed_log)
Loading