trazas 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trazas-0.1.0/.editorconfig +12 -0
- trazas-0.1.0/.github/CODEOWNERS +3 -0
- trazas-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +28 -0
- trazas-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- trazas-0.1.0/.github/ISSUE_TEMPLATE/new_scenario.yml +30 -0
- trazas-0.1.0/.github/dependabot.yml +21 -0
- trazas-0.1.0/.github/pull_request_template.md +9 -0
- trazas-0.1.0/.github/workflows/ci.yml +78 -0
- trazas-0.1.0/.github/workflows/codeql.yml +35 -0
- trazas-0.1.0/.github/workflows/release.yml +76 -0
- trazas-0.1.0/.github/workflows/scorecard.yml +30 -0
- trazas-0.1.0/.gitignore +17 -0
- trazas-0.1.0/.pre-commit-config.yaml +25 -0
- trazas-0.1.0/CHANGELOG.md +25 -0
- trazas-0.1.0/CLAUDE.md +40 -0
- trazas-0.1.0/CODE_OF_CONDUCT.md +9 -0
- trazas-0.1.0/CONTRIBUTING.md +50 -0
- trazas-0.1.0/LICENSE +21 -0
- trazas-0.1.0/PKG-INFO +114 -0
- trazas-0.1.0/README.es.md +53 -0
- trazas-0.1.0/README.md +85 -0
- trazas-0.1.0/SECURITY.md +38 -0
- trazas-0.1.0/docs/github-setup.md +54 -0
- trazas-0.1.0/docs/testing-detections.md +55 -0
- trazas-0.1.0/pyproject.toml +77 -0
- trazas-0.1.0/src/trazas/__init__.py +3 -0
- trazas-0.1.0/src/trazas/__main__.py +5 -0
- trazas-0.1.0/src/trazas/cli.py +117 -0
- trazas-0.1.0/src/trazas/context.py +98 -0
- trazas-0.1.0/src/trazas/engine.py +47 -0
- trazas-0.1.0/src/trazas/events.py +45 -0
- trazas-0.1.0/src/trazas/linux.py +80 -0
- trazas-0.1.0/src/trazas/noise.py +97 -0
- trazas-0.1.0/src/trazas/py.typed +0 -0
- trazas-0.1.0/src/trazas/scenarios/__init__.py +34 -0
- trazas-0.1.0/src/trazas/scenarios/base.py +30 -0
- trazas-0.1.0/src/trazas/scenarios/lsass_dump.py +116 -0
- trazas-0.1.0/src/trazas/scenarios/psexec_lateral.py +70 -0
- trazas-0.1.0/src/trazas/scenarios/ssh_bruteforce.py +42 -0
- trazas-0.1.0/src/trazas/scenarios/windows_bruteforce.py +43 -0
- trazas-0.1.0/src/trazas/scenarios/windows_spray.py +46 -0
- trazas-0.1.0/src/trazas/windows.py +256 -0
- trazas-0.1.0/src/trazas/writers.py +31 -0
- trazas-0.1.0/tests/conftest.py +10 -0
- trazas-0.1.0/tests/test_cli.py +88 -0
- trazas-0.1.0/tests/test_engine.py +150 -0
- trazas-0.1.0/tests/test_writers.py +20 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something produces wrong, invalid or unrealistic output
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
**Security issue?** Do not open a public issue — see SECURITY.md.
|
|
9
|
+
- type: input
|
|
10
|
+
id: version
|
|
11
|
+
attributes:
|
|
12
|
+
label: trazas version
|
|
13
|
+
description: Output of `trazas --version`
|
|
14
|
+
validations:
|
|
15
|
+
required: true
|
|
16
|
+
- type: textarea
|
|
17
|
+
id: command
|
|
18
|
+
attributes:
|
|
19
|
+
label: Exact command (include --seed and --start so we can reproduce it)
|
|
20
|
+
render: shell
|
|
21
|
+
validations:
|
|
22
|
+
required: true
|
|
23
|
+
- type: textarea
|
|
24
|
+
id: expected
|
|
25
|
+
attributes:
|
|
26
|
+
label: What did you expect, and what happened instead?
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: New scenario
|
|
2
|
+
description: Propose an attack scenario to simulate
|
|
3
|
+
labels: [scenario]
|
|
4
|
+
body:
|
|
5
|
+
- type: input
|
|
6
|
+
id: techniques
|
|
7
|
+
attributes:
|
|
8
|
+
label: MITRE ATT&CK technique(s)
|
|
9
|
+
placeholder: T1003.001
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: dropdown
|
|
13
|
+
id: platform
|
|
14
|
+
attributes:
|
|
15
|
+
label: Platform
|
|
16
|
+
options: [windows, linux, cloud, other]
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: events
|
|
21
|
+
attributes:
|
|
22
|
+
label: Which events/log lines should appear, in what order?
|
|
23
|
+
description: Event IDs, key fields and timing. Link public references (vendor docs, DFIR reports).
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: lookalikes
|
|
28
|
+
attributes:
|
|
29
|
+
label: Benign look-alikes
|
|
30
|
+
description: Legitimate activity that produces similar logs (useful as noise / false positives).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: github-actions
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
groups:
|
|
8
|
+
actions:
|
|
9
|
+
patterns: ["*"]
|
|
10
|
+
commit-message:
|
|
11
|
+
prefix: ci
|
|
12
|
+
|
|
13
|
+
- package-ecosystem: pip
|
|
14
|
+
directory: /
|
|
15
|
+
schedule:
|
|
16
|
+
interval: weekly
|
|
17
|
+
groups:
|
|
18
|
+
dev-tools:
|
|
19
|
+
patterns: ["*"]
|
|
20
|
+
commit-message:
|
|
21
|
+
prefix: build
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
## What does this change?
|
|
2
|
+
|
|
3
|
+
## Checklist
|
|
4
|
+
|
|
5
|
+
- [ ] Tests added/updated, `pytest` passes
|
|
6
|
+
- [ ] `ruff check .`, `ruff format --check .` and `mypy` pass
|
|
7
|
+
- [ ] New scenarios only use documentation/private IPs and `example.com` domains
|
|
8
|
+
- [ ] Output is deterministic for a given `--seed` and `--start`
|
|
9
|
+
- [ ] `CHANGELOG.md` updated under *Unreleased*
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
# Least privilege by default; jobs opt in to more if they need it.
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
lint:
|
|
19
|
+
name: Lint & type-check
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
timeout-minutes: 10
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
24
|
+
with:
|
|
25
|
+
persist-credentials: false
|
|
26
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.13"
|
|
29
|
+
cache: pip
|
|
30
|
+
- run: python -m pip install -e ".[dev]"
|
|
31
|
+
- run: ruff check --output-format=github .
|
|
32
|
+
- run: ruff format --check .
|
|
33
|
+
- run: mypy
|
|
34
|
+
|
|
35
|
+
test:
|
|
36
|
+
name: Test (py${{ matrix.python }}, ${{ matrix.os }})
|
|
37
|
+
runs-on: ${{ matrix.os }}
|
|
38
|
+
timeout-minutes: 15
|
|
39
|
+
strategy:
|
|
40
|
+
fail-fast: false
|
|
41
|
+
matrix:
|
|
42
|
+
os: [ubuntu-latest]
|
|
43
|
+
python: ["3.10", "3.11", "3.12", "3.13"]
|
|
44
|
+
include:
|
|
45
|
+
- { os: windows-latest, python: "3.13" }
|
|
46
|
+
- { os: macos-latest, python: "3.13" }
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
49
|
+
with:
|
|
50
|
+
persist-credentials: false
|
|
51
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
52
|
+
with:
|
|
53
|
+
python-version: ${{ matrix.python }}
|
|
54
|
+
cache: pip
|
|
55
|
+
- run: python -m pip install -e ".[dev]"
|
|
56
|
+
- run: pytest --cov --cov-report=term --cov-report=xml
|
|
57
|
+
|
|
58
|
+
build:
|
|
59
|
+
name: Build & smoke-test package
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
timeout-minutes: 10
|
|
62
|
+
needs: [lint, test]
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
65
|
+
with:
|
|
66
|
+
persist-credentials: false
|
|
67
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
68
|
+
with:
|
|
69
|
+
python-version: "3.13"
|
|
70
|
+
- run: python -m pip install build twine
|
|
71
|
+
- run: python -m build
|
|
72
|
+
- run: python -m twine check --strict dist/*
|
|
73
|
+
- name: Install wheel in a clean venv and run it
|
|
74
|
+
run: |
|
|
75
|
+
python -m venv /tmp/venv
|
|
76
|
+
/tmp/venv/bin/pip install dist/*.whl
|
|
77
|
+
/tmp/venv/bin/trazas list
|
|
78
|
+
/tmp/venv/bin/trazas generate ssh-bruteforce -s 1 -n 5 -f raw > /dev/null
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: "27 6 * * 1"
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
analyze:
|
|
15
|
+
name: Analyze (${{ matrix.language }})
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
timeout-minutes: 20
|
|
18
|
+
permissions:
|
|
19
|
+
security-events: write
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
# "actions" scans the workflows themselves for injection and permission issues.
|
|
24
|
+
language: [python, actions]
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
27
|
+
with:
|
|
28
|
+
persist-credentials: false
|
|
29
|
+
- uses: github/codeql-action/init@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3
|
|
30
|
+
with:
|
|
31
|
+
languages: ${{ matrix.language }}
|
|
32
|
+
queries: security-extended
|
|
33
|
+
- uses: github/codeql-action/analyze@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3
|
|
34
|
+
with:
|
|
35
|
+
category: /language:${{ matrix.language }}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Push a tag like v0.1.0 to publish. No API tokens are stored anywhere:
|
|
4
|
+
# PyPI authenticates this workflow through OIDC ("Trusted Publishing").
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ["v*.*.*"]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
timeout-minutes: 10
|
|
16
|
+
permissions:
|
|
17
|
+
id-token: write # sign the provenance attestation
|
|
18
|
+
attestations: write
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
21
|
+
with:
|
|
22
|
+
persist-credentials: false
|
|
23
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.13"
|
|
26
|
+
- name: Check tag matches package version
|
|
27
|
+
env:
|
|
28
|
+
TAG: ${{ github.ref_name }}
|
|
29
|
+
run: |
|
|
30
|
+
version=$(python -c "import re,pathlib;print(re.search(r'__version__ = \"(.+?)\"', pathlib.Path('src/trazas/__init__.py').read_text())[1])")
|
|
31
|
+
test "v${version}" = "${TAG}" || { echo "tag ${TAG} != v${version}"; exit 1; }
|
|
32
|
+
- run: python -m pip install build twine
|
|
33
|
+
- run: python -m build
|
|
34
|
+
- run: python -m twine check --strict dist/*
|
|
35
|
+
- uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
|
36
|
+
with:
|
|
37
|
+
subject-path: dist/*
|
|
38
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
39
|
+
with:
|
|
40
|
+
name: dist
|
|
41
|
+
path: dist/
|
|
42
|
+
if-no-files-found: error
|
|
43
|
+
|
|
44
|
+
publish-pypi:
|
|
45
|
+
needs: build
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
timeout-minutes: 10
|
|
48
|
+
environment:
|
|
49
|
+
name: pypi
|
|
50
|
+
url: https://pypi.org/p/trazas
|
|
51
|
+
permissions:
|
|
52
|
+
id-token: write
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
55
|
+
with:
|
|
56
|
+
name: dist
|
|
57
|
+
path: dist/
|
|
58
|
+
- uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
|
|
59
|
+
|
|
60
|
+
github-release:
|
|
61
|
+
needs: publish-pypi
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
timeout-minutes: 10
|
|
64
|
+
permissions:
|
|
65
|
+
contents: write
|
|
66
|
+
steps:
|
|
67
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
68
|
+
with:
|
|
69
|
+
name: dist
|
|
70
|
+
path: dist/
|
|
71
|
+
- name: Create GitHub release
|
|
72
|
+
env:
|
|
73
|
+
GH_TOKEN: ${{ github.token }}
|
|
74
|
+
TAG: ${{ github.ref_name }}
|
|
75
|
+
REPO: ${{ github.repository }}
|
|
76
|
+
run: gh release create "$TAG" dist/* --repo "$REPO" --title "$TAG" --generate-notes --verify-tag
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: OpenSSF Scorecard
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: "41 7 * * 2"
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions: read-all
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
analysis:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
timeout-minutes: 15
|
|
16
|
+
permissions:
|
|
17
|
+
security-events: write
|
|
18
|
+
id-token: write # publish results to the public Scorecard API / badge
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
21
|
+
with:
|
|
22
|
+
persist-credentials: false
|
|
23
|
+
- uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0
|
|
24
|
+
with:
|
|
25
|
+
results_file: results.sarif
|
|
26
|
+
results_format: sarif
|
|
27
|
+
publish_results: true
|
|
28
|
+
- uses: github/codeql-action/upload-sarif@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3
|
|
29
|
+
with:
|
|
30
|
+
sarif_file: results.sarif
|
trazas-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Install once with: pre-commit install
|
|
2
|
+
# Keep hooks current with: pre-commit autoupdate
|
|
3
|
+
repos:
|
|
4
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
5
|
+
rev: v6.0.0
|
|
6
|
+
hooks:
|
|
7
|
+
- id: check-yaml
|
|
8
|
+
- id: check-toml
|
|
9
|
+
- id: end-of-file-fixer
|
|
10
|
+
- id: trailing-whitespace
|
|
11
|
+
- id: check-added-large-files
|
|
12
|
+
- id: detect-private-key
|
|
13
|
+
- id: check-merge-conflict
|
|
14
|
+
|
|
15
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
16
|
+
rev: v0.17.4
|
|
17
|
+
hooks:
|
|
18
|
+
- id: ruff-check
|
|
19
|
+
args: [--fix]
|
|
20
|
+
- id: ruff-format
|
|
21
|
+
|
|
22
|
+
- repo: https://github.com/gitleaks/gitleaks
|
|
23
|
+
rev: v8.30.0
|
|
24
|
+
hooks:
|
|
25
|
+
- id: gitleaks
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
|
|
5
|
+
[Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-11-11
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `trazas list`, `describe` and `generate` commands.
|
|
14
|
+
- Scenarios: `windows-bruteforce` (T1110.001), `windows-spray` (T1110.003),
|
|
15
|
+
`psexec-lateral` (T1021.002, T1569.002), `ssh-bruteforce` (T1110.001).
|
|
16
|
+
- Scenario `lsass-dump` (T1003.001): Sysmon 1 → Sysmon 10 ProcessAccess on `lsass.exe`
|
|
17
|
+
→ Sysmon 11 dump file, in three variants (comsvcs.dll `MiniDump`, `procdump -ma`,
|
|
18
|
+
renamed Mimikatz with an `UNKNOWN` CallTrace frame).
|
|
19
|
+
- Benign background noise for Windows and Linux, including look-alike Sysmon 10 lsass
|
|
20
|
+
access from Defender (`0x1010`), the EDR sensor (`0x1fffff`) and svchost (`0x1000`).
|
|
21
|
+
- `jsonl` output with Sentinel `SecurityEvent` column names and `raw` auth.log output.
|
|
22
|
+
- Optional ground-truth labels (`--labels`).
|
|
23
|
+
|
|
24
|
+
[Unreleased]: https://github.com/geinerjimenezvillegas-create/trazas/compare/v0.1.0...HEAD
|
|
25
|
+
[0.1.0]: https://github.com/geinerjimenezvillegas-create/trazas/releases/tag/v0.1.0
|
trazas-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# CLAUDE.md — trazas
|
|
2
|
+
|
|
3
|
+
Synthetic, labelled attack-log generator for testing detection rules. Python ≥3.10,
|
|
4
|
+
src layout, **zero runtime dependencies** (keep it that way; dev deps only in `[dev]`).
|
|
5
|
+
|
|
6
|
+
## Commands
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install -e ".[dev]" # setup
|
|
10
|
+
ruff check . && ruff format --check . && mypy && pytest --cov # must all pass
|
|
11
|
+
python -m trazas list # smoke test
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
- `src/trazas/context.py` — `GenContext`: single seeded RNG, IP/user/host helpers.
|
|
17
|
+
- `src/trazas/windows.py`, `linux.py` — event builders (Sentinel `SecurityEvent` column names / auth.log).
|
|
18
|
+
- `src/trazas/scenarios/` — one `Scenario` subclass per attack; registered explicitly in `__init__.py`.
|
|
19
|
+
- `src/trazas/noise.py` — benign background + look-alikes.
|
|
20
|
+
- `src/trazas/engine.py` — merges scenarios + noise, stable sort by time.
|
|
21
|
+
- `src/trazas/cli.py` — argparse CLI (`list`, `describe`, `generate`).
|
|
22
|
+
|
|
23
|
+
## Non-negotiable rules
|
|
24
|
+
|
|
25
|
+
- All randomness via `ctx.rng`; never `random` module directly or wall-clock time. Same seed+start ⇒ identical bytes.
|
|
26
|
+
- Only RFC 5737 / RFC 1918 IPs and `example.com` domains (enforced by tests).
|
|
27
|
+
- Every attacker event: `malicious=True` + ATT&CK `technique`.
|
|
28
|
+
- mypy strict and ruff must stay clean; no `# type: ignore` / `noqa` without a reason comment.
|
|
29
|
+
- New scenario ⇒ test + row in README.md and README.es.md + CHANGELOG entry.
|
|
30
|
+
- Never commit secrets, tokens or real log data. Never weaken workflow `permissions`.
|
|
31
|
+
- Conventional Commits. Work on a branch and open a PR; don't push to `main` directly.
|
|
32
|
+
|
|
33
|
+
## Pending work (maintainer TODO)
|
|
34
|
+
|
|
35
|
+
1. ~~Replace `OWNER` placeholder~~ — done.
|
|
36
|
+
2. ~~Pin GitHub Actions to SHAs~~ — done (Dependabot keeps them updated).
|
|
37
|
+
3. ~~`pre-commit autoupdate`~~ — done.
|
|
38
|
+
4. `docs/github-setup.md`: applied, including SSH commit signing and the PyPI pending
|
|
39
|
+
trusted publisher.
|
|
40
|
+
5. ~~LSASS credential dumping scenario (T1003.001)~~ — done (`lsass-dump`).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
This project adopts the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
|
|
4
|
+
|
|
5
|
+
In short: be respectful and welcoming, assume good faith, and focus on what is best
|
|
6
|
+
for the community. Harassment of any kind is not tolerated.
|
|
7
|
+
|
|
8
|
+
Report unacceptable behaviour privately to the maintainer through the contact on their
|
|
9
|
+
GitHub profile. All reports will be handled confidentially.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Contributing to trazas
|
|
2
|
+
|
|
3
|
+
Thanks for helping! Contributions in English or Spanish are welcome. /
|
|
4
|
+
¡Gracias! Se aceptan contribuciones en inglés o español.
|
|
5
|
+
|
|
6
|
+
## Development setup
|
|
7
|
+
|
|
8
|
+
```console
|
|
9
|
+
git clone https://github.com/geinerjimenezvillegas-create/trazas && cd trazas
|
|
10
|
+
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
11
|
+
pip install -e ".[dev]"
|
|
12
|
+
pre-commit install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Before opening a PR, everything below must pass (CI runs the same):
|
|
16
|
+
|
|
17
|
+
```console
|
|
18
|
+
ruff check . && ruff format --check . && mypy && pytest --cov
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Adding a scenario
|
|
22
|
+
|
|
23
|
+
1. Open a *New scenario* issue first so we can agree on the event sequence.
|
|
24
|
+
2. Create `src/trazas/scenarios/<name>.py` with a `Scenario` subclass. Set `id`,
|
|
25
|
+
`name`, `description`, `platform` and `techniques`, and implement `generate()`.
|
|
26
|
+
3. Build events with the helpers in `trazas.windows` / `trazas.linux`; add a helper if
|
|
27
|
+
a new event type is needed, using the field names of the closest real schema.
|
|
28
|
+
4. Register it in `src/trazas/scenarios/__init__.py`.
|
|
29
|
+
5. Add a test asserting the important parts of the chain (event IDs, order, fields).
|
|
30
|
+
6. Add a row to the scenario tables in both READMEs and a line in `CHANGELOG.md`.
|
|
31
|
+
|
|
32
|
+
### Rules for scenarios
|
|
33
|
+
|
|
34
|
+
- **All randomness through `ctx.rng`** — never `random` directly, never wall-clock
|
|
35
|
+
time. Output must be deterministic for a given seed and start.
|
|
36
|
+
- **No real infrastructure** — use `ctx.external_ip()`, `ctx.internal_ip()` and the
|
|
37
|
+
`example.com` domain. A test enforces this.
|
|
38
|
+
- **Mark every attacker event** with `malicious=True` and its ATT&CK `technique`.
|
|
39
|
+
- Prefer realism you can cite: link vendor docs or public DFIR reports in the PR.
|
|
40
|
+
|
|
41
|
+
## Commits and PRs
|
|
42
|
+
|
|
43
|
+
- Use [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`,
|
|
44
|
+
`docs:`, `ci:`…).
|
|
45
|
+
- Keep PRs focused; one scenario per PR.
|
|
46
|
+
- By contributing you agree your work is licensed under the MIT License.
|
|
47
|
+
|
|
48
|
+
## Code of Conduct
|
|
49
|
+
|
|
50
|
+
This project follows the [Code of Conduct](CODE_OF_CONDUCT.md).
|
trazas-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Geiner Jiménez Villegas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
trazas-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: trazas
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Realistic, labelled attack log generator for testing detection rules without a lab.
|
|
5
|
+
Project-URL: Homepage, https://github.com/geinerjimenezvillegas-create/trazas
|
|
6
|
+
Project-URL: Issues, https://github.com/geinerjimenezvillegas-create/trazas/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/geinerjimenezvillegas-create/trazas/blob/main/CHANGELOG.md
|
|
8
|
+
Author: Geiner Jiménez Villegas
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: blue-team,detection-engineering,kql,logs,mitre-attack,security,siem,sigma
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Education
|
|
15
|
+
Classifier: Intended Audience :: Information Technology
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Topic :: Security
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
24
|
+
Requires-Dist: pre-commit>=3.8; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# trazas
|
|
31
|
+
|
|
32
|
+
[](https://github.com/geinerjimenezvillegas-create/trazas/actions/workflows/ci.yml)
|
|
33
|
+
[](https://github.com/geinerjimenezvillegas-create/trazas/actions/workflows/codeql.yml)
|
|
34
|
+
[](https://scorecard.dev/viewer/?uri=github.com/geinerjimenezvillegas-create/trazas)
|
|
35
|
+
[](LICENSE)
|
|
36
|
+
|
|
37
|
+
**Realistic, labelled attack logs for testing detection rules — no lab required.**
|
|
38
|
+
|
|
39
|
+
🇪🇸 [Leer en español](README.es.md)
|
|
40
|
+
|
|
41
|
+
Writing a detection is easy; proving it works is hard. Most people don't have a
|
|
42
|
+
lab with domain controllers, attackers and months of baseline traffic. `trazas`
|
|
43
|
+
generates that data for you: attack chains mapped to MITRE ATT&CK, mixed with
|
|
44
|
+
benign noise (including look-alikes that *should not* fire your rule), with
|
|
45
|
+
optional ground-truth labels so you can measure true and false positives.
|
|
46
|
+
|
|
47
|
+
```console
|
|
48
|
+
$ pip install trazas
|
|
49
|
+
$ trazas generate windows-bruteforce psexec-lateral --seed 42 --labels -o dataset.jsonl
|
|
50
|
+
trazas: 248 events, seed=42, start=2026-11-10T23:00:00+00:00
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
- **Detection-ready schemas** — Windows events use Microsoft Sentinel `SecurityEvent`
|
|
56
|
+
column names (`EventID`, `TargetUserName`, `LogonType`, `IpAddress`…); Linux events
|
|
57
|
+
are real `auth.log` lines.
|
|
58
|
+
- **Reproducible** — same `--seed` + `--start` ⇒ byte-identical output. Perfect for
|
|
59
|
+
regression tests of your rules in CI.
|
|
60
|
+
- **Ground truth** — `--labels` adds `_trazas.malicious` and `_trazas.technique` to every
|
|
61
|
+
record.
|
|
62
|
+
- **Realistic noise** — normal logons, admin share use, honest password typos.
|
|
63
|
+
- **Safe by design** — external IPs come only from RFC 5737 documentation ranges,
|
|
64
|
+
internal ones from RFC 1918, domains from `example.com`. Zero runtime dependencies.
|
|
65
|
+
|
|
66
|
+
## Scenarios
|
|
67
|
+
|
|
68
|
+
| ID | Platform | ATT&CK | What happens |
|
|
69
|
+
|---|---|---|---|
|
|
70
|
+
| `windows-bruteforce` | Windows | T1110.001 | Burst of 4625 against one account from one external IP, then 4624 |
|
|
71
|
+
| `windows-spray` | Windows | T1110.003 | One password against many accounts (real and invalid), slow, one success |
|
|
72
|
+
| `psexec-lateral` | Windows | T1021.002, T1569.002 | 4624 type 3 → 5140 `ADMIN$` → 7045 `PSEXESVC` → Sysmon 1 recon as SYSTEM |
|
|
73
|
+
| `lsass-dump` | Windows | T1003.001 | Sysmon 1 dumper (comsvcs `MiniDump`, `procdump -ma` or renamed Mimikatz) → Sysmon 10 on `lsass.exe` → Sysmon 11 `.dmp`; noise adds benign Defender/EDR lsass access |
|
|
74
|
+
| `ssh-bruteforce` | Linux | T1110.001 | sshd failures with common usernames, then `Accepted password` |
|
|
75
|
+
|
|
76
|
+
Run `trazas list` and `trazas describe <id>` for details.
|
|
77
|
+
|
|
78
|
+
## Usage
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
trazas generate SCENARIO [SCENARIO ...]
|
|
82
|
+
-s, --seed INT PRNG seed (random if omitted; printed so you can reproduce)
|
|
83
|
+
--start ISO8601 start time (default: now, UTC)
|
|
84
|
+
-n, --noise INT benign events per platform (default: 200)
|
|
85
|
+
-f, --format jsonl (default) | raw (raw = native text, Linux only)
|
|
86
|
+
-o, --output PATH write to file (refuses to overwrite without --force)
|
|
87
|
+
--labels add ground-truth labels
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Testing a KQL rule without Sentinel
|
|
91
|
+
|
|
92
|
+
1. Create a free [Azure Data Explorer cluster](https://dataexplorer.azure.com/freecluster).
|
|
93
|
+
2. Generate data: `trazas generate windows-bruteforce windows-spray -s 1 --labels -o events.jsonl`
|
|
94
|
+
3. Ingest `events.jsonl` into a table named `SecurityEvent` (JSON format).
|
|
95
|
+
4. Run your rule. Example:
|
|
96
|
+
|
|
97
|
+
```kql
|
|
98
|
+
SecurityEvent
|
|
99
|
+
| where EventID == 4625
|
|
100
|
+
| summarize Failures = count(), Accounts = dcount(TargetUserName) by IpAddress, bin(TimeGenerated, 10m)
|
|
101
|
+
| where Failures > 20 or Accounts > 10
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Then compare against `_trazas.malicious` to count true and false positives. See
|
|
105
|
+
[docs/testing-detections.md](docs/testing-detections.md).
|
|
106
|
+
|
|
107
|
+
## Contributing
|
|
108
|
+
|
|
109
|
+
New scenarios are very welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). Please report
|
|
110
|
+
security issues privately as described in [SECURITY.md](SECURITY.md).
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
[MIT](LICENSE). Generated data is synthetic; any resemblance to real users is coincidental.
|