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.
Files changed (47) hide show
  1. trazas-0.1.0/.editorconfig +12 -0
  2. trazas-0.1.0/.github/CODEOWNERS +3 -0
  3. trazas-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +28 -0
  4. trazas-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  5. trazas-0.1.0/.github/ISSUE_TEMPLATE/new_scenario.yml +30 -0
  6. trazas-0.1.0/.github/dependabot.yml +21 -0
  7. trazas-0.1.0/.github/pull_request_template.md +9 -0
  8. trazas-0.1.0/.github/workflows/ci.yml +78 -0
  9. trazas-0.1.0/.github/workflows/codeql.yml +35 -0
  10. trazas-0.1.0/.github/workflows/release.yml +76 -0
  11. trazas-0.1.0/.github/workflows/scorecard.yml +30 -0
  12. trazas-0.1.0/.gitignore +17 -0
  13. trazas-0.1.0/.pre-commit-config.yaml +25 -0
  14. trazas-0.1.0/CHANGELOG.md +25 -0
  15. trazas-0.1.0/CLAUDE.md +40 -0
  16. trazas-0.1.0/CODE_OF_CONDUCT.md +9 -0
  17. trazas-0.1.0/CONTRIBUTING.md +50 -0
  18. trazas-0.1.0/LICENSE +21 -0
  19. trazas-0.1.0/PKG-INFO +114 -0
  20. trazas-0.1.0/README.es.md +53 -0
  21. trazas-0.1.0/README.md +85 -0
  22. trazas-0.1.0/SECURITY.md +38 -0
  23. trazas-0.1.0/docs/github-setup.md +54 -0
  24. trazas-0.1.0/docs/testing-detections.md +55 -0
  25. trazas-0.1.0/pyproject.toml +77 -0
  26. trazas-0.1.0/src/trazas/__init__.py +3 -0
  27. trazas-0.1.0/src/trazas/__main__.py +5 -0
  28. trazas-0.1.0/src/trazas/cli.py +117 -0
  29. trazas-0.1.0/src/trazas/context.py +98 -0
  30. trazas-0.1.0/src/trazas/engine.py +47 -0
  31. trazas-0.1.0/src/trazas/events.py +45 -0
  32. trazas-0.1.0/src/trazas/linux.py +80 -0
  33. trazas-0.1.0/src/trazas/noise.py +97 -0
  34. trazas-0.1.0/src/trazas/py.typed +0 -0
  35. trazas-0.1.0/src/trazas/scenarios/__init__.py +34 -0
  36. trazas-0.1.0/src/trazas/scenarios/base.py +30 -0
  37. trazas-0.1.0/src/trazas/scenarios/lsass_dump.py +116 -0
  38. trazas-0.1.0/src/trazas/scenarios/psexec_lateral.py +70 -0
  39. trazas-0.1.0/src/trazas/scenarios/ssh_bruteforce.py +42 -0
  40. trazas-0.1.0/src/trazas/scenarios/windows_bruteforce.py +43 -0
  41. trazas-0.1.0/src/trazas/scenarios/windows_spray.py +46 -0
  42. trazas-0.1.0/src/trazas/windows.py +256 -0
  43. trazas-0.1.0/src/trazas/writers.py +31 -0
  44. trazas-0.1.0/tests/conftest.py +10 -0
  45. trazas-0.1.0/tests/test_cli.py +88 -0
  46. trazas-0.1.0/tests/test_engine.py +150 -0
  47. trazas-0.1.0/tests/test_writers.py +20 -0
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 4
10
+
11
+ [*.{yml,yaml,toml,md}]
12
+ indent_size = 2
@@ -0,0 +1,3 @@
1
+ # Every change needs a review from the maintainer.
2
+ * @geinerjimenezvillegas-create
3
+ /.github/ @geinerjimenezvillegas-create
@@ -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,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Report a vulnerability (private)
4
+ url: https://github.com/geinerjimenezvillegas-create/trazas/security/advisories/new
5
+ about: Please report security issues privately.
@@ -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
@@ -0,0 +1,17 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ venv/
5
+ build/
6
+ dist/
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ .coverage
12
+ coverage.xml
13
+ htmlcov/
14
+ # generated datasets
15
+ *.jsonl
16
+ *.log
17
+ !tests/fixtures/**
@@ -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
+ [![CI](https://github.com/geinerjimenezvillegas-create/trazas/actions/workflows/ci.yml/badge.svg)](https://github.com/geinerjimenezvillegas-create/trazas/actions/workflows/ci.yml)
33
+ [![CodeQL](https://github.com/geinerjimenezvillegas-create/trazas/actions/workflows/codeql.yml/badge.svg)](https://github.com/geinerjimenezvillegas-create/trazas/actions/workflows/codeql.yml)
34
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/geinerjimenezvillegas-create/trazas/badge)](https://scorecard.dev/viewer/?uri=github.com/geinerjimenezvillegas-create/trazas)
35
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](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.